src/jdk/nashorn/internal/runtime/ScriptFunction.java

Thu, 10 Sep 2015 19:09:23 +0530

author
sundar
date
Thu, 10 Sep 2015 19:09:23 +0530
changeset 1529
098356b162c9
parent 1527
340b1462f3e2
child 1531
ab48ce00c634
permissions
-rw-r--r--

8135332: ScriptFunction constructor should use is bound and is strict check rather than checking for 'arguments' and 'caller'
Reviewed-by: attila, hannesw

     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  */
    25 package jdk.nashorn.internal.runtime;
    27 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
    28 import static jdk.nashorn.internal.lookup.Lookup.MH;
    29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    31 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    32 import java.lang.invoke.MethodHandle;
    33 import java.lang.invoke.MethodHandles;
    34 import java.lang.invoke.MethodType;
    35 import java.lang.invoke.SwitchPoint;
    36 import java.util.ArrayList;
    37 import java.util.Arrays;
    38 import java.util.Collection;
    39 import java.util.Collections;
    40 import java.util.HashSet;
    41 import java.util.List;
    42 import java.util.concurrent.atomic.LongAdder;
    43 import jdk.internal.dynalink.CallSiteDescriptor;
    44 import jdk.internal.dynalink.linker.GuardedInvocation;
    45 import jdk.internal.dynalink.linker.LinkRequest;
    46 import jdk.internal.dynalink.support.Guards;
    47 import jdk.nashorn.internal.codegen.ApplySpecialization;
    48 import jdk.nashorn.internal.codegen.Compiler;
    49 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
    50 import jdk.nashorn.internal.objects.Global;
    51 import jdk.nashorn.internal.objects.NativeFunction;
    52 import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
    53 import jdk.nashorn.internal.runtime.linker.Bootstrap;
    54 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
    55 import jdk.nashorn.internal.runtime.logging.DebugLogger;
    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  */
    62 public class ScriptFunction extends ScriptObject {
    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);
    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);
    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);
    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);
    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);
    89     /**
    90      * Method handle for allocate function for this ScriptFunction
    91      */
    92     static final MethodHandle ALLOCATE = findOwnMH_V("allocate", Object.class);
    94     private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class);
    96     private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
    98     /**
    99      * method handle to scope getter for this ScriptFunction
   100      */
   101     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
   103     private static final MethodHandle IS_FUNCTION_MH = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
   105     private static final MethodHandle IS_APPLY_FUNCTION = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class);
   107     private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH_S("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
   109     private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH_S("addZerothElement", Object[].class, Object[].class, Object.class);
   111     private static final MethodHandle WRAP_THIS = MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, "wrapThis", MH.type(Object.class, Object.class));
   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$;
   123     // Marker object for lazily initialized prototype object
   124     private static final Object LAZY_PROTOTYPE = new Object();
   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     }
   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     }
   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     }
   152     private static boolean isStrict(final int flags) {
   153         return (flags & ScriptFunctionData.IS_STRICT) != 0;
   154     }
   156     // Choose the map based on strict mode!
   157     private static PropertyMap getMap(final boolean strict) {
   158         return strict ? strictmodemap$ : map$;
   159     }
   161     /**
   162      * The parent scope.
   163      */
   164     private final ScriptObject scope;
   166     private final ScriptFunctionData data;
   168     /**
   169      * The property map used for newly allocated object when function is used as
   170      * constructor.
   171      */
   172     protected PropertyMap allocatorMap;
   174     /**
   175      * Reference to constructor prototype.
   176      */
   177     protected Object prototype;
   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) {
   192         super(map);
   194         if (Context.DEBUG) {
   195             constructorCount.increment();
   196         }
   198         this.data = data;
   199         this.scope = scope;
   200         this.setInitialProto(global.getFunctionPrototype());
   201         this.prototype = LAZY_PROTOTYPE;
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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"));
   326         return func;
   327     }
   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     }
   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     }
   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     }
   364     // Subclass to represent bound functions
   365     private static class Bound extends ScriptFunction {
   366         private final ScriptFunction target;
   368         Bound(final ScriptFunctionData boundData, final ScriptFunction target) {
   369             super(boundData, boundfunctionmap$, null, Global.instance());
   370             setPrototype(ScriptRuntime.UNDEFINED);
   371             this.target = target;
   372         }
   374         @Override
   375         protected ScriptFunction getTargetFunction() {
   376             return target;
   377         }
   378     }
   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     }
   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     }
   407     @Override
   408     public String getClassName() {
   409         return "Function";
   410     }
   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         }
   423         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
   424             if (proto == basePrototype) {
   425                 return true;
   426             }
   427         }
   429         return false;
   430     }
   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     }
   445     final boolean isBoundFunction() {
   446         return getTargetFunction() != this;
   447     }
   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     }
   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     }
   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     }
   477     private static boolean needsWrappedThis(final Object fn) {
   478         return fn instanceof ScriptFunction ? ((ScriptFunction) fn).needsWrappedThis() : false;
   479     }
   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     }
   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     }
   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         }
   522         assert !isBoundFunction(); // allocate never invoked on bound functions
   524         final ScriptObject object = data.allocate(getAllocatorMap());
   526         if (object != null) {
   527             final Object prototype = getPrototype();
   528             if (prototype instanceof ScriptObject) {
   529                 object.setInitialProto((ScriptObject) prototype);
   530             }
   532             if (object.getProto() == null) {
   533                 object.setInitialProto(getObjectPrototype());
   534             }
   535         }
   537         return object;
   538     }
   540     private PropertyMap getAllocatorMap() {
   541         if (allocatorMap == null) {
   542             allocatorMap = data.getAllocatorMap();
   543         }
   544         return allocatorMap;
   545     }
   547     /**
   548      * Return Object.prototype - used by "allocate"
   549      *
   550      * @return Object.prototype
   551      */
   552     protected final ScriptObject getObjectPrototype() {
   553         return Global.objectPrototype();
   554     }
   556     @Override
   557     public final String safeToString() {
   558         return toSource();
   559     }
   561     @Override
   562     public final String toString() {
   563         return data.toString();
   564     }
   566     /**
   567      * Get this function as a String containing its source code. If no source
   568      * code exists in this ScriptFunction, its contents will be displayed as
   569      * {@code [native code]}
   570      *
   571      * @return string representation of this function's source
   572      */
   573     public final String toSource() {
   574         return data.toSource();
   575     }
   577     /**
   578      * Get the prototype object for this function
   579      *
   580      * @return prototype
   581      */
   582     public final Object getPrototype() {
   583         if (prototype == LAZY_PROTOTYPE) {
   584             prototype = new PrototypeObject(this);
   585         }
   586         return prototype;
   587     }
   589     /**
   590      * Set the prototype object for this function
   591      *
   592      * @param newPrototype new prototype object
   593      */
   594     public final void setPrototype(Object newPrototype) {
   595         if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
   596             // Replace our current allocator map with one that is associated with the new prototype.
   597             allocatorMap = allocatorMap.changeProto((ScriptObject) newPrototype);
   598         }
   599         this.prototype = newPrototype;
   600     }
   602     /**
   603      * Return the invoke handle bound to a given ScriptObject self reference. If
   604      * callee parameter is required result is rebound to this.
   605      *
   606      * @param self self reference
   607      * @return bound invoke handle
   608      */
   609     public final MethodHandle getBoundInvokeHandle(final Object self) {
   610         return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), self);
   611     }
   613     /**
   614      * Bind the method handle to this {@code ScriptFunction} instance if it
   615      * needs a callee parameter. If this function's method handles don't have a
   616      * callee parameter, the handle is returned unchanged.
   617      *
   618      * @param methodHandle the method handle to potentially bind to this
   619      * function instance.
   620      * @return the potentially bound method handle
   621      */
   622     private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
   623         return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
   625     }
   627     /**
   628      * Get the name for this function
   629      *
   630      * @return the name
   631      */
   632     public final String getName() {
   633         return data.getName();
   634     }
   636     /**
   637      * Get the scope for this function
   638      *
   639      * @return the scope
   640      */
   641     public final ScriptObject getScope() {
   642         return scope;
   643     }
   645     /**
   646      * Prototype getter for this ScriptFunction - follows the naming convention
   647      * used by Nasgen and the code generator
   648      *
   649      * @param self self reference
   650      * @return self's prototype
   651      */
   652     public static Object G$prototype(final Object self) {
   653         return self instanceof ScriptFunction
   654                 ? ((ScriptFunction) self).getPrototype()
   655                 : UNDEFINED;
   656     }
   658     /**
   659      * Prototype setter for this ScriptFunction - follows the naming convention
   660      * used by Nasgen and the code generator
   661      *
   662      * @param self self reference
   663      * @param prototype prototype to set
   664      */
   665     public static void S$prototype(final Object self, final Object prototype) {
   666         if (self instanceof ScriptFunction) {
   667             ((ScriptFunction) self).setPrototype(prototype);
   668         }
   669     }
   671     /**
   672      * Length getter - ECMA 15.3.3.2: Function.length
   673      *
   674      * @param self self reference
   675      * @return length
   676      */
   677     public static int G$length(final Object self) {
   678         if (self instanceof ScriptFunction) {
   679             return ((ScriptFunction) self).data.getArity();
   680         }
   682         return 0;
   683     }
   685     /**
   686      * Name getter - ECMA Function.name
   687      *
   688      * @param self self refence
   689      * @return the name, or undefined if none
   690      */
   691     public static Object G$name(final Object self) {
   692         if (self instanceof ScriptFunction) {
   693             return ((ScriptFunction) self).getName();
   694         }
   696         return UNDEFINED;
   697     }
   699     /**
   700      * Get the prototype for this ScriptFunction
   701      *
   702      * @param constructor constructor
   703      * @return prototype, or null if given constructor is not a ScriptFunction
   704      */
   705     public static ScriptObject getPrototype(final ScriptFunction constructor) {
   706         if (constructor != null) {
   707             final Object proto = constructor.getPrototype();
   708             if (proto instanceof ScriptObject) {
   709                 return (ScriptObject) proto;
   710             }
   711         }
   713         return null;
   714     }
   716     // These counters are updated only in debug mode.
   717     private static LongAdder constructorCount;
   718     private static LongAdder invokes;
   719     private static LongAdder allocations;
   721     static {
   722         if (Context.DEBUG) {
   723             constructorCount = new LongAdder();
   724             invokes = new LongAdder();
   725             allocations = new LongAdder();
   726         }
   727     }
   729     /**
   730      * @return the constructorCount
   731      */
   732     public static long getConstructorCount() {
   733         return constructorCount.longValue();
   734     }
   736     /**
   737      * @return the invokes
   738      */
   739     public static long getInvokes() {
   740         return invokes.longValue();
   741     }
   743     /**
   744      * @return the allocations
   745      */
   746     public static long getAllocations() {
   747         return allocations.longValue();
   748     }
   750     @Override
   751     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
   752         final MethodType type = desc.getMethodType();
   753         assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
   754         final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
   755         final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
   756         //TODO - ClassCastException
   757         return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
   758     }
   760     private static Object wrapFilter(final Object obj) {
   761         if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
   762             return obj;
   763         }
   764         return Context.getGlobal().wrapAsObject(obj);
   765     }
   767     @SuppressWarnings("unused")
   768     private static Object globalFilter(final Object object) {
   769         // replace whatever we get with the current global object
   770         return Context.getGlobal();
   771     }
   773     /**
   774      * Some receivers are primitive, in that case, according to the Spec we
   775      * create a new native object per callsite with the wrap filter. We can only
   776      * apply optimistic builtins if there is no per instance state saved for
   777      * these wrapped objects (e.g. currently NativeStrings), otherwise we can't
   778      * create optimistic versions
   779      *
   780      * @param self receiver
   781      * @param linkLogicClass linkLogicClass, or null if no link logic exists
   782      * @return link logic instance, or null if one could not be constructed for
   783      * this receiver
   784      */
   785     private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
   786         if (linkLogicClass == null) {
   787             return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
   788         }
   790         if (!Context.getContextTrusted().getEnv()._optimistic_types) {
   791             return null; //if optimistic types are off, optimistic builtins are too
   792         }
   794         final Object wrappedSelf = wrapFilter(self);
   795         if (wrappedSelf instanceof OptimisticBuiltins) {
   796             if (wrappedSelf != self && ((OptimisticBuiltins) wrappedSelf).hasPerInstanceAssumptions()) {
   797                 return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
   798             }
   799             return ((OptimisticBuiltins) wrappedSelf).getLinkLogic(linkLogicClass);
   800         }
   801         return null;
   802     }
   804     /**
   805      * dyn:call call site signature: (callee, thiz, [args...]) generated method
   806      * signature: (callee, thiz, [args...])
   807      *
   808      * cases:
   809      * (a) method has callee parameter
   810      *     (1) for local/scope calls, we just bind thiz and drop the second argument.
   811      *     (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
   812      * (b) method doesn't have callee parameter (builtin functions)
   813      *     (3) for local/scope calls, bind thiz and drop both callee and thiz.
   814      *     (4) for normal this-calls, drop callee.
   815      *
   816      * @return guarded invocation for call
   817      */
   818     @Override
   819     protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
   820         final MethodType type = desc.getMethodType();
   822         final String name = getName();
   823         final boolean isUnstable = request.isCallSiteUnstable();
   824         final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
   825         final boolean isCall = !scopeCall && data.isBuiltin() && "call".equals(name);
   826         final boolean isApply = !scopeCall && data.isBuiltin() && "apply".equals(name);
   828         final boolean isApplyOrCall = isCall | isApply;
   830         if (isUnstable && !isApplyOrCall) {
   831             //megamorphic - replace call with apply
   832             final MethodHandle handle;
   833             //ensure that the callsite is vararg so apply can consume it
   834             if (type.parameterCount() == 3 && type.parameterType(2) == Object[].class) {
   835                 // Vararg call site
   836                 handle = ScriptRuntime.APPLY.methodHandle();
   837             } else {
   838                 // (callee, this, args...) => (callee, this, args[])
   839                 handle = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
   840             }
   842             // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
   843             // generic "is this a ScriptFunction?" guard.
   844             return new GuardedInvocation(
   845                     handle,
   846                     null,
   847                     (SwitchPoint) null,
   848                     ClassCastException.class);
   849         }
   851         MethodHandle boundHandle;
   852         MethodHandle guard = null;
   854         // Special handling of Function.apply and Function.call. Note we must be invoking
   855         if (isApplyOrCall && !isUnstable) {
   856             final Object[] args = request.getArguments();
   857             if (Bootstrap.isCallable(args[1])) {
   858                 return createApplyOrCallCall(isApply, desc, request, args);
   859             }
   860         } //else just fall through and link as ordinary function or unstable apply
   862         int programPoint = INVALID_PROGRAM_POINT;
   863         if (NashornCallSiteDescriptor.isOptimistic(desc)) {
   864             programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
   865         }
   867         CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
   868         final Object self = request.getArguments()[1];
   869         final Collection<CompiledFunction> forbidden = new HashSet<>();
   871         //check for special fast versions of the compiled function
   872         final List<SwitchPoint> sps = new ArrayList<>();
   873         Class<? extends Throwable> exceptionGuard = null;
   875         while (cf.isSpecialization()) {
   876             final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
   877             //if linklogic is null, we can always link with the standard mechanism, it's still a specialization
   878             final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
   880             if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
   881                 final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
   883                 if (log.isEnabled()) {
   884                     log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
   885                 }
   887                 exceptionGuard = linkLogic.getRelinkException();
   889                 break;
   890             }
   892             //could not link this specialization because link check failed
   893             forbidden.add(cf);
   894             final CompiledFunction oldCf = cf;
   895             cf = data.getBestInvoker(type, scope, forbidden);
   896             assert oldCf != cf;
   897         }
   899         final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
   900         final MethodHandle callHandle = bestInvoker.getInvocation();
   902         if (data.needsCallee()) {
   903             if (scopeCall && needsWrappedThis()) {
   904                 // (callee, this, args...) => (callee, [this], args...)
   905                 boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER);
   906             } else {
   907                 // It's already (callee, this, args...), just what we need
   908                 boundHandle = callHandle;
   909             }
   910         } else if (data.isBuiltin() && "extend".equals(data.getName())) {
   911             // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
   912             // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
   913             boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, type.parameterType(0), type.parameterType(1));
   914         } else if (scopeCall && needsWrappedThis()) {
   915             // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
   916             // (this, args...) => ([this], args...)
   917             boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER);
   918             // ([this], args...) => ([callee], [this], args...)
   919             boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0));
   920         } else {
   921             // (this, args...) => ([callee], this, args...)
   922             boundHandle = MH.dropArguments(callHandle, 0, type.parameterType(0));
   923         }
   925         // For non-strict functions, check whether this-object is primitive type.
   926         // If so add a to-object-wrapper argument filter.
   927         // Else install a guard that will trigger a relink when the argument becomes primitive.
   928         if (!scopeCall && needsWrappedThis()) {
   929             if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
   930                 boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
   931             } else {
   932                 guard = getNonStrictFunctionGuard(this);
   933             }
   934         }
   936         boundHandle = pairArguments(boundHandle, type);
   938         if (bestInvoker.getSwitchPoints() != null) {
   939             sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
   940         }
   941         final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
   943         return new GuardedInvocation(
   944                 boundHandle,
   945                 guard == null ?
   946                         getFunctionGuard(
   947                                 this,
   948                                 cf.getFlags()) :
   949                         guard,
   950                 spsArray,
   951                 exceptionGuard);
   952     }
   954     private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
   955         final MethodType descType = desc.getMethodType();
   956         final int paramCount = descType.parameterCount();
   957         if (descType.parameterType(paramCount - 1).isArray()) {
   958             // This is vararg invocation of apply or call. This can normally only happen when we do a recursive
   959             // invocation of createApplyOrCallCall (because we're doing apply-of-apply). In this case, create delegate
   960             // linkage by unpacking the vararg invocation and use pairArguments to introduce the necessary spreader.
   961             return createVarArgApplyOrCallCall(isApply, desc, request, args);
   962         }
   964         final boolean passesThis = paramCount > 2;
   965         final boolean passesArgs = paramCount > 3;
   966         final int realArgCount = passesArgs ? paramCount - 3 : 0;
   968         final Object appliedFn = args[1];
   969         final boolean appliedFnNeedsWrappedThis = needsWrappedThis(appliedFn);
   971         //box call back to apply
   972         CallSiteDescriptor appliedDesc = desc;
   973         final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
   974         //enough to change the proto switchPoint here
   976         final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
   977         final boolean isFailedApplyToCall = isApplyToCall && applyToCallSwitchPoint.hasBeenInvalidated();
   979         // R(apply|call, ...) => R(...)
   980         MethodType appliedType = descType.dropParameterTypes(0, 1);
   981         if (!passesThis) {
   982             // R() => R(this)
   983             appliedType = appliedType.insertParameterTypes(1, Object.class);
   984         } else if (appliedFnNeedsWrappedThis) {
   985             appliedType = appliedType.changeParameterType(1, Object.class);
   986         }
   988         /*
   989          * dropArgs is a synthetic method handle that contains any args that we need to
   990          * get rid of that come after the arguments array in the apply case. We adapt
   991          * the callsite to ask for 3 args only and then dropArguments on the method handle
   992          * to make it fit the extraneous args.
   993          */
   994         MethodType dropArgs = MH.type(void.class);
   995         if (isApply && !isFailedApplyToCall) {
   996             final int pc = appliedType.parameterCount();
   997             for (int i = 3; i < pc; i++) {
   998                 dropArgs = dropArgs.appendParameterTypes(appliedType.parameterType(i));
   999             }
  1000             if (pc > 3) {
  1001                 appliedType = appliedType.dropParameterTypes(3, pc);
  1005         if (isApply || isFailedApplyToCall) {
  1006             if (passesArgs) {
  1007                 // R(this, args) => R(this, Object[])
  1008                 appliedType = appliedType.changeParameterType(2, Object[].class);
  1009                 // drop any extraneous arguments for the apply fail case
  1010                 if (isFailedApplyToCall) {
  1011                     appliedType = appliedType.dropParameterTypes(3, paramCount - 1);
  1013             } else {
  1014                 // R(this) => R(this, Object[])
  1015                 appliedType = appliedType.insertParameterTypes(2, Object[].class);
  1019         appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
  1021         // Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
  1022         final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
  1023         appliedArgs[0] = appliedFn;
  1024         appliedArgs[1] = passesThis ? appliedFnNeedsWrappedThis ? ScriptFunctionData.wrapThis(args[2]) : args[2] : ScriptRuntime.UNDEFINED;
  1025         if (isApply && !isFailedApplyToCall) {
  1026             appliedArgs[2] = passesArgs ? NativeFunction.toApplyArgs(args[3]) : ScriptRuntime.EMPTY_ARRAY;
  1027         } else {
  1028             if (passesArgs) {
  1029                 if (isFailedApplyToCall) {
  1030                     final Object[] tmp = new Object[args.length - 3];
  1031                     System.arraycopy(args, 3, tmp, 0, tmp.length);
  1032                     appliedArgs[2] = NativeFunction.toApplyArgs(tmp);
  1033                 } else {
  1034                     assert !isApply;
  1035                     System.arraycopy(args, 3, appliedArgs, 2, args.length - 3);
  1037             } else if (isFailedApplyToCall) {
  1038                 appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
  1042         // Ask the linker machinery for an invocation of the target function
  1043         final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
  1045         GuardedInvocation appliedInvocation;
  1046         try {
  1047             appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
  1048         } catch (final RuntimeException | Error e) {
  1049             throw e;
  1050         } catch (final Exception e) {
  1051             throw new RuntimeException(e);
  1053         assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
  1055         final Class<?> applyFnType = descType.parameterType(0);
  1056         MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation
  1058         if (isApply && !isFailedApplyToCall) {
  1059             if (passesArgs) {
  1060                 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
  1061                 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
  1062             } else {
  1063                 // If the original call site doesn't pass argArray, pass in an empty array
  1064                 inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY);
  1068         if (isApplyToCall) {
  1069             if (isFailedApplyToCall) {
  1070                 //take the real arguments that were passed to a call and force them into the apply instead
  1071                 Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
  1072                 inv = MH.asCollector(inv, Object[].class, realArgCount);
  1073             } else {
  1074                 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
  1078         if (!passesThis) {
  1079             // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
  1080             inv = bindImplicitThis(appliedFn, inv);
  1081         } else if (appliedFnNeedsWrappedThis) {
  1082             // target function needs a wrapped this, so make sure we filter for that
  1083             inv = MH.filterArguments(inv, 1, WRAP_THIS);
  1085         inv = MH.dropArguments(inv, 0, applyFnType);
  1087         /*
  1088          * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
  1089          * is when we need to add arguments to the callsite to catch and ignore the synthetic
  1090          * extra args that someone has added to the command line.
  1091          */
  1092         for (int i = 0; i < dropArgs.parameterCount(); i++) {
  1093             inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
  1096         MethodHandle guard = appliedInvocation.getGuard();
  1097         // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one
  1098         if (!passesThis && guard.type().parameterCount() > 1) {
  1099             guard = bindImplicitThis(appliedFn, guard);
  1101         final MethodType guardType = guard.type();
  1103         // We need to account for the dropped (apply|call) function argument.
  1104         guard = MH.dropArguments(guard, 0, descType.parameterType(0));
  1105         // Take the "isApplyFunction" guard, and bind it to this function.
  1106         MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
  1107         // Adapt the guard to receive all the arguments that the original guard does.
  1108         applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
  1109         // Fold the original function guard into our apply guard.
  1110         guard = MH.foldArguments(applyFnGuard, guard);
  1112         return appliedInvocation.replaceMethods(inv, guard);
  1115     /*
  1116      * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity
  1117      * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with
  1118      * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method.
  1119      * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back
  1120      * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to
  1121      * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity
  1122      * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already
  1123      * solved by createApplyOrCallCall) non-vararg call site linking.
  1124      */
  1125     private GuardedInvocation createVarArgApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc,
  1126             final LinkRequest request, final Object[] args) {
  1127         final MethodType descType = desc.getMethodType();
  1128         final int paramCount = descType.parameterCount();
  1129         final Object[] varArgs = (Object[]) args[paramCount - 1];
  1130         // -1 'cause we're not passing the vararg array itself
  1131         final int copiedArgCount = args.length - 1;
  1132         final int varArgCount = varArgs.length;
  1134         // Spread arguments for the delegate createApplyOrCallCall invocation.
  1135         final Object[] spreadArgs = new Object[copiedArgCount + varArgCount];
  1136         System.arraycopy(args, 0, spreadArgs, 0, copiedArgCount);
  1137         System.arraycopy(varArgs, 0, spreadArgs, copiedArgCount, varArgCount);
  1139         // Spread call site descriptor for the delegate createApplyOrCallCall invocation. We drop vararg array and
  1140         // replace it with a list of Object.class.
  1141         final MethodType spreadType = descType.dropParameterTypes(paramCount - 1, paramCount).appendParameterTypes(
  1142                 Collections.<Class<?>>nCopies(varArgCount, Object.class));
  1143         final CallSiteDescriptor spreadDesc = desc.changeMethodType(spreadType);
  1145         // Delegate back to createApplyOrCallCall with the spread (that is, reverted to non-vararg) request/
  1146         final LinkRequest spreadRequest = request.replaceArguments(spreadDesc, spreadArgs);
  1147         final GuardedInvocation spreadInvocation = createApplyOrCallCall(isApply, spreadDesc, spreadRequest, spreadArgs);
  1149         // Add spreader combinators to returned invocation and guard.
  1150         return spreadInvocation.replaceMethods(
  1151                 // Use standard ScriptObject.pairArguments on the invocation
  1152                 pairArguments(spreadInvocation.getInvocation(), descType),
  1153                 // Use our specialized spreadGuardArguments on the guard (see below).
  1154                 spreadGuardArguments(spreadInvocation.getGuard(), descType));
  1157     private static MethodHandle spreadGuardArguments(final MethodHandle guard, final MethodType descType) {
  1158         final MethodType guardType = guard.type();
  1159         final int guardParamCount = guardType.parameterCount();
  1160         final int descParamCount = descType.parameterCount();
  1161         final int spreadCount = guardParamCount - descParamCount + 1;
  1162         if (spreadCount <= 0) {
  1163             // Guard doesn't dip into the varargs
  1164             return guard;
  1167         final MethodHandle arrayConvertingGuard;
  1168         // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
  1169         // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
  1170         // with ClassCastException of NativeArray to Object[].
  1171         if (guardType.parameterType(guardParamCount - 1).isArray()) {
  1172             arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
  1173         } else {
  1174             arrayConvertingGuard = guard;
  1177         return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount);
  1180     private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) {
  1181         final MethodHandle bound;
  1182         if (fn instanceof ScriptFunction && ((ScriptFunction) fn).needsWrappedThis()) {
  1183             bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
  1184         } else {
  1185             bound = mh;
  1187         return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
  1190     /**
  1191      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
  1193      * These don't want a callee parameter, so bind that. Name binding is
  1194      * optional.
  1195      */
  1196     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
  1197         return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
  1200     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
  1201         if (bindName == null) {
  1202             return methodHandle;
  1205         // if it is vararg method, we need to extend argument array with
  1206         // a new zeroth element that is set to bindName value.
  1207         final MethodType methodType = methodHandle.type();
  1208         final int parameterCount = methodType.parameterCount();
  1209         final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
  1211         if (isVarArg) {
  1212             return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
  1214         return MH.insertArguments(methodHandle, 1, bindName);
  1217     /**
  1218      * Get the guard that checks if a {@link ScriptFunction} is equal to a known
  1219      * ScriptFunction, using reference comparison
  1221      * @param function The ScriptFunction to check against. This will be bound
  1222      * to the guard method handle
  1224      * @return method handle for guard
  1225      */
  1226     private static MethodHandle getFunctionGuard(final ScriptFunction function, final int flags) {
  1227         assert function.data != null;
  1228         // Built-in functions have a 1-1 correspondence to their ScriptFunctionData, so we can use a cheaper identity
  1229         // comparison for them.
  1230         if (function.data.isBuiltin()) {
  1231             return Guards.getIdentityGuard(function);
  1233         return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
  1236     /**
  1237      * Get a guard that checks if a {@link ScriptFunction} is equal to a known
  1238      * ScriptFunction using reference comparison, and whether the type of the
  1239      * second argument (this-object) is not a JavaScript primitive type.
  1241      * @param function The ScriptFunction to check against. This will be bound
  1242      * to the guard method handle
  1244      * @return method handle for guard
  1245      */
  1246     private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
  1247         assert function.data != null;
  1248         return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
  1251     @SuppressWarnings("unused")
  1252     private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
  1253         return self instanceof ScriptFunction && ((ScriptFunction) self).data == data;
  1256     @SuppressWarnings("unused")
  1257     private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
  1258         return self instanceof ScriptFunction && ((ScriptFunction) self).data == data && arg instanceof ScriptObject;
  1261     //TODO this can probably be removed given that we have builtin switchpoints in the context
  1262     @SuppressWarnings("unused")
  1263     private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
  1264         // NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
  1265         return appliedFnCondition && self == expectedSelf;
  1268     @SuppressWarnings("unused")
  1269     private static Object[] addZerothElement(final Object[] args, final Object value) {
  1270         // extends input array with by adding new zeroth element
  1271         final Object[] src = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
  1272         final Object[] result = new Object[src.length + 1];
  1273         System.arraycopy(src, 0, result, 1, src.length);
  1274         result[0] = value;
  1275         return result;
  1278     @SuppressWarnings("unused")
  1279     private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
  1280             throws Throwable {
  1281         final Object syncObj = sync == UNDEFINED ? self : sync;
  1282         synchronized (syncObj) {
  1283             return func.invoke(self, args);
  1287     private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
  1288         return MH.findStatic(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
  1291     private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
  1292         return MH.findVirtual(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));

mercurial