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