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