src/jdk/nashorn/internal/runtime/ScriptFunction.java
Print this page
*** 35,45 ****
import java.lang.invoke.MethodType;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
- import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
import jdk.nashorn.internal.runtime.options.Options;
import org.dynalang.dynalink.CallSiteDescriptor;
--- 35,44 ----
*** 68,305 ****
private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
- /** method handle to arity setter for this ScriptFunction */
- public static final Call SET_ARITY = virtualCallNoLookup(ScriptFunction.class, "setArity", void.class, int.class);
/** method handle to scope getter for this ScriptFunction */
public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
/** Should specialized function and specialized constructors for the builtin be used if available? */
private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable");
! /** Name of function or null. */
! private final String name;
!
! /** Source of function. */
! private final Source source;
!
! /** Start position and length in source. */
! private final long token;
!
! /** Reference to code for this method. */
! private final MethodHandle invokeHandle;
!
! /** Reference to code for this method when called to create "new" object */
! protected MethodHandle constructHandle;
/** Reference to constructor prototype. */
protected Object prototype;
- /** Constructor to create a new instance. */
- private MethodHandle allocator;
-
- /** Map for new instance constructor. */
- private PropertyMap allocatorMap;
-
/** The parent scope. */
private final ScriptObject scope;
- /** Specializations - see @SpecializedFunction */
- private MethodHandle[] invokeSpecializations;
-
- /** Specializations - see @SpecializedFunction */
- private MethodHandle[] constructSpecializations;
-
- /** This field is either computed in constructor or set explicitly by calling setArity method. */
- private int arity;
-
/**
* Constructor
*
* @param name function name
* @param methodHandle method handle to function (if specializations are present, assumed to be most generic)
* @param map property map
* @param scope scope
* @param specs specialized version of this function - other method handles
- */
- protected ScriptFunction(
- final String name,
- final MethodHandle methodHandle,
- final PropertyMap map,
- final ScriptObject scope,
- final MethodHandle[] specs) {
- this(name, methodHandle, map, scope, null, 0, needsCallee(methodHandle), specs);
- }
-
- /**
- * 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
- * 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.
- * @param methodHandle the examined method handle
- * @return true if the method handle expects a callee, false otherwise
- */
- private static boolean needsCallee(MethodHandle methodHandle) {
- final MethodType type = methodHandle.type();
- final int len = type.parameterCount();
- if(len == 0) {
- return false;
- }
- if(type.parameterType(0) == boolean.class) {
- return len > 2 && type.parameterType(2) == ScriptFunction.class;
- }
- return len > 1 && type.parameterType(1) == ScriptFunction.class;
- }
-
- /**
- * Constructor
*
- * @param name function name
- * @param methodHandle method handle to function (if specializations are present, assumed to be most generic)
- * @param map property map
- * @param scope scope
- * @param source the source
- * @param token token
- * @param allocator method handle to this function's allocator - see JO$ classes
- * @param allocatorMap property map to be used for all constructors
- * @param needsCallee does this method use the {@code callee} variable
- * @param specs specialized version of this function - other method handles
*/
protected ScriptFunction(
final String name,
final MethodHandle methodHandle,
final PropertyMap map,
final ScriptObject scope,
! final Source source,
! final long token,
! final MethodHandle allocator,
! final PropertyMap allocatorMap,
! final boolean needsCallee,
! final MethodHandle[] specs) {
!
! this(name, methodHandle, map, scope, source, token, needsCallee, specs);
!
! //this is the internal constructor
! this.allocator = allocator;
! this.allocatorMap = allocatorMap;
}
/**
* Constructor
*
! * @param name function name
! * @param methodHandle method handle to function (if specializations are present, assumed to be most generic)
* @param map property map
* @param scope scope
- * @param source the source
- * @param token token
- * @param needsCallee does this method use the {@code callee} variable
- * @param specs specialized version of this function - other method handles
*/
protected ScriptFunction(
! final String name,
! final MethodHandle methodHandle,
final PropertyMap map,
! final ScriptObject scope,
! final Source source,
! final long token,
! final boolean needsCallee,
! final MethodHandle[] specs) {
super(map);
if (Context.DEBUG) {
constructorCount++;
}
! this.name = name;
! this.source = source;
! this.token = token;
this.scope = scope;
- if(needsCallee) {
- setHasCalleeParameter();
- }
-
- final MethodType type = methodHandle.type();
- final int paramCount = type.parameterCount();
- final boolean isVarArg = type.parameterType(paramCount - 1).isArray();
-
- final MethodHandle mh = MH.asType(methodHandle, adaptType(type, needsCallee, isVarArg));
-
- this.arity = isVarArg ? -1 : paramCount - 1; //drop the self param for arity
-
- if (needsCallee && !isVarArg) {
- this.arity--;
- }
-
- if (scope != null) {
- this.invokeHandle = mh;
- this.constructHandle = mh;
- } else if (isConstructor(mh)) {
- if (!isVarArg) {
- this.arity--; // drop the boolean flag for arity
- }
- /*
- * We insert a boolean argument to tell if the method was invoked as
- * constructor or not if the method handle's first argument is boolean.
- */
- this.invokeHandle = MH.insertArguments(mh, 0, false);
- this.constructHandle = MH.insertArguments(mh, 0, true);
-
- if (specs != null) {
- this.invokeSpecializations = new MethodHandle[specs.length];
- this.constructSpecializations = new MethodHandle[specs.length];
- for (int i = 0; i < specs.length; i++) {
- this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false);
- this.constructSpecializations[i] = MH.insertArguments(specs[i], 0, true);
- }
- }
- } else {
- this.invokeHandle = mh;
- this.constructHandle = mh;
- this.invokeSpecializations = specs;
- this.constructSpecializations = specs;
- }
- }
-
- /**
- * Takes a method type, and returns a (potentially different method type) that the method handles used by
- * ScriptFunction must conform to in order to be usable in {@link #invoke(Object, Object...)} and
- * {@link #construct(Object, Object...)}. The returned method type will be sure to return {@code Object}, and will
- * have all its parameters turned into {@code Object} as well, except for the following ones:
- * <ul>
- * <li>an optional first {@code boolean} parameter, used for some functions to distinguish method and constructor
- * invocation,</li>
- * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
- * <li>the second (or, in presence of boolean parameter, third) argument, which is forced to be
- * {@link ScriptFunction}, in case the function receives itself (callee) as an argument</li>
- * @param type the original type
- * @param hasCallee true if the function uses the callee argument
- * @param isVarArg if the function is a vararg
- * @return the new type, conforming to the rules above.
- */
- private static MethodType adaptType(final MethodType type, final boolean hasCallee, final boolean isVarArg) {
- // Generify broadly
- MethodType newType = type.generic().changeReturnType(Object.class);
- if(isVarArg) {
- // Change back to vararg if we over-generified it
- newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
- }
- final boolean hasBoolean = type.parameterType(0) == boolean.class;
- if(hasBoolean) {
- // Restore the initial boolean argument
- newType = newType.changeParameterType(0, boolean.class);
- }
- if(hasCallee) {
- // Restore the ScriptFunction argument
- newType = newType.changeParameterType(hasBoolean ? 2 : 1, ScriptFunction.class);
- }
- return newType;
}
@Override
public String getClassName() {
return "Function";
--- 67,132 ----
private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
/** method handle to scope getter for this ScriptFunction */
public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
/** Should specialized function and specialized constructors for the builtin be used if available? */
private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable");
! private final ScriptFunctionData data;
/** Reference to constructor prototype. */
protected Object prototype;
/** The parent scope. */
private final ScriptObject scope;
/**
* Constructor
*
* @param name function name
* @param methodHandle method handle to function (if specializations are present, assumed to be most generic)
* @param map property map
* @param scope scope
* @param specs specialized version of this function - other method handles
*
*/
protected ScriptFunction(
final String name,
final MethodHandle methodHandle,
final PropertyMap map,
final ScriptObject scope,
! final MethodHandle[] specs,
! final boolean strict,
! final boolean builtin) {
! this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin), map, scope);
}
/**
* Constructor
*
! * @param data static function data
* @param map property map
* @param scope scope
*/
protected ScriptFunction(
! final ScriptFunctionData data,
final PropertyMap map,
! final ScriptObject scope) {
super(map);
if (Context.DEBUG) {
constructorCount++;
}
! this.data = data;
this.scope = scope;
}
@Override
public String getClassName() {
return "Function";
*** 327,365 ****
/**
* Get the arity of this ScriptFunction
* @return arity
*/
public final int getArity() {
! return arity;
}
/**
* Set the arity of this ScriptFunction
* @param arity arity
*/
public final void setArity(final int arity) {
! this.arity = arity;
}
/**
* Is this a ECMAScript 'use strict' function?
* @return true if function is in strict mode
*/
! public abstract boolean isStrict();
/**
* Is this a ECMAScript built-in function (like parseInt, Array.isArray) ?
* @return true if built-in
*/
! public abstract boolean isBuiltin();
/**
! * Is this a non-strict and not-built-in script function?
! * @return true if neither strict nor built-in
*/
! public boolean isNonStrictFunction() {
! return !isStrict() && !isBuiltin();
}
/**
* Execute this script function.
* @param self Target object.
--- 154,197 ----
/**
* Get the arity of this ScriptFunction
* @return arity
*/
public final int getArity() {
! return data.getArity();
}
/**
* Set the arity of this ScriptFunction
* @param arity arity
*/
public final void setArity(final int arity) {
! data.setArity(arity);
}
/**
* Is this a ECMAScript 'use strict' function?
* @return true if function is in strict mode
*/
! public boolean isStrict() {
! return data.isStrict();
! }
/**
* Is this a ECMAScript built-in function (like parseInt, Array.isArray) ?
* @return true if built-in
*/
! public boolean isBuiltin() {
! return data.isBuiltin();
! }
/**
! * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
! * according to ECMA 10.4.3.
! * @return true if this argument must be an object
*/
! public boolean needsWrappedThis() {
! return data.needsWrappedThis();
}
/**
* Execute this script function.
* @param self Target object.
*** 370,416 ****
public Object invoke(final Object self, final Object... arguments) throws Throwable {
if (Context.DEBUG) {
invokes++;
}
final Object selfObj = convertThisObject(self);
final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
! if (isVarArg(invokeHandle)) {
! if (hasCalleeParameter()) {
! return invokeHandle.invokeExact(selfObj, this, args);
}
! return invokeHandle.invokeExact(selfObj, args);
}
! final int paramCount = invokeHandle.type().parameterCount();
! if (hasCalleeParameter()) {
switch (paramCount) {
case 2:
! return invokeHandle.invokeExact(selfObj, this);
case 3:
! return invokeHandle.invokeExact(selfObj, this, getArg(args, 0));
case 4:
! return invokeHandle.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1));
case 5:
! return invokeHandle.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return invokeHandle.invokeWithArguments(withArguments(selfObj, this, paramCount, args));
}
}
switch (paramCount) {
case 1:
! return invokeHandle.invokeExact(selfObj);
case 2:
! return invokeHandle.invokeExact(selfObj, getArg(args, 0));
case 3:
! return invokeHandle.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
case 4:
! return invokeHandle.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return invokeHandle.invokeWithArguments(withArguments(selfObj, null, paramCount, args));
}
}
private static Object getArg(final Object[] args, final int i) {
return i < args.length ? args[i] : UNDEFINED;
--- 202,249 ----
public Object invoke(final Object self, final Object... arguments) throws Throwable {
if (Context.DEBUG) {
invokes++;
}
+ final MethodHandle invoker = data.getGenericInvoker();
final Object selfObj = convertThisObject(self);
final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
! if (data.isVarArg()) {
! if (data.needsCallee()) {
! return invoker.invokeExact(selfObj, this, args);
}
! return invoker.invokeExact(selfObj, args);
}
! final int paramCount = invoker.type().parameterCount();
! if (data.needsCallee()) {
switch (paramCount) {
case 2:
! return invoker.invokeExact(selfObj, this);
case 3:
! return invoker.invokeExact(selfObj, this, getArg(args, 0));
case 4:
! return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1));
case 5:
! return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return invoker.invokeWithArguments(withArguments(selfObj, this, paramCount, args));
}
}
switch (paramCount) {
case 1:
! return invoker.invokeExact(selfObj);
case 2:
! return invoker.invokeExact(selfObj, getArg(args, 0));
case 3:
! return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
case 4:
! return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return invoker.invokeWithArguments(withArguments(selfObj, null, paramCount, args));
}
}
private static Object getArg(final Object[] args, final int i) {
return i < args.length ? args[i] : UNDEFINED;
*** 422,469 ****
* @param args Call arguments.
* @return ScriptFunction result.
* @throws Throwable if there is an exception/error with the constructor invocation or thrown from it
*/
public Object construct(final Object self, final Object... args) throws Throwable {
! if (constructHandle == null) {
typeError("not.a.constructor", ScriptRuntime.safeToString(this));
}
! if (isVarArg(constructHandle)) {
! if (hasCalleeParameter()) {
! return constructHandle.invokeExact(self, this, args);
}
! return constructHandle.invokeExact(self, args);
}
! final int paramCount = constructHandle.type().parameterCount();
! if (hasCalleeParameter()) {
switch (paramCount) {
case 2:
! return constructHandle.invokeExact(self, this);
case 3:
! return constructHandle.invokeExact(self, this, getArg(args, 0));
case 4:
! return constructHandle.invokeExact(self, this, getArg(args, 0), getArg(args, 1));
case 5:
! return constructHandle.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return constructHandle.invokeWithArguments(withArguments(self, this, args));
}
}
switch(paramCount) {
case 1:
! return constructHandle.invokeExact(self);
case 2:
! return constructHandle.invokeExact(self, getArg(args, 0));
case 3:
! return constructHandle.invokeExact(self, getArg(args, 0), getArg(args, 1));
case 4:
! return constructHandle.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return constructHandle.invokeWithArguments(withArguments(self, null, args));
}
}
private static Object[] withArguments(final Object self, final ScriptFunction function, final Object... args) {
return withArguments(self, function, args.length + (function == null ? 1 : 2), args); // + 2 to include self and function
--- 255,303 ----
* @param args Call arguments.
* @return ScriptFunction result.
* @throws Throwable if there is an exception/error with the constructor invocation or thrown from it
*/
public Object construct(final Object self, final Object... args) throws Throwable {
! if (data.getConstructor() == null) {
typeError("not.a.constructor", ScriptRuntime.safeToString(this));
}
! final MethodHandle constructor = data.getGenericConstructor();
! if (data.isVarArg()) {
! if (data.needsCallee()) {
! return constructor.invokeExact(self, this, args);
}
! return constructor.invokeExact(self, args);
}
! final int paramCount = constructor.type().parameterCount();
! if (data.needsCallee()) {
switch (paramCount) {
case 2:
! return constructor.invokeExact(self, this);
case 3:
! return constructor.invokeExact(self, this, getArg(args, 0));
case 4:
! return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1));
case 5:
! return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return constructor.invokeWithArguments(withArguments(self, this, args));
}
}
switch(paramCount) {
case 1:
! return constructor.invokeExact(self);
case 2:
! return constructor.invokeExact(self, getArg(args, 0));
case 3:
! return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1));
case 4:
! return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2));
default:
! return constructor.invokeWithArguments(withArguments(self, null, args));
}
}
private static Object[] withArguments(final Object self, final ScriptFunction function, final Object... args) {
return withArguments(self, function, args.length + (function == null ? 1 : 2), args); // + 2 to include self and function
*** 507,519 ****
typeError("not.a.constructor", ScriptRuntime.safeToString(this));
}
ScriptObject object = null;
! if (allocator != null) {
try {
! object = (ScriptObject)allocator.invokeExact(allocatorMap);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
--- 341,353 ----
typeError("not.a.constructor", ScriptRuntime.safeToString(this));
}
ScriptObject object = null;
! if (data.getAllocator() != null) {
try {
! object = (ScriptObject)data.getAllocator().invokeExact(data.getAllocatorMap());
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {
throw new RuntimeException(t);
}
*** 544,610 ****
* @param args other arguments (beside self) to bind the function to
* @return the bound function
*/
public abstract ScriptFunction makeBoundFunction(Object self, Object[] args);
- /**
- * Test if a methodHandle refers to a constructor.
- * @param methodHandle MethodHandle to test.
- * @return True if method is a constructor.
- */
- private static boolean isConstructor(final MethodHandle methodHandle) {
- return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class;
- }
-
- /**
- * Test if a methodHandle refers to a variable argument method.
- * @param methodHandle MethodHandle to test.
- * @return True if variable arguments.
- */
- public boolean isVarArg(final MethodHandle methodHandle) {
- return hasCalleeParameter()
- ? methodHandle.type().parameterCount() == 3 && methodHandle.type().parameterType(2).isArray()
- : methodHandle.type().parameterCount() == 2 && methodHandle.type().parameterType(1).isArray();
- }
@Override
public final String safeToString() {
return toSource();
}
@Override
public String toString() {
! final StringBuilder sb = new StringBuilder();
!
! sb.append(super.toString())
! .append(" [ ")
! .append(invokeHandle)
! .append(", ")
! .append((name == null || name.isEmpty()) ? "<anonymous>" : name);
!
! if (source != null) {
! sb.append(" @ ")
! .append(source.getName())
! .append(':')
! .append(source.getLine(Token.descPosition(token)));
! }
! sb.append(" ]");
!
! return sb.toString();
}
/**
* Get this function as a String containing its source code. If no source code
* exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
* @return string representation of this function's source
*/
public final String toSource() {
! if (source != null && token != 0) {
! return source.getString(Token.descPosition(token), Token.descLength(token));
! }
!
! return "function " + (name == null ? "" : name) + "() { [native code] }";
}
/**
* Get the prototype object for this function
* @return prototype
--- 378,405 ----
* @param args other arguments (beside self) to bind the function to
* @return the bound function
*/
public abstract ScriptFunction makeBoundFunction(Object self, Object[] args);
@Override
public final String safeToString() {
return toSource();
}
@Override
public String toString() {
! return data.toString();
}
/**
* Get this function as a String containing its source code. If no source code
* exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
* @return string representation of this function's source
*/
public final String toSource() {
! return data.toSource();
}
/**
* Get the prototype object for this function
* @return prototype
*** 694,714 ****
* Return the most appropriate invoke handle if there are specializations
* @param type most specific method type to look for invocation with
* @return invoke method handle
*/
public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) {
! return candidateWithLowestWeight(type, getInvokeHandle(), invokeSpecializations);
}
/**
* Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
* method handle for this ScriptFunction
* @see SpecializedFunction
* @return invokeHandle
*/
public final MethodHandle getInvokeHandle() {
! return invokeHandle;
}
/**
* Return the invoke handle bound to a given ScriptObject self reference.
* If callee parameter is required result is rebound to this.
--- 489,509 ----
* Return the most appropriate invoke handle if there are specializations
* @param type most specific method type to look for invocation with
* @return invoke method handle
*/
public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) {
! return candidateWithLowestWeight(type, getInvokeHandle(), data.getInvokeSpecializations());
}
/**
* Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
* method handle for this ScriptFunction
* @see SpecializedFunction
* @return invokeHandle
*/
public final MethodHandle getInvokeHandle() {
! return data.getInvoker();
}
/**
* Return the invoke handle bound to a given ScriptObject self reference.
* If callee parameter is required result is rebound to this.
*** 716,791 ****
* @param self self reference
* @return bound invoke handle
*/
public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
final MethodHandle bound = MH.bindTo(getInvokeHandle(), self);
! return hasCalleeParameter() ? MH.bindTo(bound, this) : bound;
}
- /**
- * Check whether the ScriptFunction has callee parameter
- * @return true if callee parameter
- */
- protected abstract boolean hasCalleeParameter();
-
- /**
- * Flag ScriptFunction as needing a callee parameter
- */
- protected abstract void setHasCalleeParameter();
/**
* Get the construct handle - the most generic (and if no specializations are in place, only) constructor
* method handle for this ScriptFunction
* @see SpecializedConstructor
* @param type type for wanted constructor
* @return construct handle
*/
public final MethodHandle getConstructHandle(final MethodType type) {
! return candidateWithLowestWeight(type, getConstructHandle(), constructSpecializations);
}
/**
* Get a method handle to the constructor for this function
* @return constructor handle
*/
public final MethodHandle getConstructHandle() {
! return constructHandle;
}
/**
* Set a method handle to the constructor for this function
* @param constructHandle constructor handle
*/
public final void setConstructHandle(final MethodHandle constructHandle) {
! this.constructHandle = constructHandle;
! this.constructSpecializations = null;
}
/**
* Get the name for this function
* @return the name
*/
public final String getName() {
! return name;
}
/**
* Does this script function need to be compiled. This determined by
* null checking invokeHandle
*
* @return true if this needs compilation
*/
public final boolean needsCompilation() {
! return invokeHandle == null;
}
/**
* Get token for this function
* @return token
*/
public final long getToken() {
! return token;
}
/**
* Get the scope for this function
* @return the scope
--- 511,575 ----
* @param self self reference
* @return bound invoke handle
*/
public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
final MethodHandle bound = MH.bindTo(getInvokeHandle(), self);
! return data.needsCallee() ? MH.bindTo(bound, this) : bound;
}
/**
* Get the construct handle - the most generic (and if no specializations are in place, only) constructor
* method handle for this ScriptFunction
* @see SpecializedConstructor
* @param type type for wanted constructor
* @return construct handle
*/
public final MethodHandle getConstructHandle(final MethodType type) {
! return candidateWithLowestWeight(type, getConstructHandle(), data.getConstructSpecializations());
}
/**
* Get a method handle to the constructor for this function
* @return constructor handle
*/
public final MethodHandle getConstructHandle() {
! return data.getConstructor();
}
/**
* Set a method handle to the constructor for this function
* @param constructHandle constructor handle
*/
public final void setConstructHandle(final MethodHandle constructHandle) {
! data.setConstructor(constructHandle);
}
/**
* Get the name for this function
* @return the name
*/
public final String getName() {
! return data.getName();
}
/**
* Does this script function need to be compiled. This determined by
* null checking invokeHandle
*
* @return true if this needs compilation
*/
public final boolean needsCompilation() {
! return data.getInvoker() == null;
}
/**
* Get token for this function
* @return token
*/
public final long getToken() {
! return data.getToken();
}
/**
* Get the scope for this function
* @return the scope
*** 905,915 ****
// apply new filter
final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); // drop self
MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor);
! if (hasCalleeParameter()) {
handle = MH.foldArguments(handle, ALLOCATE);
} else {
handle = MH.filterArguments(handle, 0, ALLOCATE);
}
--- 689,699 ----
// apply new filter
final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); // drop self
MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor);
! if (data.needsCallee()) {
handle = MH.foldArguments(handle, ALLOCATE);
} else {
handle = MH.filterArguments(handle, 0, ALLOCATE);
}
*** 956,971 ****
}
MethodHandle boundHandle;
MethodHandle guard = null;
! if (hasCalleeParameter()) {
final MethodHandle callHandle = getBestSpecializedInvokeHandle(type);
if(NashornCallSiteDescriptor.isScope(desc)) {
// (this, callee, args...) => (callee, args...) => (callee, [this], args...)
! boundHandle = MH.bindTo(callHandle, isNonStrictFunction() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
} else {
// (this, callee, args...) permute => (callee, this, args...) which is what we get in
final MethodType oldType = callHandle.type();
final int[] reorder = new int[oldType.parameterCount()];
--- 740,755 ----
}
MethodHandle boundHandle;
MethodHandle guard = null;
! if (data.needsCallee()) {
final MethodHandle callHandle = getBestSpecializedInvokeHandle(type);
if(NashornCallSiteDescriptor.isScope(desc)) {
// (this, callee, args...) => (callee, args...) => (callee, [this], args...)
! boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
} else {
// (this, callee, args...) permute => (callee, this, args...) which is what we get in
final MethodType oldType = callHandle.type();
final int[] reorder = new int[oldType.parameterCount()];
*** 978,988 ****
boundHandle = MethodHandles.permuteArguments(callHandle, newType, reorder);
// For non-strict functions, check whether this-object is primitive type.
// If so add a to-object-wrapper argument filter.
// Else install a guard that will trigger a relink when the argument becomes primitive.
! if (isNonStrictFunction()) {
if (isPrimitiveThis(request.getArguments()[1])) {
boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
} else {
guard = NashornGuards.getNonStrictFunctionGuard(this);
}
--- 762,772 ----
boundHandle = MethodHandles.permuteArguments(callHandle, newType, reorder);
// For non-strict functions, check whether this-object is primitive type.
// If so add a to-object-wrapper argument filter.
// Else install a guard that will trigger a relink when the argument becomes primitive.
! if (needsWrappedThis()) {
if (isPrimitiveThis(request.getArguments()[1])) {
boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
} else {
guard = NashornGuards.getNonStrictFunctionGuard(this);
}
*** 990,1000 ****
}
} else {
final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1));
if(NashornCallSiteDescriptor.isScope(desc)) {
! boundHandle = MH.bindTo(callHandle, isNonStrictFunction() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
} else {
boundHandle = MH.dropArguments(callHandle, 0, Object.class);
}
}
--- 774,784 ----
}
} else {
final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1));
if(NashornCallSiteDescriptor.isScope(desc)) {
! boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
} else {
boundHandle = MH.dropArguments(callHandle, 0, Object.class);
}
}
*** 1010,1026 ****
*/
MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
MethodHandle methodHandle = getBestSpecializedInvokeHandle(type);
if (bindName != null) {
! if (hasCalleeParameter()) {
methodHandle = MH.insertArguments(methodHandle, 1, this, bindName);
} else {
methodHandle = MH.insertArguments(methodHandle, 1, bindName);
}
} else {
! if (hasCalleeParameter()) {
methodHandle = MH.insertArguments(methodHandle, 1, this);
}
}
return pairArguments(methodHandle, type);
--- 794,810 ----
*/
MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
MethodHandle methodHandle = getBestSpecializedInvokeHandle(type);
if (bindName != null) {
! if (data.needsCallee()) {
methodHandle = MH.insertArguments(methodHandle, 1, this, bindName);
} else {
methodHandle = MH.insertArguments(methodHandle, 1, bindName);
}
} else {
! if (data.needsCallee()) {
methodHandle = MH.insertArguments(methodHandle, 1, this);
}
}
return pairArguments(methodHandle, type);
*** 1032,1042 ****
* @param thiz the this argument
*
* @return the converted this object
*/
protected Object convertThisObject(final Object thiz) {
! if (!(thiz instanceof ScriptObject) && isNonStrictFunction()) {
if (JSType.nullOrUndefined(thiz)) {
return Context.getGlobalTrusted();
}
if (isPrimitiveThis(thiz)) {
--- 816,826 ----
* @param thiz the this argument
*
* @return the converted this object
*/
protected Object convertThisObject(final Object thiz) {
! if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
if (JSType.nullOrUndefined(thiz)) {
return Context.getGlobalTrusted();
}
if (isPrimitiveThis(thiz)) {