8027031: complete merging of loads and converts
Reviewed-by: jlaskey, lagergren
This commit is contained in:
parent
0206687c1a
commit
806a003cb6
@ -43,6 +43,7 @@ import java.util.concurrent.Callable;
|
||||
import javax.script.Bindings;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.GlobalObject;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
@ -705,4 +706,45 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant Object to int32 conversion
|
||||
* See ECMA 9.5 ToInt32
|
||||
*
|
||||
* @return this object's int32 representation
|
||||
*/
|
||||
public int toInt32() {
|
||||
return inGlobal(new Callable<Integer>() {
|
||||
@Override public Integer call() {
|
||||
return JSType.toInt32(sobj);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant Object to int64 conversion
|
||||
*
|
||||
* @return this object's int64 representation
|
||||
*/
|
||||
public long toInt64() {
|
||||
return inGlobal(new Callable<Long>() {
|
||||
@Override public Long call() {
|
||||
return JSType.toInt64(sobj);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant conversion of Object to number
|
||||
* See ECMA 9.3 ToNumber
|
||||
*
|
||||
* @return this object's number representation
|
||||
*/
|
||||
public double toNumber() {
|
||||
return inGlobal(new Callable<Double>() {
|
||||
@Override public Double call() {
|
||||
return JSType.toNumber(sobj);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +72,7 @@ final class BranchOptimizer {
|
||||
}
|
||||
|
||||
// convert to boolean
|
||||
codegen.load(unaryNode);
|
||||
method.convert(Type.BOOLEAN);
|
||||
codegen.load(unaryNode, Type.BOOLEAN);
|
||||
if (state) {
|
||||
method.ifne(label);
|
||||
} else {
|
||||
@ -146,8 +145,7 @@ final class BranchOptimizer {
|
||||
break;
|
||||
}
|
||||
|
||||
codegen.load(binaryNode);
|
||||
method.convert(Type.BOOLEAN);
|
||||
codegen.load(binaryNode, Type.BOOLEAN);
|
||||
if (state) {
|
||||
method.ifne(label);
|
||||
} else {
|
||||
@ -169,8 +167,7 @@ final class BranchOptimizer {
|
||||
}
|
||||
}
|
||||
|
||||
codegen.load(node);
|
||||
method.convert(Type.BOOLEAN);
|
||||
codegen.load(node, Type.BOOLEAN);
|
||||
if (state) {
|
||||
method.ifne(label);
|
||||
} else {
|
||||
|
@ -402,7 +402,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
return loadBinaryOperands(node.lhs(), node.rhs(), node.getType(), false);
|
||||
}
|
||||
|
||||
private MethodEmitter load(final Expression node, final Type type) {
|
||||
MethodEmitter load(final Expression node, final Type type) {
|
||||
return load(node, type, false);
|
||||
}
|
||||
|
||||
@ -432,7 +432,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
@Override
|
||||
public boolean enterAccessNode(final AccessNode accessNode) {
|
||||
if (!baseAlreadyOnStack) {
|
||||
load(accessNode.getBase()).convert(Type.OBJECT);
|
||||
load(accessNode.getBase(), Type.OBJECT);
|
||||
}
|
||||
assert method.peekType().isObject();
|
||||
method.dynamicGet(type, accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
|
||||
@ -442,7 +442,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
@Override
|
||||
public boolean enterIndexNode(final IndexNode indexNode) {
|
||||
if (!baseAlreadyOnStack) {
|
||||
load(indexNode.getBase()).convert(Type.OBJECT);
|
||||
load(indexNode.getBase(), Type.OBJECT);
|
||||
load(indexNode.getIndex());
|
||||
}
|
||||
method.dynamicGetIndex(type, getCallSiteFlags(), indexNode.isFunction());
|
||||
@ -632,11 +632,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
final Type[] params = signature == null ? null : Type.getMethodArguments(signature);
|
||||
for (final Expression arg : args) {
|
||||
assert arg != null;
|
||||
load(arg);
|
||||
if (n >= argCount) {
|
||||
load(arg);
|
||||
method.pop(); // we had to load the arg for its side effects
|
||||
} else if (params != null) {
|
||||
method.convert(params[n]);
|
||||
load(arg, params[n]);
|
||||
} else {
|
||||
load(arg);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
@ -1277,7 +1279,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
method.dup();
|
||||
method.load(i);
|
||||
load(args.get(i)).convert(Type.OBJECT); //has to be upcast to object or we fail
|
||||
load(args.get(i), Type.OBJECT); //has to be upcast to object or we fail
|
||||
method.arraystore();
|
||||
}
|
||||
|
||||
@ -1719,7 +1721,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
}
|
||||
|
||||
for (final Expression arg : args) {
|
||||
load(arg).convert(Type.OBJECT);
|
||||
load(arg, Type.OBJECT);
|
||||
}
|
||||
|
||||
method.invokestatic(
|
||||
@ -2105,7 +2107,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
|
||||
if (exceptionCondition != null) {
|
||||
next = new Label("next");
|
||||
load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next);
|
||||
load(exceptionCondition, Type.BOOLEAN).ifeq(next);
|
||||
} else {
|
||||
next = null;
|
||||
}
|
||||
@ -2352,7 +2354,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
final List<Expression> args = callNode.getArgs();
|
||||
|
||||
// Load function reference.
|
||||
load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error
|
||||
load(callNode.getFunction(), Type.OBJECT); // must detect type error
|
||||
|
||||
method.dynamicNew(1 + loadArgs(args), getCallSiteFlags());
|
||||
method.store(unaryNode.getSymbol());
|
||||
@ -2383,7 +2385,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
@Override
|
||||
public boolean enterSUB(final UnaryNode unaryNode) {
|
||||
assert unaryNode.getType().isNumeric();
|
||||
load(unaryNode.rhs()).convert(unaryNode.getType()).neg().store(unaryNode.getSymbol());
|
||||
load(unaryNode.rhs(), unaryNode.getType()).neg().store(unaryNode.getSymbol());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2424,7 +2426,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
|
||||
final Label skip = new Label("skip");
|
||||
|
||||
load(lhs).convert(Type.OBJECT).dup().convert(Type.BOOLEAN);
|
||||
load(lhs, Type.OBJECT).dup().convert(Type.BOOLEAN);
|
||||
|
||||
if (binaryNode.tokenType() == TokenType.AND) {
|
||||
method.ifeq(skip);
|
||||
@ -2433,7 +2435,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
}
|
||||
|
||||
method.pop();
|
||||
load(rhs).convert(Type.OBJECT);
|
||||
load(rhs, Type.OBJECT);
|
||||
method.label(skip);
|
||||
method.store(binaryNode.getSymbol());
|
||||
|
||||
|
@ -32,7 +32,6 @@ import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.Expression;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
@ -143,7 +142,7 @@ public class SpillObjectCreator extends ObjectCreator {
|
||||
method.dup();
|
||||
method.getField(Type.getInternalName(ScriptObject.class), "spill", Type.OBJECT_ARRAY.getDescriptor());
|
||||
method.load(property.getSlot());
|
||||
codegen.load(values.get(i)).convert(OBJECT);
|
||||
codegen.load(values.get(i), OBJECT);
|
||||
method.arraystore();
|
||||
}
|
||||
}
|
||||
|
@ -246,12 +246,11 @@ public enum JSType {
|
||||
* @return the primitive form of the object
|
||||
*/
|
||||
public static Object toPrimitive(final Object obj, final Class<?> hint) {
|
||||
if (!(obj instanceof ScriptObject)) {
|
||||
return obj;
|
||||
}
|
||||
return obj instanceof ScriptObject ? toPrimitive((ScriptObject)obj, hint) : obj;
|
||||
}
|
||||
|
||||
final ScriptObject sobj = (ScriptObject)obj;
|
||||
final Object result = sobj.getDefaultValue(hint);
|
||||
private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
|
||||
final Object result = sobj.getDefaultValue(hint);
|
||||
|
||||
if (!isPrimitive(result)) {
|
||||
throw typeError("bad.default.value", result.toString());
|
||||
@ -475,6 +474,19 @@ public enum JSType {
|
||||
return toNumberGeneric(obj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JavaScript compliant conversion of Object to number
|
||||
* See ECMA 9.3 ToNumber
|
||||
*
|
||||
* @param obj an object
|
||||
*
|
||||
* @return a number
|
||||
*/
|
||||
public static double toNumber(final ScriptObject obj) {
|
||||
return toNumber(toPrimitive(obj, Number.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Digit representation for a character
|
||||
*
|
||||
@ -618,6 +630,17 @@ public enum JSType {
|
||||
return toInt32(toNumber(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant Object to int32 conversion
|
||||
* See ECMA 9.5 ToInt32
|
||||
*
|
||||
* @param obj an object
|
||||
* @return an int32
|
||||
*/
|
||||
public static int toInt32(final ScriptObject obj) {
|
||||
return toInt32(toNumber(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant long to int32 conversion
|
||||
*
|
||||
@ -648,6 +671,16 @@ public enum JSType {
|
||||
return toInt64(toNumber(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant Object to int64 conversion
|
||||
*
|
||||
* @param obj an object
|
||||
* @return an int64
|
||||
*/
|
||||
public static long toInt64(final ScriptObject obj) {
|
||||
return toInt64(toNumber(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant number to int64 conversion
|
||||
*
|
||||
@ -1028,7 +1061,7 @@ public enum JSType {
|
||||
}
|
||||
|
||||
if (obj instanceof ScriptObject) {
|
||||
return toNumber(toPrimitive(obj, Number.class));
|
||||
return toNumber((ScriptObject)obj);
|
||||
}
|
||||
|
||||
return Double.NaN;
|
||||
|
@ -25,25 +25,29 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
|
||||
/**
|
||||
* A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
|
||||
* as ScriptObjects from other Nashorn contexts.
|
||||
*/
|
||||
final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory {
|
||||
@Override
|
||||
public boolean canLinkType(final Class<?> type) {
|
||||
return canLinkTypeStatic(type);
|
||||
@ -75,6 +79,21 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
return Bootstrap.asType(inv, linkerServices, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception {
|
||||
if(!sourceType.isAssignableFrom(ScriptObjectMirror.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MethodHandle converter = MIRROR_CONVERTERS.get(targetType);
|
||||
if(converter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GuardedInvocation(converter, sourceType == ScriptObjectMirror.class ? null : IS_MIRROR_GUARD).asType(MethodType.methodType(targetType, sourceType));
|
||||
}
|
||||
|
||||
|
||||
private static GuardedInvocation lookup(final CallSiteDescriptor desc) {
|
||||
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
|
||||
final int c = desc.getNameTokenCount();
|
||||
@ -87,9 +106,9 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
case "setElem":
|
||||
return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
|
||||
case "call":
|
||||
return findCallMethod(desc, operator);
|
||||
return findCallMethod(desc);
|
||||
case "callMethod":
|
||||
return findCallMethodMethod(desc, operator);
|
||||
return findCallMethodMethod(desc);
|
||||
case "new":
|
||||
return findNewMethod(desc);
|
||||
default:
|
||||
@ -115,14 +134,14 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
return new GuardedInvocation(JSOBJECTLINKER_PUT, null, IS_JSOBJECT_GUARD);
|
||||
}
|
||||
|
||||
private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final String operator) {
|
||||
private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc) {
|
||||
final String methodName = desc.getNameToken(2);
|
||||
MethodHandle func = MH.insertArguments(JSOBJECT_CALLMEMBER, 1, methodName);
|
||||
func = MH.asCollector(func, Object[].class, desc.getMethodType().parameterCount() - 1);
|
||||
return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
|
||||
}
|
||||
|
||||
private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final String operator) {
|
||||
private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
|
||||
final MethodHandle func = MH.asCollector(JSOBJECT_CALL, Object[].class, desc.getMethodType().parameterCount() - 2);
|
||||
return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
|
||||
}
|
||||
@ -137,6 +156,11 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
return self instanceof JSObject;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isScriptObjectMirror(final Object self) {
|
||||
return self instanceof ScriptObjectMirror;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object get(final Object jsobj, final Object key) {
|
||||
if (key instanceof Integer) {
|
||||
@ -172,6 +196,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
|
||||
// method handles of the current class
|
||||
private static final MethodHandle IS_JSOBJECT_GUARD = findOwnMH("isJSObject", boolean.class, Object.class);
|
||||
private static final MethodHandle IS_MIRROR_GUARD = findOwnMH("isScriptObjectMirror", boolean.class, Object.class);
|
||||
private static final MethodHandle JSOBJECTLINKER_GET = findOwnMH("get", Object.class, Object.class, Object.class);
|
||||
private static final MethodHandle JSOBJECTLINKER_PUT = findOwnMH("put", Void.TYPE, Object.class, Object.class, Object.class);
|
||||
|
||||
@ -182,23 +207,32 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
|
||||
private static final MethodHandle JSOBJECT_CALL = findJSObjectMH("call", Object.class, Object.class, Object[].class);
|
||||
private static final MethodHandle JSOBJECT_NEW = findJSObjectMH("newObject", Object.class, Object[].class);
|
||||
|
||||
private static final Map<Class<?>, MethodHandle> MIRROR_CONVERTERS = new HashMap<>();
|
||||
static {
|
||||
MIRROR_CONVERTERS.put(boolean.class, MH.dropArguments(MH.constant(boolean.class, Boolean.TRUE), 0, Object.class));
|
||||
MIRROR_CONVERTERS.put(int.class, findMirrorMH("toInt32", int.class));
|
||||
MIRROR_CONVERTERS.put(long.class, findMirrorMH("toInt64", long.class));
|
||||
MIRROR_CONVERTERS.put(double.class, findMirrorMH("toNumber", double.class));
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
final Class<?> own = JSObjectLinker.class;
|
||||
final MethodType mt = MH.type(rtype, types);
|
||||
try {
|
||||
return MH.findStatic(MethodHandles.lookup(), own, name, mt);
|
||||
} catch (final MethodHandleFactory.LookupException e) {
|
||||
return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
|
||||
}
|
||||
return findMH(name, JSObjectLinker.class, rtype, types);
|
||||
}
|
||||
|
||||
private static MethodHandle findJSObjectMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
final Class<?> own = JSObject.class;
|
||||
return findMH(name, JSObject.class, rtype, types);
|
||||
}
|
||||
|
||||
private static MethodHandle findMirrorMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
return findMH(name, ScriptObjectMirror.class, rtype, types);
|
||||
}
|
||||
|
||||
private static MethodHandle findMH(final String name, final Class<?> target, final Class<?> rtype, final Class<?>... types) {
|
||||
final MethodType mt = MH.type(rtype, types);
|
||||
try {
|
||||
return MH.findVirtual(MethodHandles.publicLookup(), own, name, mt);
|
||||
return MH.findStatic(MethodHandles.lookup(), target, name, mt);
|
||||
} catch (final MethodHandleFactory.LookupException e) {
|
||||
return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
|
||||
return MH.findVirtual(MethodHandles.lookup(), target, name, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user