Merge
This commit is contained in:
commit
1f8726f7e6
@ -91,6 +91,7 @@ import java.util.StringTokenizer;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
import jdk.internal.dynalink.support.Lookup;
|
||||
|
||||
/**
|
||||
* Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the
|
||||
@ -100,6 +101,9 @@ import jdk.internal.dynalink.support.Guards;
|
||||
* @version $Id: $
|
||||
*/
|
||||
abstract class SingleDynamicMethod extends DynamicMethod {
|
||||
|
||||
private static final MethodHandle CAN_CONVERT_TO = Lookup.findOwnStatic(MethodHandles.lookup(), "canConvertTo", boolean.class, LinkerServices.class, Class.class, Object.class);
|
||||
|
||||
SingleDynamicMethod(String name) {
|
||||
super(name);
|
||||
}
|
||||
@ -201,23 +205,69 @@ abstract class SingleDynamicMethod extends DynamicMethod {
|
||||
return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
|
||||
callSiteLastArgType);
|
||||
}
|
||||
if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
|
||||
// Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
|
||||
// link immediately to a vararg-packing method handle.
|
||||
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
|
||||
|
||||
// This method handle takes the single argument and packs it into a newly allocated single-element array. It
|
||||
// will be used when the incoming argument can't be converted to the vararg array type (the "vararg packer"
|
||||
// method).
|
||||
final MethodHandle varArgCollectingInvocation = createConvertingInvocation(collectArguments(fixTarget,
|
||||
argsLen), linkerServices, callSiteType);
|
||||
|
||||
// Is call site type assignable from an array type (e.g. Object:int[], or Object[]:String[])
|
||||
final boolean isAssignableFromArray = callSiteLastArgType.isAssignableFrom(varArgType);
|
||||
// Do we have a custom conversion that can potentially convert the call site type to an array?
|
||||
final boolean isCustomConvertible = linkerServices.canConvert(callSiteLastArgType, varArgType);
|
||||
if(!isAssignableFromArray && !isCustomConvertible) {
|
||||
// Call site signature guarantees the argument can definitely not be converted to an array (i.e. it is
|
||||
// primitive), and no conversion can help with it either. Link immediately to a vararg-packing method
|
||||
// handle.
|
||||
return varArgCollectingInvocation;
|
||||
}
|
||||
// Call site signature makes no guarantees that the single argument in the vararg position will be
|
||||
// compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
|
||||
// method when it is not.
|
||||
return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
|
||||
createConvertingInvocation(fixTarget, linkerServices, callSiteType),
|
||||
createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
|
||||
|
||||
// This method handle employs language-specific conversions to convert the last argument into an array of
|
||||
// vararg type.
|
||||
final MethodHandle arrayConvertingInvocation = createConvertingInvocation(MethodHandles.filterArguments(
|
||||
fixTarget, fixParamsLen, linkerServices.getTypeConverter(callSiteLastArgType, varArgType)),
|
||||
linkerServices, callSiteType);
|
||||
|
||||
// This method handle determines whether the value can be converted to the array of vararg type using a
|
||||
// language-specific conversion.
|
||||
final MethodHandle canConvertArgToArray = MethodHandles.insertArguments(CAN_CONVERT_TO, 0, linkerServices,
|
||||
varArgType);
|
||||
|
||||
// This one adjusts the previous one for the location of the argument and the call site type.
|
||||
final MethodHandle canConvertLastArgToArray = MethodHandles.dropArguments(canConvertArgToArray, 0,
|
||||
MethodType.genericMethodType(fixParamsLen).parameterList()).asType(callSiteType.changeReturnType(boolean.class));
|
||||
|
||||
// This one takes the previous ones and combines them into a method handle that converts the argument into
|
||||
// a vararg array when it can, otherwise falls back to the vararg packer.
|
||||
final MethodHandle convertToArrayWhenPossible = MethodHandles.guardWithTest(canConvertLastArgToArray,
|
||||
arrayConvertingInvocation, varArgCollectingInvocation);
|
||||
|
||||
if(isAssignableFromArray) {
|
||||
return MethodHandles.guardWithTest(
|
||||
// Is incoming parameter already a compatible array?
|
||||
Guards.isInstance(varArgType, fixParamsLen, callSiteType),
|
||||
// Yes: just pass it to the method
|
||||
createConvertingInvocation(fixTarget, linkerServices, callSiteType),
|
||||
// No: either go through a custom conversion, or if it is not possible, go directly to the
|
||||
// vararg packer.
|
||||
isCustomConvertible ? convertToArrayWhenPossible : varArgCollectingInvocation);
|
||||
}
|
||||
|
||||
// Just do the custom conversion with fallback to the vararg packer logic.
|
||||
assert isCustomConvertible;
|
||||
return convertToArrayWhenPossible;
|
||||
}
|
||||
|
||||
// Remaining case: more than one vararg.
|
||||
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean canConvertTo(final LinkerServices linkerServices, Class<?> to, Object obj) {
|
||||
return obj == null ? false : linkerServices.canConvert(obj.getClass(), to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle out of the original target that will collect the varargs for the exact component type of
|
||||
* the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
|
||||
|
@ -88,6 +88,7 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import jdk.internal.dynalink.DynamicLinker;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
|
||||
/**
|
||||
@ -115,11 +116,11 @@ public class Guards {
|
||||
public static MethodHandle isOfClass(Class<?> clazz, MethodType type) {
|
||||
final Class<?> declaredType = type.parameterType(0);
|
||||
if(clazz == declaredType) {
|
||||
LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type });
|
||||
LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type, DynamicLinker.getLinkedCallSiteLocation() });
|
||||
return constantTrue(type);
|
||||
}
|
||||
if(!declaredType.isAssignableFrom(clazz)) {
|
||||
LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type });
|
||||
LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type, DynamicLinker.getLinkedCallSiteLocation() });
|
||||
return constantFalse(type);
|
||||
}
|
||||
return getClassBoundArgumentTest(IS_OF_CLASS, clazz, 0, type);
|
||||
@ -152,11 +153,11 @@ public class Guards {
|
||||
public static MethodHandle isInstance(Class<?> clazz, int pos, MethodType type) {
|
||||
final Class<?> declaredType = type.parameterType(pos);
|
||||
if(clazz.isAssignableFrom(declaredType)) {
|
||||
LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type });
|
||||
LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type, DynamicLinker.getLinkedCallSiteLocation() });
|
||||
return constantTrue(type);
|
||||
}
|
||||
if(!declaredType.isAssignableFrom(clazz)) {
|
||||
LOG.log(Level.WARNING, "isInstanceGuardAlwaysFalse", new Object[] { clazz.getName(), pos, type });
|
||||
LOG.log(Level.WARNING, "isInstanceGuardAlwaysFalse", new Object[] { clazz.getName(), pos, type, DynamicLinker.getLinkedCallSiteLocation() });
|
||||
return constantFalse(type);
|
||||
}
|
||||
return getClassBoundArgumentTest(IS_INSTANCE, clazz, pos, type);
|
||||
@ -174,11 +175,11 @@ public class Guards {
|
||||
public static MethodHandle isArray(int pos, MethodType type) {
|
||||
final Class<?> declaredType = type.parameterType(pos);
|
||||
if(declaredType.isArray()) {
|
||||
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type });
|
||||
LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
|
||||
return constantTrue(type);
|
||||
}
|
||||
if(!declaredType.isAssignableFrom(Object[].class)) {
|
||||
LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type });
|
||||
LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
|
||||
return constantFalse(type);
|
||||
}
|
||||
return asType(IS_ARRAY, pos, type);
|
||||
|
@ -76,11 +76,11 @@
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
isInstanceGuardAlwaysTrue=isInstance guard for {0} in position {1} in method type {2} will always return true
|
||||
isInstanceGuardAlwaysFalse=isInstance guard for {0} in position {1} in method type {2} will always return false
|
||||
isInstanceGuardAlwaysTrue=isInstance guard for {0} in position {1} in method type {2} at {3} will always return true
|
||||
isInstanceGuardAlwaysFalse=isInstance guard for {0} in position {1} in method type {2} at {3} will always return false
|
||||
|
||||
isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type {2} will always return true
|
||||
isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} will always return false
|
||||
isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type {2} at {3} will always return true
|
||||
isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} at {3} will always return false
|
||||
|
||||
isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} will always return true
|
||||
isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} will always return false
|
||||
isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} at {2} will always return true
|
||||
isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} at {2} will always return false
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
@ -57,4 +58,17 @@ public final class ScriptUtils {
|
||||
public static String format(final String format, final Object[] args) {
|
||||
return Formatter.format(format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a wrapper function that calls {@code func} synchronized on {@code sync} or, if that is undefined,
|
||||
* {@code self}. Used to implement "sync" function in resources/mozilla_compat.js.
|
||||
*
|
||||
* @param func the function to invoke
|
||||
* @param sync the object to synchronize on
|
||||
* @return a synchronizing wrapper function
|
||||
*/
|
||||
public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
|
||||
return func.makeSynchronizedFunction(sync);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -453,7 +453,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
public boolean enterFunctionNode(FunctionNode functionNode) {
|
||||
// function nodes will always leave a constructed function object on stack, no need to load the symbol
|
||||
// separately as in enterDefault()
|
||||
lc.pop(functionNode);
|
||||
functionNode.accept(codegen);
|
||||
// NOTE: functionNode.accept() will produce a different FunctionNode that we discard. This incidentally
|
||||
// doesn't cause problems as we're never touching FunctionNode again after it's visited here - codegen
|
||||
// is the last element in the compilation pipeline, the AST it produces is not used externally. So, we
|
||||
// re-push the original functionNode.
|
||||
lc.push(functionNode);
|
||||
method.convert(type);
|
||||
return false;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
@ -255,6 +256,12 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
return makeFunction(name, methodHandle, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptFunction makeSynchronizedFunction(final Object sync) {
|
||||
final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync);
|
||||
return makeFunction(getName(), mh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we
|
||||
* can expose it to methods in this package.
|
||||
|
@ -31,6 +31,8 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
@ -110,6 +112,15 @@ public enum JSType {
|
||||
/** Combined call to toPrimitive followed by toString. */
|
||||
public static final Call TO_PRIMITIVE_TO_STRING = staticCall(myLookup, JSType.class, "toPrimitiveToString", String.class, Object.class);
|
||||
|
||||
/** Method handle to convert a JS Object to a Java array. */
|
||||
public static final Call TO_JAVA_ARRAY = staticCall(myLookup, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
|
||||
|
||||
/** Method handle to convert a JS Object to a Java List. */
|
||||
public static final Call TO_JAVA_LIST = staticCall(myLookup, JSType.class, "toJavaList", List.class, Object.class);
|
||||
|
||||
/** Method handle to convert a JS Object to a Java deque. */
|
||||
public static final Call TO_JAVA_DEQUE = staticCall(myLookup, JSType.class, "toJavaDeque", Deque.class, Object.class);
|
||||
|
||||
private static final double INT32_LIMIT = 4294967296.0;
|
||||
|
||||
/**
|
||||
@ -890,6 +901,8 @@ public enum JSType {
|
||||
res[idx++] = itr.next();
|
||||
}
|
||||
return convertArray(res, componentType);
|
||||
} else if(obj == null) {
|
||||
return null;
|
||||
} else {
|
||||
throw new IllegalArgumentException("not a script object");
|
||||
}
|
||||
@ -918,6 +931,24 @@ public enum JSType {
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JavaScript object to a Java List. See {@link ListAdapter} for details.
|
||||
* @param obj the object to convert. Can be any array-like object.
|
||||
* @return a List that is live-backed by the JavaScript object.
|
||||
*/
|
||||
public static List<?> toJavaList(final Object obj) {
|
||||
return ListAdapter.create(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details.
|
||||
* @param obj the object to convert. Can be any array-like object.
|
||||
* @return a Deque that is live-backed by the JavaScript object.
|
||||
*/
|
||||
public static Deque<?> toJavaDeque(final Object obj) {
|
||||
return ListAdapter.create(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object is null or undefined
|
||||
*
|
||||
|
@ -53,7 +53,7 @@ import jdk.nashorn.internal.parser.TokenType;
|
||||
public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
|
||||
/** FunctionNode with the code for this ScriptFunction */
|
||||
private volatile FunctionNode functionNode;
|
||||
private FunctionNode functionNode;
|
||||
|
||||
/** Source from which FunctionNode was parsed. */
|
||||
private final Source source;
|
||||
@ -65,7 +65,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
private final PropertyMap allocatorMap;
|
||||
|
||||
/** Code installer used for all further recompilation/specialization of this ScriptFunction */
|
||||
private volatile CodeInstaller<ScriptEnvironment> installer;
|
||||
private CodeInstaller<ScriptEnvironment> installer;
|
||||
|
||||
/** Name of class where allocator function resides */
|
||||
private final String allocatorClassName;
|
||||
@ -178,7 +178,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void ensureCodeGenerated() {
|
||||
protected synchronized void ensureCodeGenerated() {
|
||||
if (!code.isEmpty()) {
|
||||
return; // nothing to do, we have code, at least some.
|
||||
}
|
||||
@ -336,7 +336,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
}
|
||||
|
||||
@Override
|
||||
MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
|
||||
synchronized MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
|
||||
final MethodType runtimeType = runtimeType(callSiteType, args);
|
||||
assert runtimeType.parameterCount() == callSiteType.parameterCount();
|
||||
|
||||
|
@ -59,6 +59,9 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
/** Method handle for name getter for this ScriptFunction */
|
||||
public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
|
||||
|
||||
/** Method handle used for implementing sync() in mozilla_compat */
|
||||
public static final MethodHandle INVOKE_SYNC = findOwnMH("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
|
||||
|
||||
/** Method handle for allocate function for this ScriptFunction */
|
||||
static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
|
||||
|
||||
@ -300,6 +303,14 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
*/
|
||||
public abstract void setPrototype(Object prototype);
|
||||
|
||||
/**
|
||||
* Create a function that invokes this function synchronized on {@code sync} or the self object
|
||||
* of the invocation.
|
||||
* @param sync the Object to synchronize on, or undefined
|
||||
* @return synchronized function
|
||||
*/
|
||||
public abstract ScriptFunction makeSynchronizedFunction(Object sync);
|
||||
|
||||
/**
|
||||
* Return the most appropriate invoke handle if there are specializations
|
||||
* @param type most specific method type to look for invocation with
|
||||
@ -614,6 +625,15 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
|
||||
throws Throwable {
|
||||
final Object syncObj = sync == UNDEFINED ? self : sync;
|
||||
synchronized (syncObj) {
|
||||
return func.invoke(self, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
final Class<?> own = ScriptFunction.class;
|
||||
final MethodType mt = MH.type(rtype, types);
|
||||
|
@ -675,7 +675,7 @@ public abstract class ScriptFunctionData {
|
||||
|
||||
/**
|
||||
* Heuristic to figure out if the method handle has a callee argument. If it's type is either
|
||||
* {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has
|
||||
* {@code (boolean, ScriptFunction, ...)} or {@code (ScriptFunction, ...)}, then we'll assume it has
|
||||
* a callee argument. We need this as the constructor above is not passed this information, and can't just blindly
|
||||
* assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
|
||||
* they also always receive a callee).
|
||||
@ -692,11 +692,11 @@ public abstract class ScriptFunctionData {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type.parameterType(0) == boolean.class) {
|
||||
return length > 1 && type.parameterType(1) == ScriptFunction.class;
|
||||
if (type.parameterType(0) == ScriptFunction.class) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return type.parameterType(0) == ScriptFunction.class;
|
||||
return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == ScriptFunction.class;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,8 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET;
|
||||
import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
|
||||
import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
@ -131,6 +133,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
static final MethodHandle GETPROTO = findOwnMH("getProto", ScriptObject.class);
|
||||
static final MethodHandle SETPROTOCHECK = findOwnMH("setProtoCheck", void.class, Object.class);
|
||||
static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
|
||||
|
||||
static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
|
||||
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
|
||||
@ -388,7 +391,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return global.newDataDescriptor(getWithProperty(property), configurable, enumerable, writable);
|
||||
}
|
||||
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -592,7 +595,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* @param value value to define
|
||||
*/
|
||||
protected final void defineOwnProperty(final int index, final Object value) {
|
||||
assert ArrayIndex.isValidArrayIndex(index) : "invalid array index";
|
||||
assert isValidArrayIndex(index) : "invalid array index";
|
||||
final long longIndex = ArrayIndex.toLongIndex(index);
|
||||
if (longIndex >= getArray().length()) {
|
||||
// make array big enough to hold..
|
||||
@ -602,9 +605,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private void checkIntegerKey(final String key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
|
||||
if (data.has(index)) {
|
||||
@ -614,7 +617,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private void removeArraySlot(final String key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -716,6 +719,28 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level property API. This is similar to {@link #findProperty(String, boolean)} but returns a
|
||||
* {@code boolean} value instead of a {@link FindProperty} object.
|
||||
* @param key Property key.
|
||||
* @param deep Whether the search should look up proto chain.
|
||||
* @return true if the property was found.
|
||||
*/
|
||||
boolean hasProperty(final String key, final boolean deep) {
|
||||
if (getMap().findProperty(key) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (deep) {
|
||||
final ScriptObject myProto = getProto();
|
||||
if (myProto != null) {
|
||||
return myProto.hasProperty(key, deep);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new property to the object.
|
||||
* <p>
|
||||
@ -1708,8 +1733,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
*/
|
||||
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
|
||||
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
final FindProperty find = findProperty(name, true);
|
||||
if (request.isCallSiteUnstable()) {
|
||||
return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(name, true);
|
||||
MethodHandle methodHandle;
|
||||
|
||||
if (find == null) {
|
||||
@ -1727,10 +1755,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
throw new AssertionError(); // never invoked with any other operation
|
||||
}
|
||||
|
||||
if (request.isCallSiteUnstable()) {
|
||||
return findMegaMorphicGetMethod(desc, name);
|
||||
}
|
||||
|
||||
final Class<?> returnType = desc.getMethodType().returnType();
|
||||
final Property property = find.getProperty();
|
||||
methodHandle = find.getGetter(returnType);
|
||||
@ -1757,11 +1781,21 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
|
||||
}
|
||||
|
||||
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
|
||||
final MethodType mhType = desc.getMethodType().insertParameterTypes(1, Object.class);
|
||||
final GuardedInvocation inv = findGetIndexMethod(mhType);
|
||||
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
|
||||
final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
|
||||
final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
|
||||
return new GuardedInvocation(invoker, guard);
|
||||
}
|
||||
|
||||
return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
|
||||
@SuppressWarnings("unused")
|
||||
private Object megamorphicGet(final String key, final boolean isMethod) {
|
||||
final FindProperty find = findProperty(key, true);
|
||||
|
||||
if (find != null) {
|
||||
return getObjectValue(find);
|
||||
}
|
||||
|
||||
return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1810,7 +1844,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
*/
|
||||
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
|
||||
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
if(request.isCallSiteUnstable()) {
|
||||
if (request.isCallSiteUnstable()) {
|
||||
return findMegaMorphicSetMethod(desc, name);
|
||||
}
|
||||
|
||||
@ -2045,6 +2079,26 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get __noSuchMethod__ as a function bound to this object and {@code name} if it is defined.
|
||||
* @param name the method name
|
||||
* @return the bound function, or undefined
|
||||
*/
|
||||
private Object getNoSuchMethod(final String name) {
|
||||
final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
|
||||
|
||||
if (find == null) {
|
||||
return invokeNoSuchProperty(name);
|
||||
}
|
||||
|
||||
final Object value = getObjectValue(find);
|
||||
if (! (value instanceof ScriptFunction)) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
return ((ScriptFunction)value).makeBoundFunction(this, new Object[] {name});
|
||||
}
|
||||
|
||||
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
|
||||
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap()));
|
||||
}
|
||||
@ -2308,7 +2362,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private int getInt(final int index, final String key) {
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject object = this; ; ) {
|
||||
final FindProperty find = object.findProperty(key, false, false, this);
|
||||
|
||||
@ -2339,7 +2393,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public int getInt(final Object key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2351,7 +2405,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public int getInt(final double key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2363,7 +2417,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public int getInt(final long key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2385,7 +2439,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private long getLong(final int index, final String key) {
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject object = this; ; ) {
|
||||
final FindProperty find = object.findProperty(key, false, false, this);
|
||||
|
||||
@ -2416,7 +2470,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public long getLong(final Object key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2428,7 +2482,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public long getLong(final double key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2440,7 +2494,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public long getLong(final long key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2462,7 +2516,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private double getDouble(final int index, final String key) {
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject object = this; ; ) {
|
||||
final FindProperty find = object.findProperty(key, false, false, this);
|
||||
|
||||
@ -2493,7 +2547,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public double getDouble(final Object key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2505,7 +2559,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public double getDouble(final double key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2517,7 +2571,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public double getDouble(final long key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2539,7 +2593,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private Object get(final int index, final String key) {
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject object = this; ; ) {
|
||||
final FindProperty find = object.findProperty(key, false, false, this);
|
||||
|
||||
@ -2570,7 +2624,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public Object get(final Object key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2582,7 +2636,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public Object get(final double key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2594,7 +2648,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public Object get(final long key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -2710,9 +2764,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public void set(final Object key, final int value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2722,14 +2776,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(key, JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final Object key, final long value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2739,14 +2794,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(key, JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final Object key, final double value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2756,14 +2812,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(key, JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final Object key, final Object value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2773,17 +2830,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
final String propName = JSType.toString(key);
|
||||
final FindProperty find = findProperty(propName, true);
|
||||
|
||||
setObject(find, strict, propName, value);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final double key, final int value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2793,14 +2848,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final double key, final long value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2810,14 +2866,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final double key, final double value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2827,14 +2884,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final double key, final Object value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2844,14 +2902,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), value, strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final long key, final int value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2861,14 +2920,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final long key, final long value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2878,14 +2938,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final long key, final double value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2895,14 +2956,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final long key, final Object value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2912,14 +2974,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), value, strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final int key, final int value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2929,14 +2992,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final int key, final long value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2946,14 +3010,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final int key, final double value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2963,14 +3028,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), JSType.toObject(value), strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final int key, final Object value, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
setArray(getArray().set(index, value, strict));
|
||||
} else {
|
||||
@ -2980,14 +3046,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return;
|
||||
}
|
||||
|
||||
set(JSType.toObject(key), value, strict);
|
||||
final String propName = JSType.toString(key);
|
||||
setObject(findProperty(propName, true), strict, propName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(final Object key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject self = this; self != null; self = self.getProto()) {
|
||||
if (self.getArray().has(index)) {
|
||||
return true;
|
||||
@ -2995,16 +3062,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
return hasProperty(JSType.toString(key), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(final double key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject self = this; self != null; self = self.getProto()) {
|
||||
if (self.getArray().has(index)) {
|
||||
return true;
|
||||
@ -3012,16 +3077,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
return hasProperty(JSType.toString(key), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(final long key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject self = this; self != null; self = self.getProto()) {
|
||||
if (self.getArray().has(index)) {
|
||||
return true;
|
||||
@ -3029,16 +3092,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
return hasProperty(JSType.toString(key), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(final int key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
|
||||
if (ArrayIndex.isValidArrayIndex(index)) {
|
||||
if (isValidArrayIndex(index)) {
|
||||
for (ScriptObject self = this; self != null; self = self.getProto()) {
|
||||
if (self.getArray().has(index)) {
|
||||
return true;
|
||||
@ -3046,66 +3107,32 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), true);
|
||||
|
||||
return find != null;
|
||||
return hasProperty(JSType.toString(key), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnProperty(final Object key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
|
||||
if (getArray().has(index)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnProperty(final int key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
|
||||
if (getArray().has(index)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnProperty(final long key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
|
||||
if (getArray().has(index)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnProperty(final double key) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
|
||||
if (getArray().has(index)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final FindProperty find = findProperty(JSType.toString(key), false);
|
||||
|
||||
return find != null;
|
||||
return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(final int key, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -3121,7 +3148,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public boolean delete(final long key, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -3137,7 +3164,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public boolean delete(final double key, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
@ -3153,7 +3180,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
@Override
|
||||
public boolean delete(final Object key, final boolean strict) {
|
||||
final int index = ArrayIndex.getArrayIndex(key);
|
||||
final int index = getArrayIndex(key);
|
||||
final ArrayData array = getArray();
|
||||
|
||||
if (array.has(index)) {
|
||||
|
@ -25,9 +25,9 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
@ -211,6 +211,20 @@ final class JavaArgumentConverters {
|
||||
return null;
|
||||
} else if (obj instanceof Long) {
|
||||
return (Long) obj;
|
||||
} else if (obj instanceof Integer) {
|
||||
return ((Integer)obj).longValue();
|
||||
} else if (obj instanceof Double) {
|
||||
final Double d = (Double)obj;
|
||||
if(Double.isInfinite(d.doubleValue())) {
|
||||
return 0L;
|
||||
}
|
||||
return d.longValue();
|
||||
} else if (obj instanceof Float) {
|
||||
final Float f = (Float)obj;
|
||||
if(Float.isInfinite(f.floatValue())) {
|
||||
return 0L;
|
||||
}
|
||||
return f.longValue();
|
||||
} else if (obj instanceof Number) {
|
||||
return ((Number)obj).longValue();
|
||||
} else if (obj instanceof String || obj instanceof ConsString) {
|
||||
|
@ -30,6 +30,8 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.ConversionComparator;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
@ -38,6 +40,8 @@ import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
import jdk.nashorn.internal.objects.NativeArray;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.Undefined;
|
||||
@ -47,6 +51,13 @@ import jdk.nashorn.internal.runtime.Undefined;
|
||||
* includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}.
|
||||
*/
|
||||
final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
|
||||
private static final ClassValue<MethodHandle> ARRAY_CONVERTERS = new ClassValue<MethodHandle>() {
|
||||
@Override
|
||||
protected MethodHandle computeValue(Class<?> type) {
|
||||
return createArrayConverter(type);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if {@code ScriptObject} is assignable from {@code type}, or it is {@code Undefined}.
|
||||
*/
|
||||
@ -103,6 +114,12 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
if (mh != null) {
|
||||
return new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : IS_NASHORN_OR_UNDEFINED_TYPE);
|
||||
}
|
||||
|
||||
GuardedInvocation inv = getArrayConverter(sourceType, targetType);
|
||||
if(inv != null) {
|
||||
return inv;
|
||||
}
|
||||
|
||||
return getSamTypeConverter(sourceType, targetType);
|
||||
}
|
||||
|
||||
@ -129,6 +146,41 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a guarded invocation that converts from a source type that is NativeArray to a Java array or List or
|
||||
* Deque type.
|
||||
* @param sourceType the source type (presumably NativeArray a superclass of it)
|
||||
* @param targetType the target type (presumably an array type, or List or Deque)
|
||||
* @return a guarded invocation that converts from the source type to the target type. null is returned if
|
||||
* either the source type is neither NativeArray, nor a superclass of it, or if the target type is not an array
|
||||
* type, List, or Deque.
|
||||
*/
|
||||
private static GuardedInvocation getArrayConverter(final Class<?> sourceType, final Class<?> targetType) {
|
||||
final boolean isSourceTypeNativeArray = sourceType == NativeArray.class;
|
||||
// If source type is more generic than ScriptFunction class, we'll need to use a guard
|
||||
final boolean isSourceTypeGeneric = !isSourceTypeNativeArray && sourceType.isAssignableFrom(NativeArray.class);
|
||||
|
||||
if (isSourceTypeNativeArray || isSourceTypeGeneric) {
|
||||
final MethodHandle guard = isSourceTypeGeneric ? IS_NATIVE_ARRAY : null;
|
||||
if(targetType.isArray()) {
|
||||
return new GuardedInvocation(ARRAY_CONVERTERS.get(targetType), guard);
|
||||
}
|
||||
if(targetType == List.class) {
|
||||
return new GuardedInvocation(JSType.TO_JAVA_LIST.methodHandle(), guard);
|
||||
}
|
||||
if(targetType == Deque.class) {
|
||||
return new GuardedInvocation(JSType.TO_JAVA_DEQUE.methodHandle(), guard);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static MethodHandle createArrayConverter(final Class<?> type) {
|
||||
assert type.isArray();
|
||||
final MethodHandle converter = MH.insertArguments(JSType.TO_JAVA_ARRAY.methodHandle(), 1, type.getComponentType());
|
||||
return MH.asType(converter, converter.type().changeReturnType(type));
|
||||
}
|
||||
|
||||
private static boolean isAutoConvertibleFromFunction(final Class<?> clazz) {
|
||||
return isAbstractClass(clazz) && !ScriptObject.class.isAssignableFrom(clazz) &&
|
||||
JavaAdapterFactory.isAutoConvertibleFromFunction(clazz);
|
||||
@ -148,7 +200,26 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
|
||||
@Override
|
||||
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
|
||||
if(sourceType == NativeArray.class) {
|
||||
// Prefer lists, as they're less costly to create than arrays.
|
||||
if(isList(targetType1)) {
|
||||
if(!isList(targetType2)) {
|
||||
return Comparison.TYPE_1_BETTER;
|
||||
}
|
||||
} else if(isList(targetType2)) {
|
||||
return Comparison.TYPE_2_BETTER;
|
||||
}
|
||||
// Then prefer arrays
|
||||
if(targetType1.isArray()) {
|
||||
if(!targetType2.isArray()) {
|
||||
return Comparison.TYPE_1_BETTER;
|
||||
}
|
||||
} else if(targetType2.isArray()) {
|
||||
return Comparison.TYPE_2_BETTER;
|
||||
}
|
||||
}
|
||||
if(ScriptObject.class.isAssignableFrom(sourceType)) {
|
||||
// Prefer interfaces
|
||||
if(targetType1.isInterface()) {
|
||||
if(!targetType2.isInterface()) {
|
||||
return Comparison.TYPE_1_BETTER;
|
||||
@ -160,7 +231,12 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
return Comparison.INDETERMINATE;
|
||||
}
|
||||
|
||||
private static boolean isList(Class<?> clazz) {
|
||||
return clazz == List.class || clazz == Deque.class;
|
||||
}
|
||||
|
||||
private static final MethodHandle IS_SCRIPT_FUNCTION = Guards.isInstance(ScriptFunction.class, MH.type(Boolean.TYPE, Object.class));
|
||||
private static final MethodHandle IS_NATIVE_ARRAY = Guards.isOfClass(NativeArray.class, MH.type(Boolean.TYPE, Object.class));
|
||||
|
||||
private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined",
|
||||
Boolean.TYPE, Object.class);
|
||||
|
@ -98,6 +98,17 @@ Object.defineProperty(this, "importPackage", {
|
||||
|
||||
}
|
||||
|
||||
// sync
|
||||
Object.defineProperty(this, "sync", {
|
||||
configurable: true, enumerable: false, writable: true,
|
||||
value: function(func, syncobj) {
|
||||
if (arguments.length < 1 || arguments.length > 2 ) {
|
||||
throw "sync(function [,object]) parameter count mismatch";
|
||||
}
|
||||
return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj);
|
||||
}
|
||||
});
|
||||
|
||||
// Object.prototype.__defineGetter__
|
||||
Object.defineProperty(Object.prototype, "__defineGetter__", {
|
||||
configurable: true, enumerable: false, writable: true,
|
||||
|
68
nashorn/test/script/basic/JDK-8026016.js
Normal file
68
nashorn/test/script/basic/JDK-8026016.js
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8026016: too many relinks dominate avatar.js http benchmark
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
function accessMegamorphic() {
|
||||
for (var i = 0; i < 26; i++) {
|
||||
var o = {};
|
||||
o[String.fromCharCode(i + 97)] = 1;
|
||||
o._;
|
||||
}
|
||||
}
|
||||
|
||||
function invokeMegamorphic() {
|
||||
for (var i = 0; i < 26; i++) {
|
||||
var o = {};
|
||||
o[String.fromCharCode(i + 97)] = 1;
|
||||
try {
|
||||
o._(i);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.prototype.__noSuchProperty__ = function() {
|
||||
print("no such property", Array.prototype.slice.call(arguments));
|
||||
};
|
||||
|
||||
invokeMegamorphic();
|
||||
accessMegamorphic();
|
||||
|
||||
Object.prototype.__noSuchMethod__ = function() {
|
||||
print("no such method", Array.prototype.slice.call(arguments));
|
||||
};
|
||||
|
||||
invokeMegamorphic();
|
||||
accessMegamorphic();
|
||||
|
||||
Object.prototype.__noSuchMethod__ = "nofunction";
|
||||
|
||||
invokeMegamorphic();
|
||||
accessMegamorphic();
|
182
nashorn/test/script/basic/JDK-8026016.js.EXPECTED
Normal file
182
nashorn/test/script/basic/JDK-8026016.js.EXPECTED
Normal file
@ -0,0 +1,182 @@
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such method _,0
|
||||
no such method _,1
|
||||
no such method _,2
|
||||
no such method _,3
|
||||
no such method _,4
|
||||
no such method _,5
|
||||
no such method _,6
|
||||
no such method _,7
|
||||
no such method _,8
|
||||
no such method _,9
|
||||
no such method _,10
|
||||
no such method _,11
|
||||
no such method _,12
|
||||
no such method _,13
|
||||
no such method _,14
|
||||
no such method _,15
|
||||
no such method _,16
|
||||
no such method _,17
|
||||
no such method _,18
|
||||
no such method _,19
|
||||
no such method _,20
|
||||
no such method _,21
|
||||
no such method _,22
|
||||
no such method _,23
|
||||
no such method _,24
|
||||
no such method _,25
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
TypeError: Cannot call undefined
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
||||
no such property _
|
61
nashorn/test/script/basic/JDK-8026367.js
Normal file
61
nashorn/test/script/basic/JDK-8026367.js
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8026367: Add a sync keyword to mozilla_compat
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
if (typeof sync === "undefined") {
|
||||
load("nashorn:mozilla_compat.js");
|
||||
}
|
||||
|
||||
var obj = {
|
||||
count: 0,
|
||||
// Sync called with one argument will synchronize on this-object of invocation
|
||||
inc: sync(function(d) {
|
||||
this.count += d;
|
||||
}),
|
||||
// Pass explicit object to synchronize on as second argument
|
||||
dec: sync(function(d) {
|
||||
this.count -= d;
|
||||
}, obj)
|
||||
};
|
||||
|
||||
var t1 = new java.lang.Thread(function() {
|
||||
for (var i = 0; i < 100000; i++) obj.inc(1);
|
||||
});
|
||||
var t2 = new java.lang.Thread(function() {
|
||||
for (var i = 0; i < 100000; i++) obj.dec(1);
|
||||
});
|
||||
|
||||
t1.start();
|
||||
t2.start();
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
if (obj.count !== 0) {
|
||||
throw new Error("Expected count == 0, got " + obj.count);
|
||||
}
|
@ -48,3 +48,7 @@ if (typeof JavaAdapter != 'function') {
|
||||
if (typeof importPackage != 'function') {
|
||||
fail("importPackage function is missing in compatibility script");
|
||||
}
|
||||
|
||||
if (typeof sync != 'function') {
|
||||
fail("sync function is missing in compatibility script");
|
||||
}
|
||||
|
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.api.javaaccess;
|
||||
|
||||
import static org.testng.AssertJUnit.assertEquals;
|
||||
import static org.testng.AssertJUnit.assertFalse;
|
||||
import static org.testng.AssertJUnit.assertNull;
|
||||
import static org.testng.AssertJUnit.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import org.testng.TestNG;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class ArrayConversionTest {
|
||||
private static ScriptEngine e = null;
|
||||
|
||||
public static void main(final String[] args) {
|
||||
TestNG.main(args);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws ScriptException {
|
||||
e = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
e = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntArrays() throws ScriptException {
|
||||
runTest("assertNullIntArray", "null");
|
||||
runTest("assertEmptyIntArray", "[]");
|
||||
runTest("assertSingle42IntArray", "[42]");
|
||||
runTest("assertSingle42IntArray", "['42']");
|
||||
runTest("assertIntArrayConversions", "[false, true, NaN, Infinity, -Infinity, 0.4, 0.6, null, undefined, [], {}, [1], [1, 2]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntIntArrays() throws ScriptException {
|
||||
runTest("assertNullIntIntArray", "null");
|
||||
runTest("assertEmptyIntIntArray", "[]");
|
||||
runTest("assertSingleEmptyIntIntArray", "[[]]");
|
||||
runTest("assertSingleNullIntIntArray", "[null]");
|
||||
runTest("assertLargeIntIntArray", "[[false], [1], [2, 3], [4, 5, 6], ['7', {valueOf: function() { return 8 }}]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectObjectArrays() throws ScriptException {
|
||||
runTest("assertLargeObjectObjectArray", "[[false], [1], ['foo', 42.3], [{x: 17}]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanArrays() throws ScriptException {
|
||||
runTest("assertBooleanArrayConversions", "[false, true, '', 'false', 0, 1, 0.4, 0.6, {}, [], [false], [true], NaN, Infinity, null, undefined]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayAmbiguity() throws ScriptException {
|
||||
runTest("x", "'abc'");
|
||||
runTest("x", "['foo', 'bar']");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListArrays() throws ScriptException {
|
||||
runTest("assertListArray", "[['foo', 'bar'], ['apple', 'orange']]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarArgs() throws ScriptException {
|
||||
// Sole NativeArray in vararg position becomes vararg array itself
|
||||
runTest("assertVarArg_42_17", "[42, 17]");
|
||||
// NativeArray in vararg position becomes an argument if there are more arguments
|
||||
runTest("assertVarArg_array_17", "[42], 18");
|
||||
// Only NativeArray is converted to vararg array, other objects (e.g. a function) aren't
|
||||
runTest("assertVarArg_function", "function() { return 'Hello' }");
|
||||
}
|
||||
|
||||
private static void runTest(final String testMethodName, final String argument) throws ScriptException {
|
||||
e.eval("Java.type('" + ArrayConversionTest.class.getName() + "')." + testMethodName + "(" + argument + ")");
|
||||
}
|
||||
|
||||
public static void assertNullIntArray(int[] array) {
|
||||
assertNull(array);
|
||||
}
|
||||
|
||||
public static void assertNullIntIntArray(int[][] array) {
|
||||
assertNull(array);
|
||||
}
|
||||
|
||||
public static void assertEmptyIntArray(int[] array) {
|
||||
assertEquals(0, array.length);
|
||||
}
|
||||
|
||||
public static void assertSingle42IntArray(int[] array) {
|
||||
assertEquals(1, array.length);
|
||||
assertEquals(42, array[0]);
|
||||
}
|
||||
|
||||
|
||||
public static void assertIntArrayConversions(int[] array) {
|
||||
assertEquals(13, array.length);
|
||||
assertEquals(0, array[0]); // false
|
||||
assertEquals(1, array[1]); // true
|
||||
assertEquals(0, array[2]); // NaN
|
||||
assertEquals(0, array[3]); // Infinity
|
||||
assertEquals(0, array[4]); // -Infinity
|
||||
assertEquals(0, array[5]); // 0.4
|
||||
assertEquals(0, array[6]); // 0.6 - floor, not round
|
||||
assertEquals(0, array[7]); // null
|
||||
assertEquals(0, array[8]); // undefined
|
||||
assertEquals(0, array[9]); // []
|
||||
assertEquals(0, array[10]); // {}
|
||||
assertEquals(1, array[11]); // [1]
|
||||
assertEquals(0, array[12]); // [1, 2]
|
||||
}
|
||||
|
||||
public static void assertEmptyIntIntArray(int[][] array) {
|
||||
assertEquals(0, array.length);
|
||||
}
|
||||
|
||||
public static void assertSingleEmptyIntIntArray(int[][] array) {
|
||||
assertEquals(1, array.length);
|
||||
assertTrue(Arrays.equals(new int[0], array[0]));
|
||||
}
|
||||
|
||||
public static void assertSingleNullIntIntArray(int[][] array) {
|
||||
assertEquals(1, array.length);
|
||||
assertNull(null, array[0]);
|
||||
}
|
||||
|
||||
public static void assertLargeIntIntArray(int[][] array) {
|
||||
assertEquals(5, array.length);
|
||||
assertTrue(Arrays.equals(new int[] { 0 }, array[0]));
|
||||
assertTrue(Arrays.equals(new int[] { 1 }, array[1]));
|
||||
assertTrue(Arrays.equals(new int[] { 2, 3 }, array[2]));
|
||||
assertTrue(Arrays.equals(new int[] { 4, 5, 6 }, array[3]));
|
||||
assertTrue(Arrays.equals(new int[] { 7, 8 }, array[4]));
|
||||
}
|
||||
|
||||
public static void assertLargeObjectObjectArray(Object[][] array) throws ScriptException {
|
||||
assertEquals(4, array.length);
|
||||
assertTrue(Arrays.equals(new Object[] { Boolean.FALSE }, array[0]));
|
||||
assertTrue(Arrays.equals(new Object[] { 1 }, array[1]));
|
||||
assertTrue(Arrays.equals(new Object[] { "foo", 42.3d }, array[2]));
|
||||
assertEquals(1, array[3].length);
|
||||
e.getBindings(ScriptContext.ENGINE_SCOPE).put("obj", array[3][0]);
|
||||
assertEquals(17, e.eval("obj.x"));
|
||||
}
|
||||
|
||||
public static void assertBooleanArrayConversions(boolean[] array) {
|
||||
assertEquals(16, array.length);
|
||||
assertFalse(array[0]); // false
|
||||
assertTrue(array[1]); // true
|
||||
assertFalse(array[2]); // ''
|
||||
assertTrue(array[3]); // 'false' (yep, every non-empty string converts to true)
|
||||
assertFalse(array[4]); // 0
|
||||
assertTrue(array[5]); // 1
|
||||
assertTrue(array[6]); // 0.4
|
||||
assertTrue(array[7]); // 0.6
|
||||
assertTrue(array[8]); // {}
|
||||
assertTrue(array[9]); // []
|
||||
assertTrue(array[10]); // [false]
|
||||
assertTrue(array[11]); // [true]
|
||||
assertFalse(array[12]); // NaN
|
||||
assertTrue(array[13]); // Infinity
|
||||
assertFalse(array[14]); // null
|
||||
assertFalse(array[15]); // undefined
|
||||
}
|
||||
|
||||
public static void assertListArray(List<?>[] array) {
|
||||
assertEquals(2, array.length);
|
||||
assertEquals(Arrays.asList("foo", "bar"), array[0]);
|
||||
assertEquals(Arrays.asList("apple", "orange"), array[1]);
|
||||
}
|
||||
|
||||
public static void assertVarArg_42_17(Object... args) throws ScriptException {
|
||||
assertEquals(2, args.length);
|
||||
assertEquals(42, ((Number)args[0]).intValue());
|
||||
assertEquals(17, ((Number)args[1]).intValue());
|
||||
}
|
||||
|
||||
public static void assertVarArg_array_17(Object... args) throws ScriptException {
|
||||
assertEquals(2, args.length);
|
||||
e.getBindings(ScriptContext.ENGINE_SCOPE).put("arr", args[0]);
|
||||
assertTrue((Boolean)e.eval("arr instanceof Array && arr.length == 1 && arr[0] == 42"));
|
||||
assertEquals(18, ((Number)args[1]).intValue());
|
||||
}
|
||||
|
||||
public static void assertVarArg_function(Object... args) throws ScriptException {
|
||||
assertEquals(1, args.length);
|
||||
e.getBindings(ScriptContext.ENGINE_SCOPE).put("fn", args[0]);
|
||||
assertEquals("Hello", e.eval("fn()"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void x(String y) {
|
||||
assertEquals("abc", y);
|
||||
}
|
||||
public static void x(String[] y) {
|
||||
assertTrue(Arrays.equals(new String[] { "foo", "bar"}, y));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user