ScriptFunction.java revision 1036:f0b5e3900a10
11553Srgrimes/* 21553Srgrimes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 31553Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41553Srgrimes * 51553Srgrimes * This code is free software; you can redistribute it and/or modify it 61553Srgrimes * under the terms of the GNU General Public License version 2 only, as 71553Srgrimes * published by the Free Software Foundation. Oracle designates this 81553Srgrimes * particular file as subject to the "Classpath" exception as provided 91553Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101553Srgrimes * 111553Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121553Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131553Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141553Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151553Srgrimes * accompanied this code). 161553Srgrimes * 171553Srgrimes * You should have received a copy of the GNU General Public License version 181553Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191553Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201553Srgrimes * 211553Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221553Srgrimes * or visit www.oracle.com if you need additional information or have any 231553Srgrimes * questions. 241553Srgrimes */ 251553Srgrimes 261553Srgrimespackage jdk.nashorn.internal.runtime; 271553Srgrimes 281553Srgrimesimport static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; 291553Srgrimesimport static jdk.nashorn.internal.lookup.Lookup.MH; 301553Srgrimesimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 3130642Scharnierimport static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 321553Srgrimesimport static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 3330642Scharnierimport java.lang.invoke.MethodHandle; 3430642Scharnierimport java.lang.invoke.MethodHandles; 3550479Speterimport java.lang.invoke.MethodType; 361553Srgrimesimport java.lang.invoke.SwitchPoint; 371553Srgrimesimport java.util.ArrayList; 381553Srgrimesimport java.util.Arrays; 391553Srgrimesimport java.util.Collection; 40202204Sedimport java.util.Collections; 411553Srgrimesimport java.util.HashSet; 421553Srgrimesimport java.util.List; 431553Srgrimesimport jdk.internal.dynalink.CallSiteDescriptor; 441553Srgrimesimport jdk.internal.dynalink.linker.GuardedInvocation; 451553Srgrimesimport jdk.internal.dynalink.linker.LinkRequest; 461553Srgrimesimport jdk.internal.dynalink.support.Guards; 471553Srgrimesimport jdk.nashorn.internal.codegen.ApplySpecialization; 481553Srgrimesimport jdk.nashorn.internal.codegen.Compiler; 4930872Scharnierimport jdk.nashorn.internal.codegen.CompilerConstants.Call; 501553Srgrimesimport jdk.nashorn.internal.objects.Global; 511553Srgrimesimport jdk.nashorn.internal.objects.NativeFunction; 521553Srgrimesimport jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic; 53173412Skevloimport jdk.nashorn.internal.runtime.linker.Bootstrap; 54173412Skevloimport jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 55173412Skevloimport jdk.nashorn.internal.runtime.logging.DebugLogger; 561553Srgrimes 571553Srgrimes/** 58246209Scharnier * Runtime representation of a JavaScript function. 591553Srgrimes */ 601553Srgrimespublic abstract class ScriptFunction extends ScriptObject { 611553Srgrimes 621553Srgrimes /** Method handle for prototype getter for this ScriptFunction */ 631553Srgrimes public static final MethodHandle G$PROTOTYPE = findOwnMH_S("G$prototype", Object.class, Object.class); 641553Srgrimes 651553Srgrimes /** Method handle for prototype setter for this ScriptFunction */ 661553Srgrimes public static final MethodHandle S$PROTOTYPE = findOwnMH_S("S$prototype", void.class, Object.class, Object.class); 671553Srgrimes 681553Srgrimes /** Method handle for length getter for this ScriptFunction */ 691553Srgrimes public static final MethodHandle G$LENGTH = findOwnMH_S("G$length", int.class, Object.class); 7086644Sjhb 7137267Sbde /** Method handle for name getter for this ScriptFunction */ 721553Srgrimes public static final MethodHandle G$NAME = findOwnMH_S("G$name", Object.class, Object.class); 731553Srgrimes 741553Srgrimes /** Method handle used for implementing sync() in mozilla_compat */ 751553Srgrimes public static final MethodHandle INVOKE_SYNC = findOwnMH_S("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class); 761553Srgrimes 771553Srgrimes /** Method handle for allocate function for this ScriptFunction */ 78202204Sed static final MethodHandle ALLOCATE = findOwnMH_V("allocate", Object.class); 791553Srgrimes 801553Srgrimes private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class); 811553Srgrimes 821553Srgrimes private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class); 831553Srgrimes 841553Srgrimes /** method handle to scope getter for this ScriptFunction */ 851553Srgrimes public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class); 86239991Sed 871553Srgrimes private static final MethodHandle IS_FUNCTION_MH = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class); 881553Srgrimes 891553Srgrimes private static final MethodHandle IS_APPLY_FUNCTION = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class); 901553Srgrimes 911553Srgrimes private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH_S("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class); 921553Srgrimes 931553Srgrimes private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH_S("addZerothElement", Object[].class, Object[].class, Object.class); 941553Srgrimes 951553Srgrimes private static final MethodHandle WRAP_THIS = MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, "wrapThis", MH.type(Object.class, Object.class)); 961553Srgrimes 971553Srgrimes /** The parent scope. */ 981553Srgrimes private final ScriptObject scope; 991553Srgrimes 1001553Srgrimes private final ScriptFunctionData data; 1011553Srgrimes 1021553Srgrimes /** The property map used for newly allocated object when function is used as constructor. */ 1031553Srgrimes protected PropertyMap allocatorMap; 1041553Srgrimes 1051553Srgrimes /** 106239991Sed * Constructor 1071553Srgrimes * 1081553Srgrimes * @param name function name 1091553Srgrimes * @param methodHandle method handle to function (if specializations are present, assumed to be most generic) 1101553Srgrimes * @param map property map 1111553Srgrimes * @param scope scope 1121553Srgrimes * @param specs specialized version of this function - other method handles 1131553Srgrimes * @param flags {@link ScriptFunctionData} flags 1141553Srgrimes */ 1151553Srgrimes protected ScriptFunction( 1161553Srgrimes final String name, 1171553Srgrimes final MethodHandle methodHandle, 1181553Srgrimes final PropertyMap map, 1191553Srgrimes final ScriptObject scope, 1201553Srgrimes final Specialization[] specs, 1211553Srgrimes final int flags) { 1221553Srgrimes 1231553Srgrimes this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope); 1241553Srgrimes } 1251553Srgrimes 1261553Srgrimes /** 1271553Srgrimes * Constructor 1281553Srgrimes * 1291553Srgrimes * @param data static function data 1301553Srgrimes * @param map property map 1311553Srgrimes * @param scope scope 1321553Srgrimes */ 1331553Srgrimes protected ScriptFunction( 1341553Srgrimes final ScriptFunctionData data, 135239991Sed final PropertyMap map, 1361553Srgrimes final ScriptObject scope) { 1371553Srgrimes 1381553Srgrimes super(map); 1391553Srgrimes 1401553Srgrimes if (Context.DEBUG) { 1411553Srgrimes constructorCount++; 1421553Srgrimes } 1431553Srgrimes 1441553Srgrimes this.data = data; 1451553Srgrimes this.scope = scope; 1461553Srgrimes this.allocatorMap = data.getAllocatorMap(); 14730830Scharnier } 1481553Srgrimes 1491553Srgrimes @Override 1501553Srgrimes public String getClassName() { 1511553Srgrimes return "Function"; 1521553Srgrimes } 1531553Srgrimes 1541553Srgrimes /** 1551553Srgrimes * ECMA 15.3.5.3 [[HasInstance]] (V) 156239991Sed * Step 3 if "prototype" value is not an Object, throw TypeError 1571553Srgrimes */ 1581553Srgrimes @Override 1591553Srgrimes public boolean isInstance(final ScriptObject instance) { 1601553Srgrimes final Object basePrototype = getTargetFunction().getPrototype(); 1611553Srgrimes if (!(basePrototype instanceof ScriptObject)) { 1621553Srgrimes throw typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype)); 1631553Srgrimes } 1641553Srgrimes 1651553Srgrimes for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) { 1661553Srgrimes if (proto == basePrototype) { 1671553Srgrimes return true; 1681553Srgrimes } 1691553Srgrimes } 1701553Srgrimes 1711553Srgrimes return false; 1721553Srgrimes } 1731553Srgrimes 1741553Srgrimes /** 1751553Srgrimes * Returns the target function for this function. If the function was not created using 1761553Srgrimes * {@link #makeBoundFunction(Object, Object[])}, its target function is itself. If it is bound, its target function 1771553Srgrimes * is the target function of the function it was made from (therefore, the target function is always the final, 1781553Srgrimes * unbound recipient of the calls). 1791553Srgrimes * @return the target function for this function. 1801553Srgrimes */ 1811553Srgrimes protected ScriptFunction getTargetFunction() { 1821553Srgrimes return this; 1831553Srgrimes } 1841553Srgrimes 1851553Srgrimes boolean isBoundFunction() { 1861553Srgrimes return getTargetFunction() != this; 1871553Srgrimes } 1881553Srgrimes 1891553Srgrimes /** 1901553Srgrimes * Set the arity of this ScriptFunction 1911553Srgrimes * @param arity arity 1921553Srgrimes */ 1931553Srgrimes public final void setArity(final int arity) { 1941553Srgrimes data.setArity(arity); 1951553Srgrimes } 1961553Srgrimes 1971553Srgrimes /** 1981553Srgrimes * Is this a ECMAScript 'use strict' function? 1991553Srgrimes * @return true if function is in strict mode 2001553Srgrimes */ 2011553Srgrimes public boolean isStrict() { 2021553Srgrimes return data.isStrict(); 2031553Srgrimes } 2041553Srgrimes 2051553Srgrimes /** 2061553Srgrimes * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument 2071553Srgrimes * according to ECMA 10.4.3. 2081553Srgrimes * @return true if this argument must be an object 2091553Srgrimes */ 2101553Srgrimes public boolean needsWrappedThis() { 2111553Srgrimes return data.needsWrappedThis(); 2121553Srgrimes } 2131553Srgrimes 2141553Srgrimes private static boolean needsWrappedThis(final Object fn) { 2151553Srgrimes return fn instanceof ScriptFunction ? ((ScriptFunction)fn).needsWrappedThis() : false; 2161553Srgrimes } 2171553Srgrimes 2181553Srgrimes /** 2191553Srgrimes * Execute this script function. 2201553Srgrimes * @param self Target object. 2211553Srgrimes * @param arguments Call arguments. 2221553Srgrimes * @return ScriptFunction result. 2231553Srgrimes * @throws Throwable if there is an exception/error with the invocation or thrown from it 2241553Srgrimes */ 2251553Srgrimes Object invoke(final Object self, final Object... arguments) throws Throwable { 2261553Srgrimes if (Context.DEBUG) { 2271553Srgrimes invokes++; 228239991Sed } 2291553Srgrimes return data.invoke(this, self, arguments); 2301553Srgrimes } 2311553Srgrimes 2321553Srgrimes /** 2331553Srgrimes * Execute this script function as a constructor. 2341553Srgrimes * @param arguments Call arguments. 2351553Srgrimes * @return Newly constructed result. 2361553Srgrimes * @throws Throwable if there is an exception/error with the invocation or thrown from it 237239991Sed */ 2381553Srgrimes Object construct(final Object... arguments) throws Throwable { 2391553Srgrimes return data.construct(this, arguments); 2401553Srgrimes } 2411553Srgrimes 2421553Srgrimes /** 2431553Srgrimes * Allocate function. Called from generated {@link ScriptObject} code 2441553Srgrimes * for allocation as a factory method 2451553Srgrimes * 2461553Srgrimes * @return a new instance of the {@link ScriptObject} whose allocator this is 2471553Srgrimes */ 2481553Srgrimes @SuppressWarnings("unused") 2491553Srgrimes private Object allocate() { 2501553Srgrimes if (Context.DEBUG) { 251239991Sed allocations++; 2521553Srgrimes } 2531553Srgrimes 2541553Srgrimes assert !isBoundFunction(); // allocate never invoked on bound functions 2551553Srgrimes 2561553Srgrimes final ScriptObject object = data.allocate(allocatorMap); 25730830Scharnier 25837267Sbde if (object != null) { 25937267Sbde final Object prototype = getPrototype(); 2601553Srgrimes if (prototype instanceof ScriptObject) { 2611553Srgrimes object.setInitialProto((ScriptObject)prototype); 2621553Srgrimes } 2631553Srgrimes 2641553Srgrimes if (object.getProto() == null) { 2651553Srgrimes object.setInitialProto(getObjectPrototype()); 2661553Srgrimes } 2671553Srgrimes } 2681553Srgrimes 2691553Srgrimes return object; 27086644Sjhb } 27186644Sjhb 27286644Sjhb /** 2731553Srgrimes * Return Object.prototype - used by "allocate" 2741553Srgrimes * @return Object.prototype 2751553Srgrimes */ 2761553Srgrimes protected abstract ScriptObject getObjectPrototype(); 2771553Srgrimes 2781553Srgrimes /** 279202204Sed * Creates a version of this function bound to a specific "self" and other arguments, as per 280202204Sed * {@code Function.prototype.bind} functionality in ECMAScript 5.1 section 15.3.4.5. 281202204Sed * @param self the self to bind to this function. Can be null (in which case, null is bound as this). 282202204Sed * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. 283202204Sed * @return a function with the specified self and parameters bound. 284202204Sed */ 285202204Sed protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) { 2861553Srgrimes return makeBoundFunction(data.makeBoundFunctionData(this, self, args)); 2871553Srgrimes } 2881553Srgrimes 2891553Srgrimes /** 2901553Srgrimes * Create a version of this function as in {@link ScriptFunction#makeBoundFunction(Object, Object[])}, 2911553Srgrimes * but using a {@link ScriptFunctionData} for the bound data. 292239991Sed * 2931553Srgrimes * @param boundData ScriptFuntionData for the bound function 2941553Srgrimes * @return a function with the bindings performed according to the given data 2951553Srgrimes */ 2961553Srgrimes protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData); 2971553Srgrimes 2981553Srgrimes @Override 2991553Srgrimes public final String safeToString() { 3001553Srgrimes return toSource(); 3011553Srgrimes } 3021553Srgrimes 3031553Srgrimes @Override 3041553Srgrimes public String toString() { 3051553Srgrimes return data.toString(); 3061553Srgrimes } 3071553Srgrimes 3081553Srgrimes /** 3091553Srgrimes * Get this function as a String containing its source code. If no source code 3101553Srgrimes * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} 3111553Srgrimes * @return string representation of this function's source 3121553Srgrimes */ 3131553Srgrimes public final String toSource() { 3141553Srgrimes return data.toSource(); 3151553Srgrimes } 3161553Srgrimes 3171553Srgrimes /** 3181553Srgrimes * Get the prototype object for this function 3191553Srgrimes * @return prototype 3201553Srgrimes */ 3211553Srgrimes public abstract Object getPrototype(); 3221553Srgrimes 3231553Srgrimes /** 3241553Srgrimes * Set the prototype object for this function 3251553Srgrimes * @param prototype new prototype object 3261553Srgrimes */ 3271553Srgrimes public abstract void setPrototype(Object prototype); 3281553Srgrimes 3291553Srgrimes /** 330239991Sed * Create a function that invokes this function synchronized on {@code sync} or the self object 3311553Srgrimes * of the invocation. 3321553Srgrimes * @param sync the Object to synchronize on, or undefined 3331553Srgrimes * @return synchronized function 3341553Srgrimes */ 3351553Srgrimes public abstract ScriptFunction makeSynchronizedFunction(Object sync); 3361553Srgrimes 3371553Srgrimes /** 3381553Srgrimes * Return the invoke handle bound to a given ScriptObject self reference. 339239991Sed * If callee parameter is required result is rebound to this. 3401553Srgrimes * 3411553Srgrimes * @param self self reference 3421553Srgrimes * @return bound invoke handle 3431553Srgrimes */ 34437267Sbde public final MethodHandle getBoundInvokeHandle(final Object self) { 34537267Sbde return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), self); 3461553Srgrimes } 3471553Srgrimes 3481553Srgrimes /** 3491553Srgrimes * Bind the method handle to this {@code ScriptFunction} instance if it needs a callee parameter. If this function's 3501553Srgrimes * method handles don't have a callee parameter, the handle is returned unchanged. 3511553Srgrimes * @param methodHandle the method handle to potentially bind to this function instance. 35237267Sbde * @return the potentially bound method handle 35337267Sbde */ 3541553Srgrimes private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) { 3551553Srgrimes return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle; 3561553Srgrimes 3571553Srgrimes } 3581553Srgrimes 3591553Srgrimes /** 3601553Srgrimes * Get the name for this function 3611553Srgrimes * @return the name 3621553Srgrimes */ 3631553Srgrimes public final String getName() { 3641553Srgrimes return data.getName(); 3651553Srgrimes } 3661553Srgrimes 3671553Srgrimes 3681553Srgrimes /** 3691553Srgrimes * Get the scope for this function 3701553Srgrimes * @return the scope 3711553Srgrimes */ 3721553Srgrimes public final ScriptObject getScope() { 3731553Srgrimes return scope; 3741553Srgrimes } 3751553Srgrimes 3761553Srgrimes /** 3771553Srgrimes * Prototype getter for this ScriptFunction - follows the naming convention 3781553Srgrimes * used by Nasgen and the code generator 3791553Srgrimes * 3801553Srgrimes * @param self self reference 3811553Srgrimes * @return self's prototype 3821553Srgrimes */ 3831553Srgrimes public static Object G$prototype(final Object self) { 384239991Sed return self instanceof ScriptFunction ? 3851553Srgrimes ((ScriptFunction)self).getPrototype() : 3861553Srgrimes UNDEFINED; 3871553Srgrimes } 3881553Srgrimes 3891553Srgrimes /** 3901553Srgrimes * Prototype setter for this ScriptFunction - follows the naming convention 3911553Srgrimes * used by Nasgen and the code generator 3921553Srgrimes * 3931553Srgrimes * @param self self reference 3941553Srgrimes * @param prototype prototype to set 3951553Srgrimes */ 3961553Srgrimes public static void S$prototype(final Object self, final Object prototype) { 3971553Srgrimes if (self instanceof ScriptFunction) { 3981553Srgrimes ((ScriptFunction)self).setPrototype(prototype); 3991553Srgrimes } 4001553Srgrimes } 4011553Srgrimes 4021553Srgrimes /** 4031553Srgrimes * Length getter - ECMA 15.3.3.2: Function.length 4041553Srgrimes * @param self self reference 4051553Srgrimes * @return length 40630830Scharnier */ 40730830Scharnier public static int G$length(final Object self) { 4081553Srgrimes if (self instanceof ScriptFunction) { 4091553Srgrimes return ((ScriptFunction)self).data.getArity(); 4101553Srgrimes } 4111553Srgrimes 4121553Srgrimes return 0; 4131553Srgrimes } 4141553Srgrimes 4151553Srgrimes /** 4161553Srgrimes * Name getter - ECMA Function.name 4171553Srgrimes * @param self self refence 41830830Scharnier * @return the name, or undefined if none 4191553Srgrimes */ 4201553Srgrimes public static Object G$name(final Object self) { 4211553Srgrimes if (self instanceof ScriptFunction) { 4221553Srgrimes return ((ScriptFunction)self).getName(); 4231553Srgrimes } 4241553Srgrimes 4251553Srgrimes return UNDEFINED; 4261553Srgrimes } 4271553Srgrimes 4281553Srgrimes /** 4291553Srgrimes * Get the prototype for this ScriptFunction 4301553Srgrimes * @param constructor constructor 4311553Srgrimes * @return prototype, or null if given constructor is not a ScriptFunction 4321553Srgrimes */ 4331553Srgrimes public static ScriptObject getPrototype(final ScriptFunction constructor) { 4341553Srgrimes if (constructor != null) { 4351553Srgrimes final Object proto = constructor.getPrototype(); 4361553Srgrimes if (proto instanceof ScriptObject) { 43730830Scharnier return (ScriptObject)proto; 4381553Srgrimes } 4391553Srgrimes } 4401553Srgrimes 4411553Srgrimes return null; 4421553Srgrimes } 4431553Srgrimes 4441553Srgrimes // These counters are updated only in debug mode. 4451553Srgrimes private static int constructorCount; 4461553Srgrimes private static int invokes; 4471553Srgrimes private static int allocations; 4481553Srgrimes 4491553Srgrimes /** 4501553Srgrimes * @return the constructorCount 4511553Srgrimes */ 4521553Srgrimes public static int getConstructorCount() { 4531553Srgrimes return constructorCount; 4541553Srgrimes } 4551553Srgrimes 4561553Srgrimes /** 4571553Srgrimes * @return the invokes 4581553Srgrimes */ 4591553Srgrimes public static int getInvokes() { 4601553Srgrimes return invokes; 4611553Srgrimes } 4621553Srgrimes 4631553Srgrimes /** 4641553Srgrimes * @return the allocations 4651553Srgrimes */ 4661553Srgrimes public static int getAllocations() { 4671553Srgrimes return allocations; 4681553Srgrimes } 4691553Srgrimes 4701553Srgrimes @Override 47130830Scharnier protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) { 4721553Srgrimes final MethodType type = desc.getMethodType(); 4731553Srgrimes assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc); 4741553Srgrimes final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS); 4751553Srgrimes final GuardedInvocation bestCtorInv = cf.createConstructorInvocation(); 4761553Srgrimes //TODO - ClassCastException 4771553Srgrimes return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null); 4781553Srgrimes } 47930830Scharnier 4801553Srgrimes private static Object wrapFilter(final Object obj) { 4811553Srgrimes if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) { 4821553Srgrimes return obj; 48330642Scharnier } 48430830Scharnier return Context.getGlobal().wrapAsObject(obj); 4851553Srgrimes } 4861553Srgrimes 4871553Srgrimes 4881553Srgrimes @SuppressWarnings("unused") 4891553Srgrimes private static Object globalFilter(final Object object) { 4901553Srgrimes // replace whatever we get with the current global object 4911553Srgrimes return Context.getGlobal(); 4921553Srgrimes } 4931553Srgrimes 4941553Srgrimes /** 4951553Srgrimes * Some receivers are primitive, in that case, according to the Spec we create a new 4961553Srgrimes * native object per callsite with the wrap filter. We can only apply optimistic builtins 4971553Srgrimes * if there is no per instance state saved for these wrapped objects (e.g. currently NativeStrings), 4981553Srgrimes * otherwise we can't create optimistic versions 4991553Srgrimes * 5001553Srgrimes * @param self receiver 5011553Srgrimes * @param linkLogicClass linkLogicClass, or null if no link logic exists 5021553Srgrimes * @return link logic instance, or null if one could not be constructed for this receiver 5031553Srgrimes */ 5041553Srgrimes private LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) { 5051553Srgrimes if (linkLogicClass == null) { 5061553Srgrimes return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic 5071553Srgrimes } 5081553Srgrimes 5091553Srgrimes if (!Context.getContextTrusted().getEnv()._optimistic_types) { 5101553Srgrimes return null; //if optimistic types are off, optimistic builtins are too 5111553Srgrimes } 5121553Srgrimes 5131553Srgrimes final Object wrappedSelf = wrapFilter(self); 5141553Srgrimes if (wrappedSelf instanceof OptimisticBuiltins) { 5151553Srgrimes if (wrappedSelf != self && ((OptimisticBuiltins)wrappedSelf).hasPerInstanceAssumptions()) { 5161553Srgrimes return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state 5171553Srgrimes } 5181553Srgrimes return ((OptimisticBuiltins)wrappedSelf).getLinkLogic(linkLogicClass); 5191553Srgrimes } 5201553Srgrimes return null; 5211553Srgrimes } 5221553Srgrimes 5231553Srgrimes /** 5241553Srgrimes * dyn:call call site signature: (callee, thiz, [args...]) 5251553Srgrimes * generated method signature: (callee, thiz, [args...]) 5261553Srgrimes * 5271553Srgrimes * cases: 5281553Srgrimes * (a) method has callee parameter 52930830Scharnier * (1) for local/scope calls, we just bind thiz and drop the second argument. 5301553Srgrimes * (2) for normal this-calls, we have to swap thiz and callee to get matching signatures. 53130830Scharnier * (b) method doesn't have callee parameter (builtin functions) 5321553Srgrimes * (3) for local/scope calls, bind thiz and drop both callee and thiz. 5331553Srgrimes * (4) for normal this-calls, drop callee. 5341553Srgrimes * 5351553Srgrimes * @return guarded invocation for call 5361553Srgrimes */ 5371553Srgrimes @Override 5381553Srgrimes protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) { 5391553Srgrimes final MethodType type = desc.getMethodType(); 5401553Srgrimes 541239991Sed final String name = getName(); 5421553Srgrimes final boolean isUnstable = request.isCallSiteUnstable(); 5431553Srgrimes final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc); 5441553Srgrimes final boolean isCall = !scopeCall && data.isBuiltin() && "call".equals(name); 5451553Srgrimes final boolean isApply = !scopeCall && data.isBuiltin() && "apply".equals(name); 5461553Srgrimes 5471553Srgrimes final boolean isApplyOrCall = isCall | isApply; 5481553Srgrimes 5491553Srgrimes if (isUnstable && !isApplyOrCall) { 5501553Srgrimes //megamorphic - replace call with apply 5511553Srgrimes final MethodHandle handle; 5521553Srgrimes //ensure that the callsite is vararg so apply can consume it 5531553Srgrimes if (type.parameterCount() == 3 && type.parameterType(2) == Object[].class) { 5541553Srgrimes // Vararg call site 5551553Srgrimes handle = ScriptRuntime.APPLY.methodHandle(); 5561553Srgrimes } else { 5571553Srgrimes // (callee, this, args...) => (callee, this, args[]) 5581553Srgrimes handle = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2); 5591553Srgrimes } 5601553Srgrimes 5611553Srgrimes // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a 5621553Srgrimes // generic "is this a ScriptFunction?" guard. 5631553Srgrimes return new GuardedInvocation( 5641553Srgrimes handle, 5651553Srgrimes null, 5661553Srgrimes (SwitchPoint)null, 5671553Srgrimes ClassCastException.class); 5681553Srgrimes } 5691553Srgrimes 5701553Srgrimes MethodHandle boundHandle; 5711553Srgrimes MethodHandle guard = null; 5721553Srgrimes 5731553Srgrimes // Special handling of Function.apply and Function.call. Note we must be invoking 5741553Srgrimes if (isApplyOrCall && !isUnstable) { 5751553Srgrimes final Object[] args = request.getArguments(); 5761553Srgrimes if (Bootstrap.isCallable(args[1])) { 5771553Srgrimes return createApplyOrCallCall(isApply, desc, request, args); 5781553Srgrimes } 5791553Srgrimes } //else just fall through and link as ordinary function or unstable apply 5801553Srgrimes 5811553Srgrimes int programPoint = INVALID_PROGRAM_POINT; 5821553Srgrimes if (NashornCallSiteDescriptor.isOptimistic(desc)) { 5831553Srgrimes programPoint = NashornCallSiteDescriptor.getProgramPoint(desc); 58430830Scharnier } 5851553Srgrimes 5861553Srgrimes CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS); 5871553Srgrimes final Object self = request.getArguments()[1]; 5881553Srgrimes final Collection<CompiledFunction> forbidden = new HashSet<>(); 5891553Srgrimes 5901553Srgrimes //check for special fast versions of the compiled function 5911553Srgrimes final List<SwitchPoint> sps = new ArrayList<>(); 5921553Srgrimes Class<? extends Throwable> exceptionGuard = null; 593239991Sed 5941553Srgrimes while (cf.isSpecialization()) { 5951553Srgrimes final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass(); 5961553Srgrimes //if linklogic is null, we can always link with the standard mechanism, it's still a specialization 5971553Srgrimes final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass); 5981553Srgrimes 5991553Srgrimes if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) { 6001553Srgrimes final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class); 6011553Srgrimes 6021553Srgrimes if (log.isEnabled()) { 6031553Srgrimes log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc); 6041553Srgrimes } 6051553Srgrimes 6061553Srgrimes final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints(); 6071553Srgrimes if (msps != null) { 6081553Srgrimes for (final SwitchPoint sp : msps) { 6091553Srgrimes if (sp != null) { 6101553Srgrimes assert !sp.hasBeenInvalidated(); 6111553Srgrimes sps.add(sp); 6121553Srgrimes } 613246209Scharnier } 6141553Srgrimes } 6151553Srgrimes 6161553Srgrimes exceptionGuard = linkLogic.getRelinkException(); 6171553Srgrimes 6181553Srgrimes break; 61930830Scharnier } 6201553Srgrimes 6211553Srgrimes //could not link this specialization because link check failed 6221553Srgrimes forbidden.add(cf); 6231553Srgrimes final CompiledFunction oldCf = cf; 6241553Srgrimes cf = data.getBestInvoker(type, scope, forbidden); 6251553Srgrimes assert oldCf != cf; 6261553Srgrimes } 6271553Srgrimes 6281553Srgrimes final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint); 6291553Srgrimes final MethodHandle callHandle = bestInvoker.getInvocation(); 6301553Srgrimes 6311553Srgrimes if (data.needsCallee()) { 6321553Srgrimes if (scopeCall && needsWrappedThis()) { 6331553Srgrimes // (callee, this, args...) => (callee, [this], args...) 6341553Srgrimes boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER); 6351553Srgrimes } else { 6361553Srgrimes // It's already (callee, this, args...), just what we need 6371553Srgrimes boundHandle = callHandle; 6381553Srgrimes } 6391553Srgrimes } else if (data.isBuiltin() && "extend".equals(data.getName())) { 6401553Srgrimes // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the 6411553Srgrimes // current lookup as its "this" so it can do security-sensitive creation of adapter classes. 642246209Scharnier boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, type.parameterType(0), type.parameterType(1)); 6431553Srgrimes } else if (scopeCall && needsWrappedThis()) { 6441553Srgrimes // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined 6451553Srgrimes // (this, args...) => ([this], args...) 6461553Srgrimes boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER); 6471553Srgrimes // ([this], args...) => ([callee], [this], args...) 6481553Srgrimes boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0)); 6491553Srgrimes } else { 6501553Srgrimes // (this, args...) => ([callee], this, args...) 6511553Srgrimes boundHandle = MH.dropArguments(callHandle, 0, type.parameterType(0)); 6521553Srgrimes } 6531553Srgrimes 6541553Srgrimes // For non-strict functions, check whether this-object is primitive type. 6551553Srgrimes // If so add a to-object-wrapper argument filter. 6561553Srgrimes // Else install a guard that will trigger a relink when the argument becomes primitive. 6571553Srgrimes if (!scopeCall && needsWrappedThis()) { 6581553Srgrimes if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { 6591553Srgrimes boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); 660239991Sed } else { 6611553Srgrimes guard = getNonStrictFunctionGuard(this); 6621553Srgrimes } 6631553Srgrimes } 6641553Srgrimes 66530830Scharnier boundHandle = pairArguments(boundHandle, type); 6661553Srgrimes 6671553Srgrimes if (bestInvoker.getSwitchPoints() != null) { 6681553Srgrimes sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints())); 6691553Srgrimes } 6701553Srgrimes final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]); 6711553Srgrimes 6721553Srgrimes return new GuardedInvocation( 6731553Srgrimes boundHandle, 6741553Srgrimes guard == null ? 6751553Srgrimes getFunctionGuard( 6761553Srgrimes this, 6771553Srgrimes cf.getFlags()) : 6781553Srgrimes guard, 6791553Srgrimes spsArray, 680246209Scharnier exceptionGuard); 6811553Srgrimes } 6821553Srgrimes 6831553Srgrimes private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) { 6841553Srgrimes final MethodType descType = desc.getMethodType(); 6851553Srgrimes final int paramCount = descType.parameterCount(); 6861553Srgrimes if(descType.parameterType(paramCount - 1).isArray()) { 6871553Srgrimes // This is vararg invocation of apply or call. This can normally only happen when we do a recursive 6881553Srgrimes // invocation of createApplyOrCallCall (because we're doing apply-of-apply). In this case, create delegate 6891553Srgrimes // linkage by unpacking the vararg invocation and use pairArguments to introduce the necessary spreader. 6901553Srgrimes return createVarArgApplyOrCallCall(isApply, desc, request, args); 691 } 692 693 final boolean passesThis = paramCount > 2; 694 final boolean passesArgs = paramCount > 3; 695 final int realArgCount = passesArgs ? paramCount - 3 : 0; 696 697 final Object appliedFn = args[1]; 698 final boolean appliedFnNeedsWrappedThis = needsWrappedThis(appliedFn); 699 700 //box call back to apply 701 CallSiteDescriptor appliedDesc = desc; 702 final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint(); 703 //enough to change the proto switchPoint here 704 705 final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc); 706 final boolean isFailedApplyToCall = isApplyToCall && applyToCallSwitchPoint.hasBeenInvalidated(); 707 708 // R(apply|call, ...) => R(...) 709 MethodType appliedType = descType.dropParameterTypes(0, 1); 710 if (!passesThis) { 711 // R() => R(this) 712 appliedType = appliedType.insertParameterTypes(1, Object.class); 713 } else if (appliedFnNeedsWrappedThis) { 714 appliedType = appliedType.changeParameterType(1, Object.class); 715 } 716 717 /* 718 * dropArgs is a synthetic method handle that contains any args that we need to 719 * get rid of that come after the arguments array in the apply case. We adapt 720 * the callsite to ask for 3 args only and then dropArguments on the method handle 721 * to make it fit the extraneous args. 722 */ 723 MethodType dropArgs = MH.type(void.class); 724 if (isApply && !isFailedApplyToCall) { 725 final int pc = appliedType.parameterCount(); 726 for (int i = 3; i < pc; i++) { 727 dropArgs = dropArgs.appendParameterTypes(appliedType.parameterType(i)); 728 } 729 if (pc > 3) { 730 appliedType = appliedType.dropParameterTypes(3, pc); 731 } 732 } 733 734 if (isApply || isFailedApplyToCall) { 735 if (passesArgs) { 736 // R(this, args) => R(this, Object[]) 737 appliedType = appliedType.changeParameterType(2, Object[].class); 738 // drop any extraneous arguments for the apply fail case 739 if (isFailedApplyToCall) { 740 appliedType = appliedType.dropParameterTypes(3, paramCount - 1); 741 } 742 } else { 743 // R(this) => R(this, Object[]) 744 appliedType = appliedType.insertParameterTypes(2, Object[].class); 745 } 746 } 747 748 appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args 749 750 // Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation 751 final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()]; 752 appliedArgs[0] = appliedFn; 753 appliedArgs[1] = passesThis ? appliedFnNeedsWrappedThis ? ScriptFunctionData.wrapThis(args[2]) : args[2] : ScriptRuntime.UNDEFINED; 754 if (isApply && !isFailedApplyToCall) { 755 appliedArgs[2] = passesArgs ? NativeFunction.toApplyArgs(args[3]) : ScriptRuntime.EMPTY_ARRAY; 756 } else { 757 if (passesArgs) { 758 if (isFailedApplyToCall) { 759 final Object[] tmp = new Object[args.length - 3]; 760 System.arraycopy(args, 3, tmp, 0, tmp.length); 761 appliedArgs[2] = NativeFunction.toApplyArgs(tmp); 762 } else { 763 assert !isApply; 764 System.arraycopy(args, 3, appliedArgs, 2, args.length - 3); 765 } 766 } else if (isFailedApplyToCall) { 767 appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY; 768 } 769 } 770 771 // Ask the linker machinery for an invocation of the target function 772 final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs); 773 774 GuardedInvocation appliedInvocation; 775 try { 776 appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest); 777 } catch (final RuntimeException | Error e) { 778 throw e; 779 } catch (final Exception e) { 780 throw new RuntimeException(e); 781 } 782 assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage. 783 784 final Class<?> applyFnType = descType.parameterType(0); 785 MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation 786 787 if (isApply && !isFailedApplyToCall) { 788 if (passesArgs) { 789 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it. 790 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS); 791 } else { 792 // If the original call site doesn't pass argArray, pass in an empty array 793 inv = MH.insertArguments(inv, 2, (Object)ScriptRuntime.EMPTY_ARRAY); 794 } 795 } 796 797 if (isApplyToCall) { 798 if (isFailedApplyToCall) { 799 //take the real arguments that were passed to a call and force them into the apply instead 800 Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn); 801 inv = MH.asCollector(inv, Object[].class, realArgCount); 802 } else { 803 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint); 804 } 805 } 806 807 if (!passesThis) { 808 // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed 809 inv = bindImplicitThis(appliedFn, inv); 810 } else if (appliedFnNeedsWrappedThis) { 811 // target function needs a wrapped this, so make sure we filter for that 812 inv = MH.filterArguments(inv, 1, WRAP_THIS); 813 } 814 inv = MH.dropArguments(inv, 0, applyFnType); 815 816 /* 817 * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which 818 * is when we need to add arguments to the callsite to catch and ignore the synthetic 819 * extra args that someone has added to the command line. 820 */ 821 for (int i = 0; i < dropArgs.parameterCount(); i++) { 822 inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i)); 823 } 824 825 MethodHandle guard = appliedInvocation.getGuard(); 826 // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one 827 if (!passesThis && guard.type().parameterCount() > 1) { 828 guard = bindImplicitThis(appliedFn, guard); 829 } 830 final MethodType guardType = guard.type(); 831 832 // We need to account for the dropped (apply|call) function argument. 833 guard = MH.dropArguments(guard, 0, descType.parameterType(0)); 834 // Take the "isApplyFunction" guard, and bind it to this function. 835 MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint 836 // Adapt the guard to receive all the arguments that the original guard does. 837 applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray()); 838 // Fold the original function guard into our apply guard. 839 guard = MH.foldArguments(applyFnGuard, guard); 840 841 return appliedInvocation.replaceMethods(inv, guard); 842 } 843 844 /* 845 * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity 846 * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with 847 * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method. 848 * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back 849 * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to 850 * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity 851 * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already 852 * solved by createApplyOrCallCall) non-vararg call site linking. 853 */ 854 private GuardedInvocation createVarArgApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, 855 final LinkRequest request, final Object[] args) { 856 final MethodType descType = desc.getMethodType(); 857 final int paramCount = descType.parameterCount(); 858 final Object[] varArgs = (Object[])args[paramCount - 1]; 859 // -1 'cause we're not passing the vararg array itself 860 final int copiedArgCount = args.length - 1; 861 final int varArgCount = varArgs.length; 862 863 // Spread arguments for the delegate createApplyOrCallCall invocation. 864 final Object[] spreadArgs = new Object[copiedArgCount + varArgCount]; 865 System.arraycopy(args, 0, spreadArgs, 0, copiedArgCount); 866 System.arraycopy(varArgs, 0, spreadArgs, copiedArgCount, varArgCount); 867 868 // Spread call site descriptor for the delegate createApplyOrCallCall invocation. We drop vararg array and 869 // replace it with a list of Object.class. 870 final MethodType spreadType = descType.dropParameterTypes(paramCount - 1, paramCount).appendParameterTypes( 871 Collections.<Class<?>>nCopies(varArgCount, Object.class)); 872 final CallSiteDescriptor spreadDesc = desc.changeMethodType(spreadType); 873 874 // Delegate back to createApplyOrCallCall with the spread (that is, reverted to non-vararg) request/ 875 final LinkRequest spreadRequest = request.replaceArguments(spreadDesc, spreadArgs); 876 final GuardedInvocation spreadInvocation = createApplyOrCallCall(isApply, spreadDesc, spreadRequest, spreadArgs); 877 878 // Add spreader combinators to returned invocation and guard. 879 return spreadInvocation.replaceMethods( 880 // Use standard ScriptObject.pairArguments on the invocation 881 pairArguments(spreadInvocation.getInvocation(), descType), 882 // Use our specialized spreadGuardArguments on the guard (see below). 883 spreadGuardArguments(spreadInvocation.getGuard(), descType)); 884 } 885 886 private static MethodHandle spreadGuardArguments(final MethodHandle guard, final MethodType descType) { 887 final MethodType guardType = guard.type(); 888 final int guardParamCount = guardType.parameterCount(); 889 final int descParamCount = descType.parameterCount(); 890 final int spreadCount = guardParamCount - descParamCount + 1; 891 if (spreadCount <= 0) { 892 // Guard doesn't dip into the varargs 893 return guard; 894 } 895 896 final MethodHandle arrayConvertingGuard; 897 // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply 898 // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail 899 // with ClassCastException of NativeArray to Object[]. 900 if(guardType.parameterType(guardParamCount - 1).isArray()) { 901 arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS); 902 } else { 903 arrayConvertingGuard = guard; 904 } 905 906 return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount); 907 } 908 909 private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) { 910 final MethodHandle bound; 911 if(fn instanceof ScriptFunction && ((ScriptFunction)fn).needsWrappedThis()) { 912 bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER); 913 } else { 914 bound = mh; 915 } 916 return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED); 917 } 918 919 /** 920 * Used for noSuchMethod/noSuchProperty and JSAdapter hooks. 921 * 922 * These don't want a callee parameter, so bind that. Name binding is optional. 923 */ 924 MethodHandle getCallMethodHandle(final MethodType type, final String bindName) { 925 return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type); 926 } 927 928 private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) { 929 if (bindName == null) { 930 return methodHandle; 931 } 932 933 // if it is vararg method, we need to extend argument array with 934 // a new zeroth element that is set to bindName value. 935 final MethodType methodType = methodHandle.type(); 936 final int parameterCount = methodType.parameterCount(); 937 final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); 938 939 if (isVarArg) { 940 return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName)); 941 } 942 return MH.insertArguments(methodHandle, 1, bindName); 943 } 944 945 /** 946 * Get the guard that checks if a {@link ScriptFunction} is equal to 947 * a known ScriptFunction, using reference comparison 948 * 949 * @param function The ScriptFunction to check against. This will be bound to the guard method handle 950 * 951 * @return method handle for guard 952 */ 953 private static MethodHandle getFunctionGuard(final ScriptFunction function, final int flags) { 954 assert function.data != null; 955 // Built-in functions have a 1-1 correspondence to their ScriptFunctionData, so we can use a cheaper identity 956 // comparison for them. 957 if (function.data.isBuiltin()) { 958 return Guards.getIdentityGuard(function); 959 } 960 return MH.insertArguments(IS_FUNCTION_MH, 1, function.data); 961 } 962 963 /** 964 * Get a guard that checks if a {@link ScriptFunction} is equal to 965 * a known ScriptFunction using reference comparison, and whether the type of 966 * the second argument (this-object) is not a JavaScript primitive type. 967 * 968 * @param function The ScriptFunction to check against. This will be bound to the guard method handle 969 * 970 * @return method handle for guard 971 */ 972 private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) { 973 assert function.data != null; 974 return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data); 975 } 976 977 @SuppressWarnings("unused") 978 private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) { 979 return self instanceof ScriptFunction && ((ScriptFunction)self).data == data; 980 } 981 982 @SuppressWarnings("unused") 983 private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) { 984 return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject; 985 } 986 987 //TODO this can probably be removed given that we have builtin switchpoints in the context 988 @SuppressWarnings("unused") 989 private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) { 990 // NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call() 991 return appliedFnCondition && self == expectedSelf; 992 } 993 994 @SuppressWarnings("unused") 995 private static Object[] addZerothElement(final Object[] args, final Object value) { 996 // extends input array with by adding new zeroth element 997 final Object[] src = args == null? ScriptRuntime.EMPTY_ARRAY : args; 998 final Object[] result = new Object[src.length + 1]; 999 System.arraycopy(src, 0, result, 1, src.length); 1000 result[0] = value; 1001 return result; 1002 } 1003 1004 @SuppressWarnings("unused") 1005 private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args) 1006 throws Throwable { 1007 final Object syncObj = sync == UNDEFINED ? self : sync; 1008 synchronized (syncObj) { 1009 return func.invoke(self, args); 1010 } 1011 } 1012 1013 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) { 1014 return MH.findStatic(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types)); 1015 } 1016 1017 private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) { 1018 return MH.findVirtual(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types)); 1019 } 1020} 1021 1022