1/*
2 * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package jdk.nashorn.internal.runtime;
26
27import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
28import static jdk.nashorn.internal.lookup.Lookup.MH;
29import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
31import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
32
33import java.lang.invoke.MethodHandle;
34import java.lang.invoke.MethodHandles;
35import java.lang.invoke.MethodHandles.Lookup;
36import java.lang.invoke.MethodType;
37import java.lang.invoke.SwitchPoint;
38import java.security.AccessControlContext;
39import java.security.AccessController;
40import java.security.PrivilegedAction;
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.Collection;
44import java.util.Collections;
45import java.util.HashSet;
46import java.util.List;
47import java.util.concurrent.atomic.LongAdder;
48import jdk.dynalink.CallSiteDescriptor;
49import jdk.dynalink.SecureLookupSupplier;
50import jdk.dynalink.linker.GuardedInvocation;
51import jdk.dynalink.linker.LinkRequest;
52import jdk.dynalink.linker.support.Guards;
53import jdk.nashorn.internal.codegen.ApplySpecialization;
54import jdk.nashorn.internal.codegen.Compiler;
55import jdk.nashorn.internal.codegen.CompilerConstants.Call;
56import jdk.nashorn.internal.ir.FunctionNode;
57import jdk.nashorn.internal.objects.Global;
58import jdk.nashorn.internal.objects.NativeFunction;
59import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
60import jdk.nashorn.internal.runtime.linker.Bootstrap;
61import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
62import jdk.nashorn.internal.runtime.logging.DebugLogger;
63
64/**
65 * Runtime representation of a JavaScript function. This class has only private
66 * and protected constructors. There are no *public* constructors - but only
67 * factory methods that follow the naming pattern "createXYZ".
68 */
69public class ScriptFunction extends ScriptObject {
70
71    /**
72     * Method handle for prototype getter for this ScriptFunction
73     */
74    public static final MethodHandle G$PROTOTYPE = findOwnMH_S("G$prototype", Object.class, Object.class);
75
76    /**
77     * Method handle for prototype setter for this ScriptFunction
78     */
79    public static final MethodHandle S$PROTOTYPE = findOwnMH_S("S$prototype", void.class, Object.class, Object.class);
80
81    /**
82     * Method handle for length getter for this ScriptFunction
83     */
84    public static final MethodHandle G$LENGTH = findOwnMH_S("G$length", int.class, Object.class);
85
86    /**
87     * Method handle for name getter for this ScriptFunction
88     */
89    public static final MethodHandle G$NAME = findOwnMH_S("G$name", Object.class, Object.class);
90
91    /**
92     * Method handle used for implementing sync() in mozilla_compat
93     */
94    public static final MethodHandle INVOKE_SYNC = findOwnMH_S("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
95
96    /**
97     * Method handle for allocate function for this ScriptFunction
98     */
99    static final MethodHandle ALLOCATE = findOwnMH_V("allocate", Object.class);
100
101    private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class);
102
103    private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
104
105    /**
106     * method handle to scope getter for this ScriptFunction
107     */
108    public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
109
110    private static final MethodHandle IS_FUNCTION_MH = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
111
112    private static final MethodHandle IS_APPLY_FUNCTION = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class);
113
114    private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH_S("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
115
116    private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH_S("addZerothElement", Object[].class, Object[].class, Object.class);
117
118    private static final MethodHandle WRAP_THIS = MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, "wrapThis", MH.type(Object.class, Object.class));
119
120    // various property maps used for different kinds of functions
121    // property map for anonymous function that serves as Function.prototype
122    private static final PropertyMap anonmap$;
123    // property map for strict mode functions
124    private static final PropertyMap strictmodemap$;
125    // property map for bound functions
126    private static final PropertyMap boundfunctionmap$;
127    // property map for non-strict, non-bound functions.
128    private static final PropertyMap map$;
129
130    // Marker object for lazily initialized prototype object
131    private static final Object LAZY_PROTOTYPE = new Object();
132
133    private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
134            AccessControlContextFactory.createAccessControlContext(SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
135
136    private static PropertyMap createStrictModeMap(final PropertyMap map) {
137        final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
138        PropertyMap newMap = map;
139        // Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
140        newMap = newMap.addPropertyNoHistory(map.newUserAccessors("arguments", flags));
141        newMap = newMap.addPropertyNoHistory(map.newUserAccessors("caller", flags));
142        return newMap;
143    }
144
145    private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) {
146        // Bound function map is same as strict function map, but additionally lacks the "prototype" property, see
147        // ECMAScript 5.1 section 15.3.4.5
148        return strictModeMap.deleteProperty(strictModeMap.findProperty("prototype"));
149    }
150
151    static {
152        anonmap$ = PropertyMap.newMap();
153        final ArrayList<Property> properties = new ArrayList<>(3);
154        properties.add(AccessorProperty.create("prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE));
155        properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null));
156        properties.add(AccessorProperty.create("name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null));
157        map$ = PropertyMap.newMap(properties);
158        strictmodemap$ = createStrictModeMap(map$);
159        boundfunctionmap$ = createBoundFunctionMap(strictmodemap$);
160    }
161
162    private static boolean isStrict(final int flags) {
163        return (flags & ScriptFunctionData.IS_STRICT) != 0;
164    }
165
166    // Choose the map based on strict mode!
167    private static PropertyMap getMap(final boolean strict) {
168        return strict ? strictmodemap$ : map$;
169    }
170
171    /**
172     * The parent scope.
173     */
174    private final ScriptObject scope;
175
176    private final ScriptFunctionData data;
177
178    /**
179     * The property map used for newly allocated object when function is used as
180     * constructor.
181     */
182    protected PropertyMap allocatorMap;
183
184    /**
185     * Reference to constructor prototype.
186     */
187    protected Object prototype;
188
189    /**
190     * Constructor
191     *
192     * @param data static function data
193     * @param map property map
194     * @param scope scope
195     */
196    private ScriptFunction(
197            final ScriptFunctionData data,
198            final PropertyMap map,
199            final ScriptObject scope,
200            final Global global) {
201
202        super(map);
203
204        if (Context.DEBUG) {
205            constructorCount.increment();
206        }
207
208        this.data = data;
209        this.scope = scope;
210        this.setInitialProto(global.getFunctionPrototype());
211        this.prototype = LAZY_PROTOTYPE;
212
213        // We have to fill user accessor functions late as these are stored
214        // in this object rather than in the PropertyMap of this object.
215        assert objectSpill == null;
216        if (isStrict() || isBoundFunction()) {
217            final ScriptFunction typeErrorThrower = global.getTypeErrorThrower();
218            initUserAccessors("arguments", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
219            initUserAccessors("caller", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
220        }
221    }
222
223    /**
224     * Constructor
225     *
226     * @param name function name
227     * @param methodHandle method handle to function (if specializations are
228     * present, assumed to be most generic)
229     * @param map property map
230     * @param scope scope
231     * @param specs specialized version of this function - other method handles
232     * @param flags {@link ScriptFunctionData} flags
233     */
234    private ScriptFunction(
235            final String name,
236            final MethodHandle methodHandle,
237            final PropertyMap map,
238            final ScriptObject scope,
239            final Specialization[] specs,
240            final int flags,
241            final Global global) {
242        this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope, global);
243    }
244
245    /**
246     * Constructor
247     *
248     * @param name name of function
249     * @param methodHandle handle for invocation
250     * @param scope scope object
251     * @param specs specialized versions of this method, if available, null
252     * otherwise
253     * @param flags {@link ScriptFunctionData} flags
254     */
255    private ScriptFunction(
256            final String name,
257            final MethodHandle methodHandle,
258            final ScriptObject scope,
259            final Specialization[] specs,
260            final int flags) {
261        this(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags, Global.instance());
262    }
263
264    /**
265     * Constructor called by Nasgen generated code, zero added members, use the
266     * default map. Creates builtin functions only.
267     *
268     * @param name name of function
269     * @param invokeHandle handle for invocation
270     * @param specs specialized versions of this method, if available, null
271     * otherwise
272     */
273    protected ScriptFunction(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
274        this(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR, Global.instance());
275    }
276
277    /**
278     * Constructor called by Nasgen generated code, non zero member count, use
279     * the map passed as argument. Creates builtin functions only.
280     *
281     * @param name name of function
282     * @param invokeHandle handle for invocation
283     * @param map initial property map
284     * @param specs specialized versions of this method, if available, null
285     * otherwise
286     */
287    protected ScriptFunction(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
288        this(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR, Global.instance());
289    }
290
291    // Factory methods to create various functions
292    /**
293     * Factory method called by compiler generated code for functions that need
294     * parent scope.
295     *
296     * @param constants the generated class' constant array
297     * @param index the index of the {@code RecompilableScriptFunctionData}
298     * object in the constants array.
299     * @param scope the parent scope object
300     * @return a newly created function object
301     */
302    public static ScriptFunction create(final Object[] constants, final int index, final ScriptObject scope) {
303        final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constants[index];
304        return new ScriptFunction(data, getMap(data.isStrict()), scope, Global.instance());
305    }
306
307    /**
308     * Factory method called by compiler generated code for functions that don't
309     * need parent scope.
310     *
311     * @param constants the generated class' constant array
312     * @param index the index of the {@code RecompilableScriptFunctionData}
313     * object in the constants array.
314     * @return a newly created function object
315     */
316    public static ScriptFunction create(final Object[] constants, final int index) {
317        return create(constants, index, null);
318    }
319
320    /**
321     * Create anonymous function that serves as Function.prototype
322     *
323     * @return anonymous function object
324     */
325    public static ScriptFunction createAnonymous() {
326        return new ScriptFunction("", GlobalFunctions.ANONYMOUS, anonmap$, null);
327    }
328
329    // builtin function create helper factory
330    private static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
331        final ScriptFunction func = new ScriptFunction(name, methodHandle, null, specs, flags);
332        func.setPrototype(UNDEFINED);
333        // Non-constructor built-in functions do not have "prototype" property
334        func.deleteOwnProperty(func.getMap().findProperty("prototype"));
335
336        return func;
337    }
338
339    /**
340     * Factory method for non-constructor built-in functions
341     *
342     * @param name function name
343     * @param methodHandle handle for invocation
344     * @param specs specialized versions of function if available, null
345     * otherwise
346     * @return new ScriptFunction
347     */
348    public static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
349        return ScriptFunction.createBuiltin(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
350    }
351
352    /**
353     * Factory method for non-constructor built-in functions
354     *
355     * @param name function name
356     * @param methodHandle handle for invocation
357     * @return new ScriptFunction
358     */
359    public static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle) {
360        return ScriptFunction.createBuiltin(name, methodHandle, null);
361    }
362
363    /**
364     * Factory method for non-constructor built-in, strict functions
365     *
366     * @param name function name
367     * @param methodHandle handle for invocation
368     * @return new ScriptFunction
369     */
370    public static ScriptFunction createStrictBuiltin(final String name, final MethodHandle methodHandle) {
371        return ScriptFunction.createBuiltin(name, methodHandle, null, ScriptFunctionData.IS_BUILTIN | ScriptFunctionData.IS_STRICT);
372    }
373
374    // Subclass to represent bound functions
375    private static class Bound extends ScriptFunction {
376        private final ScriptFunction target;
377
378        Bound(final ScriptFunctionData boundData, final ScriptFunction target) {
379            super(boundData, boundfunctionmap$, null, Global.instance());
380            setPrototype(ScriptRuntime.UNDEFINED);
381            this.target = target;
382        }
383
384        @Override
385        protected ScriptFunction getTargetFunction() {
386            return target;
387        }
388    }
389
390    /**
391     * Creates a version of this function bound to a specific "self" and other
392     * arguments, as per {@code Function.prototype.bind} functionality in
393     * ECMAScript 5.1 section 15.3.4.5.
394     *
395     * @param self the self to bind to this function. Can be null (in which
396     * case, null is bound as this).
397     * @param args additional arguments to bind to this function. Can be null or
398     * empty to not bind additional arguments.
399     * @return a function with the specified self and parameters bound.
400     */
401    public final ScriptFunction createBound(final Object self, final Object[] args) {
402        return new Bound(data.makeBoundFunctionData(this, self, args), getTargetFunction());
403    }
404
405    /**
406     * Create a function that invokes this function synchronized on {@code sync}
407     * or the self object of the invocation.
408     *
409     * @param sync the Object to synchronize on, or undefined
410     * @return synchronized function
411     */
412    public final ScriptFunction createSynchronized(final Object sync) {
413        final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync);
414        return createBuiltin(getName(), mh);
415    }
416
417    @Override
418    public String getClassName() {
419        return "Function";
420    }
421
422    /**
423     * ECMA 15.3.5.3 [[HasInstance]] (V) Step 3 if "prototype" value is not an
424     * Object, throw TypeError
425     */
426    @Override
427    public boolean isInstance(final ScriptObject instance) {
428        final Object basePrototype = getTargetFunction().getPrototype();
429        if (!(basePrototype instanceof ScriptObject)) {
430            throw typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype));
431        }
432
433        for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
434            if (proto == basePrototype) {
435                return true;
436            }
437        }
438
439        return false;
440    }
441
442    /**
443     * Returns the target function for this function. If the function was not
444     * created using {@link #createBound(Object, Object[])}, its target
445     * function is itself. If it is bound, its target function is the target
446     * function of the function it was made from (therefore, the target function
447     * is always the final, unbound recipient of the calls).
448     *
449     * @return the target function for this function.
450     */
451    protected ScriptFunction getTargetFunction() {
452        return this;
453    }
454
455    final boolean isBoundFunction() {
456        return getTargetFunction() != this;
457    }
458
459    /**
460     * Set the arity of this ScriptFunction
461     *
462     * @param arity arity
463     */
464    public final void setArity(final int arity) {
465        data.setArity(arity);
466    }
467
468    /**
469     * Is this a ECMAScript 'use strict' function?
470     *
471     * @return true if function is in strict mode
472     */
473    public final boolean isStrict() {
474        return data.isStrict();
475    }
476
477    /**
478     * Is this is a function with all variables in scope?
479     * @return true if function has all
480     */
481    public boolean hasAllVarsInScope() {
482        return data instanceof RecompilableScriptFunctionData &&
483                (((RecompilableScriptFunctionData) data).getFunctionFlags() & FunctionNode.HAS_ALL_VARS_IN_SCOPE) != 0;
484    }
485
486    /**
487     * Returns true if this is a non-strict, non-built-in function that requires
488     * non-primitive this argument according to ECMA 10.4.3.
489     *
490     * @return true if this argument must be an object
491     */
492    public final boolean needsWrappedThis() {
493        return data.needsWrappedThis();
494    }
495
496    private static boolean needsWrappedThis(final Object fn) {
497        return fn instanceof ScriptFunction ? ((ScriptFunction) fn).needsWrappedThis() : false;
498    }
499
500    /**
501     * Execute this script function.
502     *
503     * @param self Target object.
504     * @param arguments Call arguments.
505     * @return ScriptFunction result.
506     * @throws Throwable if there is an exception/error with the invocation or
507     * thrown from it
508     */
509    final Object invoke(final Object self, final Object... arguments) throws Throwable {
510        if (Context.DEBUG) {
511            invokes.increment();
512        }
513        return data.invoke(this, self, arguments);
514    }
515
516    /**
517     * Execute this script function as a constructor.
518     *
519     * @param arguments Call arguments.
520     * @return Newly constructed result.
521     * @throws Throwable if there is an exception/error with the invocation or
522     * thrown from it
523     */
524    final Object construct(final Object... arguments) throws Throwable {
525        return data.construct(this, arguments);
526    }
527
528    /**
529     * Allocate function. Called from generated {@link ScriptObject} code for
530     * allocation as a factory method
531     *
532     * @return a new instance of the {@link ScriptObject} whose allocator this
533     * is
534     */
535    @SuppressWarnings("unused")
536    private Object allocate() {
537        if (Context.DEBUG) {
538            allocations.increment();
539        }
540
541        assert !isBoundFunction(); // allocate never invoked on bound functions
542
543        final ScriptObject prototype = getAllocatorPrototype();
544        final ScriptObject object = data.allocate(getAllocatorMap(prototype));
545
546        if (object != null) {
547            object.setInitialProto(prototype);
548        }
549
550        return object;
551    }
552
553    /**
554     * Get the property map used by "allocate"
555     * @param prototype actual prototype object
556     * @return property map
557     */
558    private PropertyMap getAllocatorMap(final ScriptObject prototype) {
559        if (allocatorMap == null || allocatorMap.isInvalidSharedMapFor(prototype)) {
560            // The prototype map has changed since this function was last used as constructor.
561            // Get a new allocator map.
562            allocatorMap = data.getAllocatorMap(prototype);
563        }
564        return allocatorMap;
565    }
566
567    /**
568     * Return the actual prototype used by "allocate"
569     * @return allocator prototype
570     */
571    private ScriptObject getAllocatorPrototype() {
572        final Object prototype = getPrototype();
573        if (prototype instanceof ScriptObject) {
574            return (ScriptObject) prototype;
575        }
576        return Global.objectPrototype();
577    }
578
579    @Override
580    public final String safeToString() {
581        return toSource();
582    }
583
584    @Override
585    public final String toString() {
586        return data.toString();
587    }
588
589    /**
590     * Get this function as a String containing its source code. If no source
591     * code exists in this ScriptFunction, its contents will be displayed as
592     * {@code [native code]}
593     *
594     * @return string representation of this function's source
595     */
596    public final String toSource() {
597        return data.toSource();
598    }
599
600    /**
601     * Get the prototype object for this function
602     *
603     * @return prototype
604     */
605    public final Object getPrototype() {
606        if (prototype == LAZY_PROTOTYPE) {
607            prototype = new PrototypeObject(this);
608        }
609        return prototype;
610    }
611
612    /**
613     * Set the prototype object for this function
614     *
615     * @param newPrototype new prototype object
616     */
617    public final void setPrototype(final Object newPrototype) {
618        if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
619            // Unset allocator map to be replaced with one matching the new prototype.
620            allocatorMap = null;
621        }
622        this.prototype = newPrototype;
623    }
624
625    /**
626     * Return the invoke handle bound to a given ScriptObject self reference. If
627     * callee parameter is required result is rebound to this.
628     *
629     * @param self self reference
630     * @return bound invoke handle
631     */
632    public final MethodHandle getBoundInvokeHandle(final Object self) {
633        return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), self);
634    }
635
636    /**
637     * Bind the method handle to this {@code ScriptFunction} instance if it
638     * needs a callee parameter. If this function's method handles don't have a
639     * callee parameter, the handle is returned unchanged.
640     *
641     * @param methodHandle the method handle to potentially bind to this
642     * function instance.
643     * @return the potentially bound method handle
644     */
645    private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
646        return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
647
648    }
649
650    /**
651     * Get the documentation for this function
652     *
653     * @return the documentation
654     */
655    public final String getDocumentation() {
656        return data.getDocumentation();
657    }
658
659    /**
660     * Get the documentation key for this function
661     *
662     * @return the documentation key
663     */
664    public final String getDocumentationKey() {
665        return data.getDocumentationKey();
666    }
667
668    /**
669     * Set the documentation key for this function
670     *
671     * @param docKey documentation key String for this function
672     */
673    public final void setDocumentationKey(final String docKey) {
674        data.setDocumentationKey(docKey);
675    }
676
677    /**
678     * Get the name for this function
679     *
680     * @return the name
681     */
682    public final String getName() {
683        return data.getName();
684    }
685
686    /**
687     * Get the scope for this function
688     *
689     * @return the scope
690     */
691    public final ScriptObject getScope() {
692        return scope;
693    }
694
695    /**
696     * Prototype getter for this ScriptFunction - follows the naming convention
697     * used by Nasgen and the code generator
698     *
699     * @param self self reference
700     * @return self's prototype
701     */
702    public static Object G$prototype(final Object self) {
703        return self instanceof ScriptFunction
704                ? ((ScriptFunction) self).getPrototype()
705                : UNDEFINED;
706    }
707
708    /**
709     * Prototype setter for this ScriptFunction - follows the naming convention
710     * used by Nasgen and the code generator
711     *
712     * @param self self reference
713     * @param prototype prototype to set
714     */
715    public static void S$prototype(final Object self, final Object prototype) {
716        if (self instanceof ScriptFunction) {
717            ((ScriptFunction) self).setPrototype(prototype);
718        }
719    }
720
721    /**
722     * Length getter - ECMA 15.3.3.2: Function.length
723     *
724     * @param self self reference
725     * @return length
726     */
727    public static int G$length(final Object self) {
728        if (self instanceof ScriptFunction) {
729            return ((ScriptFunction) self).data.getArity();
730        }
731
732        return 0;
733    }
734
735    /**
736     * Name getter - ECMA Function.name
737     *
738     * @param self self reference
739     * @return the name, or undefined if none
740     */
741    public static Object G$name(final Object self) {
742        if (self instanceof ScriptFunction) {
743            return ((ScriptFunction) self).getName();
744        }
745
746        return UNDEFINED;
747    }
748
749    /**
750     * Get the prototype for this ScriptFunction
751     *
752     * @param constructor constructor
753     * @return prototype, or null if given constructor is not a ScriptFunction
754     */
755    public static ScriptObject getPrototype(final ScriptFunction constructor) {
756        if (constructor != null) {
757            final Object proto = constructor.getPrototype();
758            if (proto instanceof ScriptObject) {
759                return (ScriptObject) proto;
760            }
761        }
762
763        return null;
764    }
765
766    // These counters are updated only in debug mode.
767    private static LongAdder constructorCount;
768    private static LongAdder invokes;
769    private static LongAdder allocations;
770
771    static {
772        if (Context.DEBUG) {
773            constructorCount = new LongAdder();
774            invokes = new LongAdder();
775            allocations = new LongAdder();
776        }
777    }
778
779    /**
780     * @return the constructorCount
781     */
782    public static long getConstructorCount() {
783        return constructorCount.longValue();
784    }
785
786    /**
787     * @return the invokes
788     */
789    public static long getInvokes() {
790        return invokes.longValue();
791    }
792
793    /**
794     * @return the allocations
795     */
796    public static long getAllocations() {
797        return allocations.longValue();
798    }
799
800    @Override
801    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
802        final MethodType type = desc.getMethodType();
803        assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
804        final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
805        final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
806        //TODO - ClassCastException
807        return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
808    }
809
810    private static Object wrapFilter(final Object obj) {
811        if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
812            return obj;
813        }
814        return Context.getGlobal().wrapAsObject(obj);
815    }
816
817    @SuppressWarnings("unused")
818    private static Object globalFilter(final Object object) {
819        // replace whatever we get with the current global object
820        return Context.getGlobal();
821    }
822
823    /**
824     * Some receivers are primitive, in that case, according to the Spec we
825     * create a new native object per callsite with the wrap filter. We can only
826     * apply optimistic builtins if there is no per instance state saved for
827     * these wrapped objects (e.g. currently NativeStrings), otherwise we can't
828     * create optimistic versions
829     *
830     * @param self receiver
831     * @param linkLogicClass linkLogicClass, or null if no link logic exists
832     * @return link logic instance, or null if one could not be constructed for
833     * this receiver
834     */
835    private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
836        if (linkLogicClass == null) {
837            return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
838        }
839
840        if (!Context.getContextTrusted().getEnv()._optimistic_types) {
841            return null; //if optimistic types are off, optimistic builtins are too
842        }
843
844        final Object wrappedSelf = wrapFilter(self);
845        if (wrappedSelf instanceof OptimisticBuiltins) {
846            if (wrappedSelf != self && ((OptimisticBuiltins) wrappedSelf).hasPerInstanceAssumptions()) {
847                return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
848            }
849            return ((OptimisticBuiltins) wrappedSelf).getLinkLogic(linkLogicClass);
850        }
851        return null;
852    }
853
854    /**
855     * StandardOperation.CALL call site signature: (callee, thiz, [args...]) generated method
856     * signature: (callee, thiz, [args...])
857     *
858     * cases:
859     * (a) method has callee parameter
860     *     (1) for local/scope calls, we just bind thiz and drop the second argument.
861     *     (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
862     * (b) method doesn't have callee parameter (builtin functions)
863     *     (3) for local/scope calls, bind thiz and drop both callee and thiz.
864     *     (4) for normal this-calls, drop callee.
865     *
866     * @return guarded invocation for call
867     */
868    @Override
869    protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
870        final MethodType type = desc.getMethodType();
871
872        final String name = getName();
873        final boolean isUnstable = request.isCallSiteUnstable();
874        final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
875        final boolean isCall = !scopeCall && data.isBuiltin() && "call".equals(name);
876        final boolean isApply = !scopeCall && data.isBuiltin() && "apply".equals(name);
877
878        final boolean isApplyOrCall = isCall | isApply;
879
880        if (isUnstable && !isApplyOrCall) {
881            //megamorphic - replace call with apply
882            final MethodHandle handle;
883            //ensure that the callsite is vararg so apply can consume it
884            if (type.parameterCount() == 3 && type.parameterType(2) == Object[].class) {
885                // Vararg call site
886                handle = ScriptRuntime.APPLY.methodHandle();
887            } else {
888                // (callee, this, args...) => (callee, this, args[])
889                handle = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
890            }
891
892            // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
893            // generic "is this a ScriptFunction?" guard.
894            return new GuardedInvocation(
895                    handle,
896                    null,
897                    (SwitchPoint) null,
898                    ClassCastException.class);
899        }
900
901        MethodHandle boundHandle;
902        MethodHandle guard = null;
903
904        // Special handling of Function.apply and Function.call. Note we must be invoking
905        if (isApplyOrCall && !isUnstable) {
906            final Object[] args = request.getArguments();
907            if (Bootstrap.isCallable(args[1])) {
908                return createApplyOrCallCall(isApply, desc, request, args);
909            }
910        } //else just fall through and link as ordinary function or unstable apply
911
912        int programPoint = INVALID_PROGRAM_POINT;
913        if (NashornCallSiteDescriptor.isOptimistic(desc)) {
914            programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
915        }
916
917        CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
918        final Object self = request.getArguments()[1];
919        final Collection<CompiledFunction> forbidden = new HashSet<>();
920
921        //check for special fast versions of the compiled function
922        final List<SwitchPoint> sps = new ArrayList<>();
923        Class<? extends Throwable> exceptionGuard = null;
924
925        while (cf.isSpecialization()) {
926            final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
927            //if linklogic is null, we can always link with the standard mechanism, it's still a specialization
928            final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
929
930            if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
931                final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
932
933                if (log.isEnabled()) {
934                    log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
935                }
936
937                exceptionGuard = linkLogic.getRelinkException();
938
939                break;
940            }
941
942            //could not link this specialization because link check failed
943            forbidden.add(cf);
944            final CompiledFunction oldCf = cf;
945            cf = data.getBestInvoker(type, scope, forbidden);
946            assert oldCf != cf;
947        }
948
949        final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
950        final MethodHandle callHandle = bestInvoker.getInvocation();
951
952        if (data.needsCallee()) {
953            if (scopeCall && needsWrappedThis()) {
954                // (callee, this, args...) => (callee, [this], args...)
955                boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER);
956            } else {
957                // It's already (callee, this, args...), just what we need
958                boundHandle = callHandle;
959            }
960        } else if (data.isBuiltin() && Global.isBuiltInJavaExtend(this)) {
961            // We're binding the current lookup as "self" so the function can do
962            // security-sensitive creation of adapter classes.
963            boundHandle = MH.dropArguments(MH.bindTo(callHandle, getLookupPrivileged(desc)), 0, type.parameterType(0), type.parameterType(1));
964        } else if (data.isBuiltin() && Global.isBuiltInJavaTo(this)) {
965            // We're binding the current call site descriptor as "self" so the function can do
966            // security-sensitive creation of adapter classes.
967            boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc), 0, type.parameterType(0), type.parameterType(1));
968        } else if (scopeCall && needsWrappedThis()) {
969            // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
970            // (this, args...) => ([this], args...)
971            boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER);
972            // ([this], args...) => ([callee], [this], args...)
973            boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0));
974        } else {
975            // (this, args...) => ([callee], this, args...)
976            boundHandle = MH.dropArguments(callHandle, 0, type.parameterType(0));
977        }
978
979        // For non-strict functions, check whether this-object is primitive type.
980        // If so add a to-object-wrapper argument filter.
981        // Else install a guard that will trigger a relink when the argument becomes primitive.
982        if (!scopeCall && needsWrappedThis()) {
983            if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
984                boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
985            } else {
986                guard = getNonStrictFunctionGuard(this);
987            }
988        }
989
990        // Is this an unstable callsite which was earlier apply-to-call optimized?
991        // If so, earlier apply2call would have exploded arguments. We have to convert
992        // that as an array again!
993        if (isUnstable && NashornCallSiteDescriptor.isApplyToCall(desc)) {
994            boundHandle = MH.asCollector(boundHandle, Object[].class, type.parameterCount() - 2);
995        }
996
997        boundHandle = pairArguments(boundHandle, type);
998
999        if (bestInvoker.getSwitchPoints() != null) {
1000            sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
1001        }
1002        final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[0]);
1003
1004        return new GuardedInvocation(
1005                boundHandle,
1006                guard == null ?
1007                        getFunctionGuard(
1008                                this,
1009                                cf.getFlags()) :
1010                        guard,
1011                spsArray,
1012                exceptionGuard);
1013    }
1014
1015    private static Lookup getLookupPrivileged(final CallSiteDescriptor desc) {
1016        // NOTE: we'd rather not make NashornCallSiteDescriptor.getLookupPrivileged public.
1017        return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->desc.getLookup(),
1018                GET_LOOKUP_PERMISSION_CONTEXT);
1019    }
1020
1021    private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
1022        final MethodType descType = desc.getMethodType();
1023        final int paramCount = descType.parameterCount();
1024        if (descType.parameterType(paramCount - 1).isArray()) {
1025            // This is vararg invocation of apply or call. This can normally only happen when we do a recursive
1026            // invocation of createApplyOrCallCall (because we're doing apply-of-apply). In this case, create delegate
1027            // linkage by unpacking the vararg invocation and use pairArguments to introduce the necessary spreader.
1028            return createVarArgApplyOrCallCall(isApply, desc, request, args);
1029        }
1030
1031        final boolean passesThis = paramCount > 2;
1032        final boolean passesArgs = paramCount > 3;
1033        final int realArgCount = passesArgs ? paramCount - 3 : 0;
1034
1035        final Object appliedFn = args[1];
1036        final boolean appliedFnNeedsWrappedThis = needsWrappedThis(appliedFn);
1037
1038        //box call back to apply
1039        CallSiteDescriptor appliedDesc = desc;
1040        final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
1041        //enough to change the proto switchPoint here
1042
1043        final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
1044        final boolean isFailedApplyToCall = isApplyToCall && applyToCallSwitchPoint.hasBeenInvalidated();
1045
1046        // R(apply|call, ...) => R(...)
1047        MethodType appliedType = descType.dropParameterTypes(0, 1);
1048        if (!passesThis) {
1049            // R() => R(this)
1050            appliedType = appliedType.insertParameterTypes(1, Object.class);
1051        } else if (appliedFnNeedsWrappedThis) {
1052            appliedType = appliedType.changeParameterType(1, Object.class);
1053        }
1054
1055        /*
1056         * dropArgs is a synthetic method handle that contains any args that we need to
1057         * get rid of that come after the arguments array in the apply case. We adapt
1058         * the callsite to ask for 3 args only and then dropArguments on the method handle
1059         * to make it fit the extraneous args.
1060         */
1061        MethodType dropArgs = MH.type(void.class);
1062        if (isApply && !isFailedApplyToCall) {
1063            final int pc = appliedType.parameterCount();
1064            for (int i = 3; i < pc; i++) {
1065                dropArgs = dropArgs.appendParameterTypes(appliedType.parameterType(i));
1066            }
1067            if (pc > 3) {
1068                appliedType = appliedType.dropParameterTypes(3, pc);
1069            }
1070        }
1071
1072        if (isApply || isFailedApplyToCall) {
1073            if (passesArgs) {
1074                // R(this, args) => R(this, Object[])
1075                appliedType = appliedType.changeParameterType(2, Object[].class);
1076                // drop any extraneous arguments for the apply fail case
1077                if (isFailedApplyToCall) {
1078                    appliedType = appliedType.dropParameterTypes(3, paramCount - 1);
1079                }
1080            } else {
1081                // R(this) => R(this, Object[])
1082                appliedType = appliedType.insertParameterTypes(2, Object[].class);
1083            }
1084        }
1085
1086        appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
1087
1088        // Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
1089        final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
1090        appliedArgs[0] = appliedFn;
1091        appliedArgs[1] = passesThis ? appliedFnNeedsWrappedThis ? ScriptFunctionData.wrapThis(args[2]) : args[2] : ScriptRuntime.UNDEFINED;
1092        if (isApply && !isFailedApplyToCall) {
1093            appliedArgs[2] = passesArgs ? NativeFunction.toApplyArgs(args[3]) : ScriptRuntime.EMPTY_ARRAY;
1094        } else {
1095            if (passesArgs) {
1096                if (isFailedApplyToCall) {
1097                    final Object[] tmp = new Object[args.length - 3];
1098                    System.arraycopy(args, 3, tmp, 0, tmp.length);
1099                    appliedArgs[2] = NativeFunction.toApplyArgs(tmp);
1100                } else {
1101                    assert !isApply;
1102                    System.arraycopy(args, 3, appliedArgs, 2, args.length - 3);
1103                }
1104            } else if (isFailedApplyToCall) {
1105                appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
1106            }
1107        }
1108
1109        // Ask the linker machinery for an invocation of the target function
1110        final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
1111
1112        GuardedInvocation appliedInvocation;
1113        try {
1114            appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
1115        } catch (final RuntimeException | Error e) {
1116            throw e;
1117        } catch (final Exception e) {
1118            throw new RuntimeException(e);
1119        }
1120        assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
1121
1122        final Class<?> applyFnType = descType.parameterType(0);
1123        // Invocation and guard handles from apply invocation.
1124        MethodHandle inv = appliedInvocation.getInvocation();
1125        MethodHandle guard = appliedInvocation.getGuard();
1126
1127        if (isApply && !isFailedApplyToCall) {
1128            if (passesArgs) {
1129                // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
1130                inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
1131                // Some guards (non-strict functions with non-primitive this) have a this-object parameter, so we
1132                // need to apply this transformations to them as well.
1133                if (guard.type().parameterCount() > 2) {
1134                    guard = MH.filterArguments(guard, 2, NativeFunction.TO_APPLY_ARGS);
1135                }
1136            } else {
1137                // If the original call site doesn't pass argArray, pass in an empty array
1138                inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY);
1139            }
1140        }
1141
1142        if (isApplyToCall) {
1143            if (isFailedApplyToCall) {
1144                //take the real arguments that were passed to a call and force them into the apply instead
1145                Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
1146                inv = MH.asCollector(inv, Object[].class, realArgCount);
1147            } else {
1148                appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
1149            }
1150        }
1151
1152        if (!passesThis) {
1153            // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
1154            inv = bindImplicitThis(appliedFnNeedsWrappedThis, inv);
1155            // guard may have this-parameter that needs to be inserted
1156            if (guard.type().parameterCount() > 1) {
1157                guard = bindImplicitThis(appliedFnNeedsWrappedThis, guard);
1158            }
1159        } else if (appliedFnNeedsWrappedThis) {
1160            // target function needs a wrapped this, so make sure we filter for that
1161            inv = MH.filterArguments(inv, 1, WRAP_THIS);
1162            // guard may have this-parameter that needs to be wrapped
1163            if (guard.type().parameterCount() > 1) {
1164                guard = MH.filterArguments(guard, 1, WRAP_THIS);
1165            }
1166        }
1167
1168        final MethodType guardType = guard.type(); // Needed for combining guards below
1169
1170        // We need to account for the dropped (apply|call) function argument.
1171        inv = MH.dropArguments(inv, 0, applyFnType);
1172        guard = MH.dropArguments(guard, 0, applyFnType);
1173
1174        /*
1175         * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
1176         * is when we need to add arguments to the callsite to catch and ignore the synthetic
1177         * extra args that someone has added to the command line.
1178         */
1179        for (int i = 0; i < dropArgs.parameterCount(); i++) {
1180            inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
1181        }
1182
1183        // Take the "isApplyFunction" guard, and bind it to this function.
1184        MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
1185        // Adapt the guard to receive all the arguments that the original guard does.
1186        applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
1187        // Fold the original function guard into our apply guard.
1188        guard = MH.foldArguments(applyFnGuard, guard);
1189
1190        return appliedInvocation.replaceMethods(inv, guard);
1191    }
1192
1193    /*
1194     * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity
1195     * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with
1196     * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method.
1197     * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back
1198     * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to
1199     * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity
1200     * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already
1201     * solved by createApplyOrCallCall) non-vararg call site linking.
1202     */
1203    private GuardedInvocation createVarArgApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc,
1204            final LinkRequest request, final Object[] args) {
1205        final MethodType descType = desc.getMethodType();
1206        final int paramCount = descType.parameterCount();
1207        final Object[] varArgs = (Object[]) args[paramCount - 1];
1208        // -1 'cause we're not passing the vararg array itself
1209        final int copiedArgCount = args.length - 1;
1210        final int varArgCount = varArgs.length;
1211
1212        // Spread arguments for the delegate createApplyOrCallCall invocation.
1213        final Object[] spreadArgs = new Object[copiedArgCount + varArgCount];
1214        System.arraycopy(args, 0, spreadArgs, 0, copiedArgCount);
1215        System.arraycopy(varArgs, 0, spreadArgs, copiedArgCount, varArgCount);
1216
1217        // Spread call site descriptor for the delegate createApplyOrCallCall invocation. We drop vararg array and
1218        // replace it with a list of Object.class.
1219        final MethodType spreadType = descType.dropParameterTypes(paramCount - 1, paramCount).appendParameterTypes(
1220                Collections.<Class<?>>nCopies(varArgCount, Object.class));
1221        final CallSiteDescriptor spreadDesc = desc.changeMethodType(spreadType);
1222
1223        // Delegate back to createApplyOrCallCall with the spread (that is, reverted to non-vararg) request/
1224        final LinkRequest spreadRequest = request.replaceArguments(spreadDesc, spreadArgs);
1225        final GuardedInvocation spreadInvocation = createApplyOrCallCall(isApply, spreadDesc, spreadRequest, spreadArgs);
1226
1227        // Add spreader combinators to returned invocation and guard.
1228        return spreadInvocation.replaceMethods(
1229                // Use standard ScriptObject.pairArguments on the invocation
1230                pairArguments(spreadInvocation.getInvocation(), descType),
1231                // Use our specialized spreadGuardArguments on the guard (see below).
1232                spreadGuardArguments(spreadInvocation.getGuard(), descType));
1233    }
1234
1235    private static MethodHandle spreadGuardArguments(final MethodHandle guard, final MethodType descType) {
1236        final MethodType guardType = guard.type();
1237        final int guardParamCount = guardType.parameterCount();
1238        final int descParamCount = descType.parameterCount();
1239        final int spreadCount = guardParamCount - descParamCount + 1;
1240        if (spreadCount <= 0) {
1241            // Guard doesn't dip into the varargs
1242            return guard;
1243        }
1244
1245        final MethodHandle arrayConvertingGuard;
1246        // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
1247        // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
1248        // with ClassCastException of NativeArray to Object[].
1249        if (guardType.parameterType(guardParamCount - 1).isArray()) {
1250            arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
1251        } else {
1252            arrayConvertingGuard = guard;
1253        }
1254
1255        return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount);
1256    }
1257
1258    private static MethodHandle bindImplicitThis(final boolean needsWrappedThis, final MethodHandle mh) {
1259        final MethodHandle bound;
1260        if (needsWrappedThis) {
1261            bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
1262        } else {
1263            bound = mh;
1264        }
1265        return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
1266    }
1267
1268    /**
1269     * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
1270     *
1271     * These don't want a callee parameter, so bind that. Name binding is
1272     * optional.
1273     */
1274    MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
1275        return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
1276    }
1277
1278    private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
1279        if (bindName == null) {
1280            return methodHandle;
1281        }
1282
1283        // if it is vararg method, we need to extend argument array with
1284        // a new zeroth element that is set to bindName value.
1285        final MethodType methodType = methodHandle.type();
1286        final int parameterCount = methodType.parameterCount();
1287
1288        if (parameterCount < 2) {
1289            return methodHandle; // method does not have enough parameters
1290        }
1291        final boolean isVarArg = methodType.parameterType(parameterCount - 1).isArray();
1292
1293        if (isVarArg) {
1294            return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
1295        }
1296        return MH.insertArguments(methodHandle, 1, bindName);
1297    }
1298
1299    /**
1300     * Get the guard that checks if a {@link ScriptFunction} is equal to a known
1301     * ScriptFunction, using reference comparison
1302     *
1303     * @param function The ScriptFunction to check against. This will be bound
1304     * to the guard method handle
1305     *
1306     * @return method handle for guard
1307     */
1308    private static MethodHandle getFunctionGuard(final ScriptFunction function, final int flags) {
1309        assert function.data != null;
1310        // Built-in functions have a 1-1 correspondence to their ScriptFunctionData, so we can use a cheaper identity
1311        // comparison for them.
1312        if (function.data.isBuiltin()) {
1313            return Guards.getIdentityGuard(function);
1314        }
1315        return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
1316    }
1317
1318    /**
1319     * Get a guard that checks if a {@link ScriptFunction} is equal to a known
1320     * ScriptFunction using reference comparison, and whether the type of the
1321     * second argument (this-object) is not a JavaScript primitive type.
1322     *
1323     * @param function The ScriptFunction to check against. This will be bound
1324     * to the guard method handle
1325     *
1326     * @return method handle for guard
1327     */
1328    private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
1329        assert function.data != null;
1330        return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
1331    }
1332
1333    @SuppressWarnings("unused")
1334    private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
1335        return self instanceof ScriptFunction && ((ScriptFunction) self).data == data;
1336    }
1337
1338    @SuppressWarnings("unused")
1339    private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
1340        return self instanceof ScriptFunction && ((ScriptFunction) self).data == data && arg instanceof ScriptObject;
1341    }
1342
1343    //TODO this can probably be removed given that we have builtin switchpoints in the context
1344    @SuppressWarnings("unused")
1345    private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
1346        // NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
1347        return appliedFnCondition && self == expectedSelf;
1348    }
1349
1350    @SuppressWarnings("unused")
1351    private static Object[] addZerothElement(final Object[] args, final Object value) {
1352        // extends input array with by adding new zeroth element
1353        final Object[] src = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
1354        final Object[] result = new Object[src.length + 1];
1355        System.arraycopy(src, 0, result, 1, src.length);
1356        result[0] = value;
1357        return result;
1358    }
1359
1360    @SuppressWarnings("unused")
1361    private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
1362            throws Throwable {
1363        final Object syncObj = sync == UNDEFINED ? self : sync;
1364        synchronized (syncObj) {
1365            return func.invoke(self, args);
1366        }
1367    }
1368
1369    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
1370        return MH.findStatic(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
1371    }
1372
1373    private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
1374        return MH.findVirtual(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
1375    }
1376}
1377