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

Print this page




  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 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
  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.linker.Lookup.MH;
  32 
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import jdk.nashorn.internal.codegen.CompilerConstants.Call;

  37 import jdk.nashorn.internal.codegen.types.Type;
  38 import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
  39 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
  40 import jdk.nashorn.internal.parser.Token;
  41 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
  42 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  43 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  44 import jdk.nashorn.internal.runtime.options.Options;
  45 import org.dynalang.dynalink.CallSiteDescriptor;
  46 import org.dynalang.dynalink.linker.GuardedInvocation;
  47 import org.dynalang.dynalink.linker.LinkRequest;
  48 
  49 /**
  50  * Runtime representation of a JavaScript function.
  51  */
  52 public abstract class ScriptFunction extends ScriptObject {
  53 
  54     /** Method handle for prototype getter for this ScriptFunction */
  55     public static final MethodHandle G$PROTOTYPE  = findOwnMH("G$prototype",  Object.class, Object.class);
  56 
  57     /** Method handle for prototype setter for this ScriptFunction */
  58     public static final MethodHandle S$PROTOTYPE  = findOwnMH("S$prototype",  void.class, Object.class, Object.class);
  59 
  60     /** Method handle for length getter for this ScriptFunction */
  61     public static final MethodHandle G$LENGTH     = findOwnMH("G$length",     int.class, Object.class);
  62 
  63     /** Method handle for name getter for this ScriptFunction */
  64     public static final MethodHandle G$NAME       = findOwnMH("G$name",       Object.class, Object.class);
  65 
  66     /** Method handle for allocate function for this ScriptFunction */
  67     public static final MethodHandle ALLOCATE     = findOwnMH("allocate", Object.class);
  68 
  69     private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
  70 
  71     private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
  72 
  73     /** method handle to arity setter for this ScriptFunction */
  74     public static final Call SET_ARITY = virtualCallNoLookup(ScriptFunction.class, "setArity", void.class, int.class);
  75     /** method handle to scope getter for this ScriptFunction */
  76     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
  77 
  78     /** Should specialized function and specialized constructors for the builtin be used if available? */
  79     private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable");
  80 
  81     /** Name of function or null. */
  82     private final String name;
  83 
  84     /** Source of function. */
  85     private final Source source;
  86 
  87     /** Start position and length in source. */
  88     private final long token;
  89 
  90     /** Reference to code for this method. */
  91     private final MethodHandle invokeHandle;
  92 
  93     /** Reference to code for this method when called to create "new" object */
  94     protected MethodHandle constructHandle;






  95 
  96     /** Reference to constructor prototype. */
  97     protected Object prototype;
  98 
  99     /** Constructor to create a new instance. */
 100     private MethodHandle allocator;
 101 
 102     /** Map for new instance constructor. */
 103     private PropertyMap allocatorMap;
 104 
 105     /** The parent scope. */
 106     private final ScriptObject scope;
 107 
 108     /** Specializations - see @SpecializedFunction */
 109     private MethodHandle[] invokeSpecializations;
 110 
 111     /** Specializations - see @SpecializedFunction */
 112     private MethodHandle[] constructSpecializations;
 113 
 114     /** This field is either computed in constructor or set explicitly by calling setArity method. */
 115     private int arity;
 116 
 117     /**
 118      * Constructor
 119      *
 120      * @param name          function name
 121      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
 122      * @param map           property map
 123      * @param scope         scope
 124      * @param specs         specialized version of this function - other method handles
 125      */
 126     protected ScriptFunction(
 127             final String name,
 128             final MethodHandle methodHandle,
 129             final PropertyMap map,
 130             final ScriptObject scope,
 131             final MethodHandle[] specs) {
 132         this(name, methodHandle, map, scope, null, 0, needsCallee(methodHandle), specs);
 133     }
 134 
 135     /**
 136      * Heuristic to figure out if the method handle has a callee argument. If it's type is either
 137      * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has
 138      * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly
 139      * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
 140      * they also always receive a callee.
 141      * @param methodHandle the examined method handle
 142      * @return true if the method handle expects a callee, false otherwise
 143      */
 144     private static boolean needsCallee(MethodHandle methodHandle) {
 145         final MethodType type = methodHandle.type();
 146         final int len = type.parameterCount();
 147         if(len == 0) {
 148             return false;
 149         }
 150         if(type.parameterType(0) == boolean.class) {
 151             return len > 2 && type.parameterType(2) == ScriptFunction.class;
 152         }
 153         return len > 1 && type.parameterType(1) == ScriptFunction.class;
 154     }
 155 
 156     /**
 157      * Constructor
 158      *
 159      * @param name          function name
 160      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
 161      * @param map           property map
 162      * @param scope         scope
 163      * @param source        the source
 164      * @param token         token
 165      * @param allocator     method handle to this function's allocator - see JO$ classes
 166      * @param allocatorMap  property map to be used for all constructors
 167      * @param needsCallee   does this method use the {@code callee} variable
 168      * @param specs         specialized version of this function - other method handles
 169      */
 170     protected ScriptFunction(
 171             final String name,
 172             final MethodHandle methodHandle,
 173             final PropertyMap map,
 174             final ScriptObject scope,
 175             final Source source,
 176             final long token,
 177             final MethodHandle allocator,
 178             final PropertyMap allocatorMap,
 179             final boolean needsCallee,
 180             final MethodHandle[] specs) {

 181 
 182         this(name, methodHandle, map, scope, source, token, needsCallee, specs);




 183 
 184         //this is the internal constructor


 185 


 186         this.allocator    = allocator;
 187         this.allocatorMap = allocatorMap;
 188     }
 189 
 190     /**
 191      * Constructor
 192      *
 193      * @param name              function name
 194      * @param methodHandle      method handle to function (if specializations are present, assumed to be most generic)
 195      * @param map               property map
 196      * @param scope             scope
 197      * @param source            the source
 198      * @param token             token
 199      * @param needsCallee       does this method use the {@code callee} variable
 200      * @param specs             specialized version of this function - other method handles
 201      */
 202     protected ScriptFunction(
 203             final String name,
 204             final MethodHandle methodHandle,
 205             final PropertyMap map,
 206             final ScriptObject scope,
 207             final Source source,
 208             final long token,
 209             final boolean needsCallee,
 210             final MethodHandle[] specs) {
 211 
 212         super(map);
 213 
 214         if (Context.DEBUG) {
 215             constructorCount++;
 216         }
 217 
 218         this.name   = name;
 219         this.source = source;
 220         this.token  = token;
 221         this.scope  = scope;
 222         if(needsCallee) {
 223             setHasCalleeParameter();
 224         }
 225 
 226         final MethodType type       = methodHandle.type();
 227         final int        paramCount = type.parameterCount();
 228         final boolean    isVarArg   = type.parameterType(paramCount - 1).isArray();
 229 
 230         final MethodHandle mh = MH.asType(methodHandle, adaptType(type, needsCallee, isVarArg));
 231 
 232         this.arity = isVarArg ? -1 : paramCount - 1; //drop the self param for arity
 233 
 234         if (needsCallee && !isVarArg) {
 235             this.arity--;
 236         }
 237 
 238         if (scope != null) {
 239             this.invokeHandle    = mh;
 240             this.constructHandle = mh;
 241         } else if (isConstructor(mh)) {
 242             if (!isVarArg) {
 243                 this.arity--;    // drop the boolean flag for arity
 244             }
 245             /*
 246              * We insert a boolean argument to tell if the method was invoked as
 247              * constructor or not if the method handle's first argument is boolean.
 248              */
 249             this.invokeHandle    = MH.insertArguments(mh, 0, false);
 250             this.constructHandle = MH.insertArguments(mh, 0, true);
 251 
 252             if (specs != null) {
 253                 this.invokeSpecializations    = new MethodHandle[specs.length];
 254                 this.constructSpecializations = new MethodHandle[specs.length];
 255                 for (int i = 0; i < specs.length; i++) {
 256                     this.invokeSpecializations[i]    = MH.insertArguments(specs[i], 0, false);
 257                     this.constructSpecializations[i] = MH.insertArguments(specs[i], 0, true);
 258                 }
 259             }
 260         } else {
 261             this.invokeHandle             = mh;
 262             this.constructHandle          = mh;
 263             this.invokeSpecializations    = specs;
 264             this.constructSpecializations = specs;
 265         }
 266     }
 267 
 268     /**
 269      * Takes a method type, and returns a (potentially different method type) that the method handles used by
 270      * ScriptFunction must conform to in order to be usable in {@link #invoke(Object, Object...)} and
 271      * {@link #construct(Object, Object...)}. The returned method type will be sure to return {@code Object}, and will
 272      * have all its parameters turned into {@code Object} as well, except for the following ones:
 273      * <ul>
 274      * <li>an optional first {@code boolean} parameter, used for some functions to distinguish method and constructor
 275      * invocation,</li>
 276      * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
 277      * <li>the second (or, in presence of boolean parameter, third) argument, which is forced to be
 278      * {@link ScriptFunction}, in case the function receives itself (callee) as an argument</li>
 279      * @param type the original type
 280      * @param hasCallee true if the function uses the callee argument
 281      * @param isVarArg if the function is a vararg
 282      * @return the new type, conforming to the rules above.
 283      */
 284     private static MethodType adaptType(final MethodType type, final boolean hasCallee, final boolean isVarArg) {
 285         // Generify broadly
 286         MethodType newType = type.generic().changeReturnType(Object.class);
 287         if(isVarArg) {
 288             // Change back to vararg if we over-generified it
 289             newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
 290         }
 291         final boolean hasBoolean = type.parameterType(0) == boolean.class;
 292         if(hasBoolean) {
 293             // Restore the initial boolean argument
 294             newType = newType.changeParameterType(0, boolean.class);
 295         }
 296         if(hasCallee) {
 297             // Restore the ScriptFunction argument
 298             newType = newType.changeParameterType(hasBoolean ? 2 : 1, ScriptFunction.class);
 299         }
 300         return newType;
 301     }
 302 
 303     @Override
 304     public String getClassName() {
 305         return "Function";
 306     }
 307 
 308     /**
 309      * ECMA 15.3.5.3 [[HasInstance]] (V)
 310      * Step 3 if "prototype" value is not an Object, throw TypeError
 311      */
 312     @Override
 313     public boolean isInstance(final ScriptObject instance) {
 314         if (!(prototype instanceof ScriptObject)) {
 315             typeError("prototype.not.an.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(prototype));
 316         }
 317 
 318         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
 319             if (proto == prototype) {
 320                 return true;


 355     /**
 356      * Is this a non-strict and not-built-in script function?
 357      * @return true if neither strict nor built-in
 358      */
 359     public boolean isNonStrictFunction() {
 360         return !isStrict() && !isBuiltin();
 361     }
 362 
 363     /**
 364      * Execute this script function.
 365      * @param self  Target object.
 366      * @param arguments  Call arguments.
 367      * @return ScriptFunction result.
 368      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 369      */
 370     public Object invoke(final Object self, final Object... arguments) throws Throwable {
 371         if (Context.DEBUG) {
 372             invokes++;
 373         }
 374 




 375         final Object selfObj = convertThisObject(self);
 376         final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 377 
 378         if (isVarArg(invokeHandle)) {
 379             if (hasCalleeParameter()) {
 380                 return invokeHandle.invokeExact(selfObj, this, args);
 381             }
 382             return invokeHandle.invokeExact(selfObj, args);
 383         }
 384 
 385         final int paramCount = invokeHandle.type().parameterCount();
 386         if (hasCalleeParameter()) {
 387             switch (paramCount) {
 388             case 2:
 389                 return invokeHandle.invokeExact(selfObj, this);
 390             case 3:
 391                 return invokeHandle.invokeExact(selfObj, this, getArg(args, 0));
 392             case 4:
 393                 return invokeHandle.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1));
 394             case 5:
 395                 return invokeHandle.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 396             default:
 397                 return invokeHandle.invokeWithArguments(withArguments(selfObj, this, paramCount, args));
 398             }
 399         }
 400 
 401         switch (paramCount) {
 402         case 1:
 403             return invokeHandle.invokeExact(selfObj);
 404         case 2:
 405             return invokeHandle.invokeExact(selfObj, getArg(args, 0));
 406         case 3:
 407             return invokeHandle.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
 408         case 4:
 409             return invokeHandle.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 410         default:
 411             return invokeHandle.invokeWithArguments(withArguments(selfObj, null, paramCount, args));
 412         }
 413     }
 414 
 415     private static Object getArg(final Object[] args, final int i) {
 416         return i < args.length ? args[i] : UNDEFINED;
 417     }
 418 
 419     /**
 420      * Construct new object using this constructor.
 421      * @param self  Target object.
 422      * @param args  Call arguments.
 423      * @return ScriptFunction result.
 424      * @throws Throwable if there is an exception/error with the constructor invocation or thrown from it
 425      */
 426     public Object construct(final Object self, final Object... args) throws Throwable {
 427         if (constructHandle == null) {
 428             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 429         }
 430 
 431         if (isVarArg(constructHandle)) {



 432             if (hasCalleeParameter()) {
 433                 return constructHandle.invokeExact(self, this, args);
 434             }
 435             return constructHandle.invokeExact(self, args);
 436         }
 437 
 438         final int paramCount = constructHandle.type().parameterCount();
 439         if (hasCalleeParameter()) {
 440             switch (paramCount) {
 441             case 2:
 442                 return constructHandle.invokeExact(self, this);
 443             case 3:
 444                 return constructHandle.invokeExact(self, this, getArg(args, 0));
 445             case 4:
 446                 return constructHandle.invokeExact(self, this, getArg(args, 0), getArg(args, 1));
 447             case 5:
 448                 return constructHandle.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 449             default:
 450                 return constructHandle.invokeWithArguments(withArguments(self, this, args));
 451             }
 452         }
 453 
 454         switch(paramCount) {
 455         case 1:
 456             return constructHandle.invokeExact(self);
 457         case 2:
 458             return constructHandle.invokeExact(self, getArg(args, 0));
 459         case 3:
 460             return constructHandle.invokeExact(self, getArg(args, 0), getArg(args, 1));
 461         case 4:
 462             return constructHandle.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 463         default:
 464             return constructHandle.invokeWithArguments(withArguments(self, null, args));
 465         }
 466     }
 467 
 468     private static Object[] withArguments(final Object self, final ScriptFunction function, final Object... args) {
 469         return withArguments(self, function, args.length + (function == null ? 1 : 2), args); // + 2 to include self and function
 470     }
 471 
 472     private static Object[] withArguments(final Object self, final ScriptFunction function, final int paramCount, final Object... args) {
 473         final Object[] finalArgs = new Object[paramCount];
 474 
 475         finalArgs[0] = self;
 476         int nextArg = 1;
 477         if (function != null) {
 478             finalArgs[nextArg++] = function;
 479         }
 480 
 481         //don't add more args that there is paramcount in the handle (including self)
 482         final int maxArgs = Math.min(args.length, paramCount - (function == null ? 1 : 2));
 483         for (int i = 0; i < maxArgs;) {
 484             finalArgs[nextArg++] = args[i++];


 560      * @param methodHandle MethodHandle to test.
 561      * @return True if variable arguments.
 562      */
 563     public boolean isVarArg(final MethodHandle methodHandle) {
 564         return hasCalleeParameter()
 565                 ? methodHandle.type().parameterCount() == 3 && methodHandle.type().parameterType(2).isArray()
 566                 : methodHandle.type().parameterCount() == 2 && methodHandle.type().parameterType(1).isArray();
 567     }
 568 
 569     @Override
 570     public final String safeToString() {
 571         return toSource();
 572     }
 573 
 574     @Override
 575     public String toString() {
 576         final StringBuilder sb = new StringBuilder();
 577 
 578         sb.append(super.toString())
 579             .append(" [ ")
 580             .append(invokeHandle)
 581             .append(", ")
 582             .append((name == null || name.isEmpty()) ? "<anonymous>" : name);
 583 
 584         if (source != null) {
 585             sb.append(" @ ")
 586                .append(source.getName())
 587                .append(':')
 588                .append(source.getLine(Token.descPosition(token)));
 589         }
 590         sb.append(" ]");
 591 
 592         return sb.toString();
 593     }
 594 
 595     /**
 596      * Get this function as a String containing its source code. If no source code
 597      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 598      * @return string representation of this function's source
 599      */
 600     public final String toSource() {


 689 
 690         return candidate;
 691     }
 692 
 693     /**
 694      * Return the most appropriate invoke handle if there are specializations
 695      * @param type most specific method type to look for invocation with
 696      * @return invoke method handle
 697      */
 698     public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) {
 699         return candidateWithLowestWeight(type, getInvokeHandle(), invokeSpecializations);
 700     }
 701 
 702     /**
 703      * Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
 704      * method handle for this ScriptFunction
 705      * @see SpecializedFunction
 706      * @return invokeHandle
 707      */
 708     public final MethodHandle getInvokeHandle() {
 709         return invokeHandle;
 710     }
 711 
 712     /**
 713      * Return the invoke handle bound to a given ScriptObject self reference.
 714      * If callee parameter is required result is rebound to this.
 715      *
 716      * @param self self reference
 717      * @return bound invoke handle
 718      */
 719     public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
 720         final MethodHandle bound = MH.bindTo(getInvokeHandle(), self);
 721         return hasCalleeParameter() ? MH.bindTo(bound, this) : bound;
 722     }
 723 
 724     protected abstract boolean hasCalleeParameter();
 725     protected abstract void setHasCalleeParameter();
 726 
 727     /**
 728      * Get the construct handle - the most generic (and if no specializations are in place, only) constructor
 729      * method handle for this ScriptFunction
 730      * @see SpecializedConstructor
 731      * @param type type for wanted constructor
 732      * @return construct handle
 733      */
 734     public final MethodHandle getConstructHandle(final MethodType type) {
 735         return candidateWithLowestWeight(type, getConstructHandle(), constructSpecializations);
 736     }
 737 
 738     /**
 739      * Get a method handle to the constructor for this function
 740      * @return constructor handle
 741      */
 742     public final MethodHandle getConstructHandle() {
 743         return constructHandle;
 744     }
 745 
 746     /**
 747      * Set a method handle to the constructor for this function
 748      * @param constructHandle constructor handle
 749      */
 750     public final void setConstructHandle(final MethodHandle constructHandle) {
 751         this.constructHandle = constructHandle;
 752         this.constructSpecializations = null;
 753     }
 754 
 755     /**
 756      * Get the name for this function
 757      * @return the name
 758      */
 759     public final String getName() {
 760         return name;
 761     }
 762 
 763     /**
 764      * Does this script function need to be compiled. This determined by
 765      * null checking invokeHandle
 766      *
 767      * @return true if this needs compilation
 768      */
 769     public final boolean needsCompilation() {
 770         return invokeHandle == null;
 771     }
 772 
 773     /**
 774      * Get token for this function
 775      * @return token
 776      */
 777     public final long getToken() {
 778         return token;
 779     }
 780 
 781     /**
 782      * Get the scope for this function
 783      * @return the scope
 784      */
 785     public final ScriptObject getScope() {
 786         return scope;
 787     }
 788 
 789     /**
 790      * Prototype getter for this ScriptFunction - follows the naming convention




  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 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
  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.linker.Lookup.MH;
  32 
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
  37 import jdk.nashorn.internal.codegen.ScriptFunctionData;
  38 import jdk.nashorn.internal.codegen.types.Type;
  39 import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
  40 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
  41 import jdk.nashorn.internal.parser.Token;
  42 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
  43 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  44 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  45 import jdk.nashorn.internal.runtime.options.Options;
  46 import org.dynalang.dynalink.CallSiteDescriptor;
  47 import org.dynalang.dynalink.linker.GuardedInvocation;
  48 import org.dynalang.dynalink.linker.LinkRequest;
  49 
  50 /**
  51  * Runtime representation of a JavaScript function.
  52  */
  53 public abstract class ScriptFunction extends ScriptObject {
  54 
  55     /** Method handle for prototype getter for this ScriptFunction */
  56     public static final MethodHandle G$PROTOTYPE  = findOwnMH("G$prototype",  Object.class, Object.class);
  57 
  58     /** Method handle for prototype setter for this ScriptFunction */
  59     public static final MethodHandle S$PROTOTYPE  = findOwnMH("S$prototype",  void.class, Object.class, Object.class);
  60 
  61     /** Method handle for length getter for this ScriptFunction */
  62     public static final MethodHandle G$LENGTH     = findOwnMH("G$length",     int.class, Object.class);
  63 
  64     /** Method handle for name getter for this ScriptFunction */
  65     public static final MethodHandle G$NAME       = findOwnMH("G$name",       Object.class, Object.class);
  66 
  67     /** Method handle for allocate function for this ScriptFunction */
  68     public static final MethodHandle ALLOCATE     = findOwnMH("allocate", Object.class);
  69 
  70     private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
  71 
  72     private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
  73 


  74     /** method handle to scope getter for this ScriptFunction */
  75     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
  76 
  77     /** Should specialized function and specialized constructors for the builtin be used if available? */
  78     private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable");
  79 
  80     /** Name of function or null. */
  81     private final String name;
  82 
  83     /** Source of function. */
  84     private final Source source;
  85 
  86     /** Start position and length in source. */
  87     private final long token;
  88 
  89     /** Reference to code for this method. */
  90     private final MethodHandle invoker;
  91 
  92     /** Reference to code for this method when called to create "new" object */
  93     protected MethodHandle constructor;
  94 
  95     /** Generic invoker to used in {@link #invoke(Object, Object...)}. */
  96     private MethodHandle genericInvoker;
  97 
  98     /** Generic constructor used in {@link #construct(Object, Object...)}. */
  99     private MethodHandle genericConstructor;
 100 
 101     /** Reference to constructor prototype. */
 102     protected Object prototype;
 103 
 104     /** Constructor to create a new instance. */
 105     private MethodHandle allocator;
 106 
 107     /** Map for new instance constructor. */
 108     private PropertyMap allocatorMap;
 109 
 110     /** The parent scope. */
 111     private final ScriptObject scope;
 112 
 113     /** Specializations - see @SpecializedFunction */
 114     private MethodHandle[] invokeSpecializations;
 115 
 116     /** Specializations - see @SpecializedFunction */
 117     private MethodHandle[] constructSpecializations;
 118 
 119     /** This field is either computed in constructor or set explicitly by calling setArity method. */
 120     private int arity;
 121 
 122     /**
 123      * Constructor
 124      *
 125      * @param name          function name
 126      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
 127      * @param map           property map
 128      * @param scope         scope
 129      * @param specs         specialized version of this function - other method handles
 130      */
 131     protected ScriptFunction(
 132             final String name,
 133             final MethodHandle methodHandle,
 134             final PropertyMap map,
 135             final ScriptObject scope,
 136             final MethodHandle[] specs) {
 137         this(name, methodHandle, map, scope, needsCallee(methodHandle), specs);
 138     }
 139 
 140     /**
 141      * Heuristic to figure out if the method handle has a callee argument. If it's type is either
 142      * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has
 143      * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly
 144      * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
 145      * they also always receive a callee.
 146      * @param methodHandle the examined method handle
 147      * @return true if the method handle expects a callee, false otherwise
 148      */
 149     private static boolean needsCallee(MethodHandle methodHandle) {
 150         final MethodType type = methodHandle.type();
 151         final int len = type.parameterCount();
 152         if(len == 0) {
 153             return false;
 154         }
 155         if(type.parameterType(0) == boolean.class) {
 156             return len > 2 && type.parameterType(2) == ScriptFunction.class;
 157         }
 158         return len > 1 && type.parameterType(1) == ScriptFunction.class;
 159     }
 160 
 161     /**
 162      * Constructor
 163      *
 164      * @param data          static function data
 165      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
 166      * @param map           property map
 167      * @param scope         scope


 168      * @param allocator     method handle to this function's allocator - see JO$ classes



 169      */
 170     protected ScriptFunction(
 171             final ScriptFunctionData data,
 172             final MethodHandle methodHandle,
 173             final PropertyMap map,
 174             final ScriptObject scope,
 175             final MethodHandle allocator) {
 176 
 177         super(map);
 178 
 179         if (Context.DEBUG) {
 180             constructorCount++;
 181         }
 182 
 183         this.name   = data.getName();
 184         this.source = data.getSource();
 185         this.token  = data.getToken();
 186         this.arity  = data.getArity();
 187         this.scope  = scope;
 188 
 189         if(data.needsCallee()) {
 190             setHasCalleeParameter();
 191         }
 192 
 193         this.invoker      = methodHandle;
 194         this.constructor  = methodHandle;
 195         this.allocator    = allocator;
 196         this.allocatorMap = data.getAllocatorMap();
 197     }
 198 
 199     /**
 200      * Constructor
 201      *
 202      * @param name              function name
 203      * @param methodHandle      method handle to function (if specializations are present, assumed to be most generic)
 204      * @param map               property map
 205      * @param scope             scope


 206      * @param needsCallee       does this method use the {@code callee} variable
 207      * @param specs             specialized version of this function - other method handles
 208      */
 209     protected ScriptFunction(
 210             final String name,
 211             final MethodHandle methodHandle,
 212             final PropertyMap map,
 213             final ScriptObject scope,


 214             final boolean needsCallee,
 215             final MethodHandle[] specs) {
 216 
 217         super(map);
 218 
 219         if (Context.DEBUG) {
 220             constructorCount++;
 221         }
 222 
 223         this.name   = name;
 224         this.source = null;
 225         this.token  = 0;
 226         this.scope  = scope;
 227         if(needsCallee) {
 228             setHasCalleeParameter();
 229         }
 230 
 231         final MethodType type       = methodHandle.type();
 232         final int        paramCount = type.parameterCount();
 233         final boolean    isVarArg   = type.parameterType(paramCount - 1).isArray();
 234 


 235         this.arity = isVarArg ? -1 : paramCount - 1; //drop the self param for arity
 236 
 237         if (needsCallee && !isVarArg) {
 238             this.arity--;
 239         }
 240 
 241         if (isConstructor(methodHandle)) {



 242             if (!isVarArg) {
 243                 this.arity--;    // drop the boolean flag for arity
 244             }
 245             /*
 246              * We insert a boolean argument to tell if the method was invoked as
 247              * constructor or not if the method handle's first argument is boolean.
 248              */
 249             this.invoker     = MH.insertArguments(methodHandle, 0, false);
 250             this.constructor = MH.insertArguments(methodHandle, 0, true);
 251 
 252             if (specs != null) {
 253                 this.invokeSpecializations    = new MethodHandle[specs.length];
 254                 this.constructSpecializations = new MethodHandle[specs.length];
 255                 for (int i = 0; i < specs.length; i++) {
 256                     this.invokeSpecializations[i]    = MH.insertArguments(specs[i], 0, false);
 257                     this.constructSpecializations[i] = MH.insertArguments(specs[i], 0, true);
 258                 }
 259             }
 260         } else {
 261             this.invoker                  = methodHandle;
 262             this.constructor              = methodHandle;
 263             this.invokeSpecializations    = specs;
 264             this.constructSpecializations = specs;
 265         }
 266     }
 267 
 268     /**
 269      * Takes a method handle, and returns a potentially different method handle that can be used in
 270      * {@link #invoke(Object, Object...)} or {@link #construct(Object, Object...)}. The returned method handle
 271      * will be sure to return {@code Object}, and will have all its parameters turned into {@code Object} as well,
 272      * except for the following ones:
 273      * <ul>


 274      *   <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
 275      *   <li>the second argument, which is forced to be {@link ScriptFunction}, in case the function receives itself
 276      *   (callee) as an argument</li>
 277      * </ul>
 278      *
 279      * @param handle the original method handle
 280      * @return the new handle, conforming to the rules above.
 281      */
 282     private MethodHandle adaptMethodType(final MethodHandle handle) {
 283         final MethodType type = handle.type();
 284         MethodType newType = type.generic();
 285         if (isVarArg(handle)) {

 286             newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
 287         }
 288         if (hasCalleeParameter()) {
 289             newType = newType.changeParameterType(1, ScriptFunction.class);






 290         }
 291         return type.equals(newType) ? handle : handle.asType(newType);
 292     }
 293 
 294     @Override
 295     public String getClassName() {
 296         return "Function";
 297     }
 298 
 299     /**
 300      * ECMA 15.3.5.3 [[HasInstance]] (V)
 301      * Step 3 if "prototype" value is not an Object, throw TypeError
 302      */
 303     @Override
 304     public boolean isInstance(final ScriptObject instance) {
 305         if (!(prototype instanceof ScriptObject)) {
 306             typeError("prototype.not.an.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(prototype));
 307         }
 308 
 309         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
 310             if (proto == prototype) {
 311                 return true;


 346     /**
 347      * Is this a non-strict and not-built-in script function?
 348      * @return true if neither strict nor built-in
 349      */
 350     public boolean isNonStrictFunction() {
 351         return !isStrict() && !isBuiltin();
 352     }
 353 
 354     /**
 355      * Execute this script function.
 356      * @param self  Target object.
 357      * @param arguments  Call arguments.
 358      * @return ScriptFunction result.
 359      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 360      */
 361     public Object invoke(final Object self, final Object... arguments) throws Throwable {
 362         if (Context.DEBUG) {
 363             invokes++;
 364         }
 365 
 366         if (genericInvoker == null) {
 367             genericInvoker = adaptMethodType(invoker);
 368         }
 369 
 370         final Object selfObj = convertThisObject(self);
 371         final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 372 
 373         if (isVarArg(genericInvoker)) {
 374             if (hasCalleeParameter()) {
 375                 return genericInvoker.invokeExact(selfObj, this, args);
 376             }
 377             return genericInvoker.invokeExact(selfObj, args);
 378         }
 379 
 380         final int paramCount = genericInvoker.type().parameterCount();
 381         if (hasCalleeParameter()) {
 382             switch (paramCount) {
 383             case 2:
 384                 return genericInvoker.invokeExact(selfObj, this);
 385             case 3:
 386                 return genericInvoker.invokeExact(selfObj, this, getArg(args, 0));
 387             case 4:
 388                 return genericInvoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1));
 389             case 5:
 390                 return genericInvoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 391             default:
 392                 return genericInvoker.invokeWithArguments(withArguments(selfObj, this, paramCount, args));
 393             }
 394         }
 395 
 396         switch (paramCount) {
 397         case 1:
 398             return genericInvoker.invokeExact(selfObj);
 399         case 2:
 400             return genericInvoker.invokeExact(selfObj, getArg(args, 0));
 401         case 3:
 402             return genericInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
 403         case 4:
 404             return genericInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 405         default:
 406             return genericInvoker.invokeWithArguments(withArguments(selfObj, null, paramCount, args));
 407         }
 408     }
 409 
 410     private static Object getArg(final Object[] args, final int i) {
 411         return i < args.length ? args[i] : UNDEFINED;
 412     }
 413 
 414     /**
 415      * Construct new object using this constructor.
 416      * @param self  Target object.
 417      * @param args  Call arguments.
 418      * @return ScriptFunction result.
 419      * @throws Throwable if there is an exception/error with the constructor invocation or thrown from it
 420      */
 421     public Object construct(final Object self, final Object... args) throws Throwable {
 422         if (constructor == null) {
 423             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 424         }
 425 
 426         if (genericConstructor == null) {
 427             genericConstructor = adaptMethodType(constructor);
 428         }
 429         if (isVarArg(genericConstructor)) {
 430             if (hasCalleeParameter()) {
 431                 return genericConstructor.invokeExact(self, this, args);
 432             }
 433             return genericConstructor.invokeExact(self, args);
 434         }
 435 
 436         final int paramCount = genericConstructor.type().parameterCount();
 437         if (hasCalleeParameter()) {
 438             switch (paramCount) {
 439             case 2:
 440                 return genericConstructor.invokeExact(self, this);
 441             case 3:
 442                 return genericConstructor.invokeExact(self, this, getArg(args, 0));
 443             case 4:
 444                 return genericConstructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1));
 445             case 5:
 446                 return genericConstructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 447             default:
 448                 return genericConstructor.invokeWithArguments(withArguments(self, this, args));
 449             }
 450         }
 451 
 452         switch(paramCount) {
 453         case 1:
 454             return genericConstructor.invokeExact(self);
 455         case 2:
 456             return genericConstructor.invokeExact(self, getArg(args, 0));
 457         case 3:
 458             return genericConstructor.invokeExact(self, getArg(args, 0), getArg(args, 1));
 459         case 4:
 460             return genericConstructor.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 461         default:
 462             return genericConstructor.invokeWithArguments(withArguments(self, null, args));
 463         }
 464     }
 465 
 466     private static Object[] withArguments(final Object self, final ScriptFunction function, final Object... args) {
 467         return withArguments(self, function, args.length + (function == null ? 1 : 2), args); // + 2 to include self and function
 468     }
 469 
 470     private static Object[] withArguments(final Object self, final ScriptFunction function, final int paramCount, final Object... args) {
 471         final Object[] finalArgs = new Object[paramCount];
 472 
 473         finalArgs[0] = self;
 474         int nextArg = 1;
 475         if (function != null) {
 476             finalArgs[nextArg++] = function;
 477         }
 478 
 479         //don't add more args that there is paramcount in the handle (including self)
 480         final int maxArgs = Math.min(args.length, paramCount - (function == null ? 1 : 2));
 481         for (int i = 0; i < maxArgs;) {
 482             finalArgs[nextArg++] = args[i++];


 558      * @param methodHandle MethodHandle to test.
 559      * @return True if variable arguments.
 560      */
 561     public boolean isVarArg(final MethodHandle methodHandle) {
 562         return hasCalleeParameter()
 563                 ? methodHandle.type().parameterCount() == 3 && methodHandle.type().parameterType(2).isArray()
 564                 : methodHandle.type().parameterCount() == 2 && methodHandle.type().parameterType(1).isArray();
 565     }
 566 
 567     @Override
 568     public final String safeToString() {
 569         return toSource();
 570     }
 571 
 572     @Override
 573     public String toString() {
 574         final StringBuilder sb = new StringBuilder();
 575 
 576         sb.append(super.toString())
 577             .append(" [ ")
 578             .append(invoker)
 579             .append(", ")
 580             .append((name == null || name.isEmpty()) ? "<anonymous>" : name);
 581 
 582         if (source != null) {
 583             sb.append(" @ ")
 584                .append(source.getName())
 585                .append(':')
 586                .append(source.getLine(Token.descPosition(token)));
 587         }
 588         sb.append(" ]");
 589 
 590         return sb.toString();
 591     }
 592 
 593     /**
 594      * Get this function as a String containing its source code. If no source code
 595      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 596      * @return string representation of this function's source
 597      */
 598     public final String toSource() {


 687 
 688         return candidate;
 689     }
 690 
 691     /**
 692      * Return the most appropriate invoke handle if there are specializations
 693      * @param type most specific method type to look for invocation with
 694      * @return invoke method handle
 695      */
 696     public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) {
 697         return candidateWithLowestWeight(type, getInvokeHandle(), invokeSpecializations);
 698     }
 699 
 700     /**
 701      * Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
 702      * method handle for this ScriptFunction
 703      * @see SpecializedFunction
 704      * @return invokeHandle
 705      */
 706     public final MethodHandle getInvokeHandle() {
 707         return invoker;
 708     }
 709 
 710     /**
 711      * Return the invoke handle bound to a given ScriptObject self reference.
 712      * If callee parameter is required result is rebound to this.
 713      *
 714      * @param self self reference
 715      * @return bound invoke handle
 716      */
 717     public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
 718         final MethodHandle bound = MH.bindTo(getInvokeHandle(), self);
 719         return hasCalleeParameter() ? MH.bindTo(bound, this) : bound;
 720     }
 721 
 722     protected abstract boolean hasCalleeParameter();
 723     protected abstract void setHasCalleeParameter();
 724 
 725     /**
 726      * Get the construct handle - the most generic (and if no specializations are in place, only) constructor
 727      * method handle for this ScriptFunction
 728      * @see SpecializedConstructor
 729      * @param type type for wanted constructor
 730      * @return construct handle
 731      */
 732     public final MethodHandle getConstructHandle(final MethodType type) {
 733         return candidateWithLowestWeight(type, getConstructHandle(), constructSpecializations);
 734     }
 735 
 736     /**
 737      * Get a method handle to the constructor for this function
 738      * @return constructor handle
 739      */
 740     public final MethodHandle getConstructHandle() {
 741         return constructor;
 742     }
 743 
 744     /**
 745      * Set a method handle to the constructor for this function
 746      * @param constructHandle constructor handle
 747      */
 748     public final void setConstructHandle(final MethodHandle constructHandle) {
 749         this.constructor = constructHandle;
 750         this.constructSpecializations = null;
 751     }
 752 
 753     /**
 754      * Get the name for this function
 755      * @return the name
 756      */
 757     public final String getName() {
 758         return name;
 759     }
 760 
 761     /**
 762      * Does this script function need to be compiled. This determined by
 763      * null checking invokeHandle
 764      *
 765      * @return true if this needs compilation
 766      */
 767     public final boolean needsCompilation() {
 768         return invoker == null;
 769     }
 770 
 771     /**
 772      * Get token for this function
 773      * @return token
 774      */
 775     public final long getToken() {
 776         return token;
 777     }
 778 
 779     /**
 780      * Get the scope for this function
 781      * @return the scope
 782      */
 783     public final ScriptObject getScope() {
 784         return scope;
 785     }
 786 
 787     /**
 788      * Prototype getter for this ScriptFunction - follows the naming convention