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

Print this page




  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;
 321             }
 322         }
 323 
 324         return false;
 325     }
 326 
 327     /**
 328      * Get the arity of this ScriptFunction
 329      * @return arity
 330      */
 331     public final int getArity() {
 332         return arity;
 333     }
 334 
 335     /**
 336      * Set the arity of this ScriptFunction
 337      * @param arity arity
 338      */
 339     public final void setArity(final int arity) {
 340         this.arity = arity;
 341     }
 342 
 343     /**
 344      * Is this a ECMAScript 'use strict' function?
 345      * @return true if function is in strict mode
 346      */
 347     public abstract boolean isStrict();


 348 
 349     /**
 350      * Is this a ECMAScript built-in function (like parseInt, Array.isArray) ?
 351      * @return true if built-in
 352      */
 353     public abstract boolean isBuiltin();


 354 
 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++];


 492         return finalArgs;
 493     }
 494 
 495     /**
 496      * Allocate function. Called from generated {@link ScriptObject} code
 497      * for allocation as a factory method
 498      *
 499      * @return a new instance of the {@link ScriptObject} whose allocator this is
 500      */
 501     public Object allocate() {
 502         if (Context.DEBUG) {
 503             allocations++;
 504         }
 505 
 506         if (getConstructHandle() == null) {
 507             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 508         }
 509 
 510         ScriptObject object = null;
 511 
 512         if (allocator != null) {
 513             try {
 514                 object = (ScriptObject)allocator.invokeExact(allocatorMap);
 515             } catch (final RuntimeException | Error e) {
 516                 throw e;
 517             } catch (final Throwable t) {
 518                 throw new RuntimeException(t);
 519             }
 520         }
 521 
 522         if (object != null) {
 523             if (prototype instanceof ScriptObject) {
 524                 object.setProto((ScriptObject)prototype);
 525             }
 526 
 527             if (object.getProto() == null) {
 528                 object.setProto(getObjectPrototype());
 529             }
 530         }
 531 
 532         return object;
 533     }
 534 
 535     /**
 536      * Return Object.prototype - used by "allocate"
 537      * @return Object.prototype
 538      */
 539     protected abstract ScriptObject getObjectPrototype();
 540 
 541     /**
 542      * Creates a version of this function bound to a specific "self" and other argumentss
 543      * @param self the self to bind the function to
 544      * @param args other arguments (beside self) to bind the function to
 545      * @return the bound function
 546      */
 547     public abstract ScriptFunction makeBoundFunction(Object self, Object[] args);
 548 
 549     /**
 550      * Test if a methodHandle refers to a constructor.
 551      * @param methodHandle MethodHandle to test.
 552      * @return True if method is a constructor.
 553      */
 554     private static boolean isConstructor(final MethodHandle methodHandle) {
 555         return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class;
 556     }
 557 
 558     /**
 559      * Test if a methodHandle refers to a variable argument method.
 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() {
 601         if (source != null && token != 0) {
 602             return source.getString(Token.descPosition(token), Token.descLength(token));
 603         }
 604 
 605         return "function " + (name == null ? "" : name) + "() { [native code] }";
 606     }
 607 
 608     /**
 609      * Get the prototype object for this function
 610      * @return prototype
 611      */
 612     public final Object getPrototype() {
 613         return prototype;
 614     }
 615 
 616     /**
 617      * Set the prototype object for this function
 618      * @param prototype new prototype object
 619      * @return the prototype parameter
 620      */
 621     public final Object setPrototype(final Object prototype) {
 622         this.prototype = prototype;
 623         return prototype;
 624     }
 625 


 679             final int specWeight = weigh(specType);
 680             if (specWeight < minimumWeight) {
 681                 candidate = spec;
 682                 minimumWeight = specWeight;
 683             }
 684         }
 685 
 686         if (DISABLE_SPECIALIZATION && candidate != initialCandidate) {
 687             Context.err("### Specializing builtin " + getName() + " -> " + candidate + "?");
 688         }
 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     /**
 725      * Check whether the ScriptFunction has callee parameter
 726      * @return true if callee parameter
 727      */
 728     protected abstract boolean hasCalleeParameter();
 729 
 730     /**
 731      * Flag ScriptFunction as needing a callee parameter
 732      */
 733     protected abstract void setHasCalleeParameter();
 734 
 735     /**
 736      * Get the construct handle - the most generic (and if no specializations are in place, only) constructor
 737      * method handle for this ScriptFunction
 738      * @see SpecializedConstructor
 739      * @param type type for wanted constructor
 740      * @return construct handle
 741      */
 742     public final MethodHandle getConstructHandle(final MethodType type) {
 743         return candidateWithLowestWeight(type, getConstructHandle(), constructSpecializations);
 744     }
 745 
 746     /**
 747      * Get a method handle to the constructor for this function
 748      * @return constructor handle
 749      */
 750     public final MethodHandle getConstructHandle() {
 751         return constructHandle;
 752     }
 753 
 754     /**
 755      * Set a method handle to the constructor for this function
 756      * @param constructHandle constructor handle
 757      */
 758     public final void setConstructHandle(final MethodHandle constructHandle) {
 759         this.constructHandle = constructHandle;
 760         this.constructSpecializations = null;
 761     }
 762 
 763     /**
 764      * Get the name for this function
 765      * @return the name
 766      */
 767     public final String getName() {
 768         return name;
 769     }
 770 
 771     /**
 772      * Does this script function need to be compiled. This determined by
 773      * null checking invokeHandle
 774      *
 775      * @return true if this needs compilation
 776      */
 777     public final boolean needsCompilation() {
 778         return invokeHandle == null;
 779     }
 780 
 781     /**
 782      * Get token for this function
 783      * @return token
 784      */
 785     public final long getToken() {
 786         return token;
 787     }
 788 
 789     /**
 790      * Get the scope for this function
 791      * @return the scope
 792      */
 793     public final ScriptObject getScope() {
 794         return scope;
 795     }
 796 
 797     /**
 798      * Prototype getter for this ScriptFunction - follows the naming convention
 799      * used by Nasgen and the code generator
 800      *
 801      * @param self  self reference
 802      * @return self's prototype
 803      */
 804     public static Object G$prototype(final Object self) {
 805         return (self instanceof ScriptFunction) ?
 806             ((ScriptFunction)self).getPrototype() :


 890 
 891     @Override
 892     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
 893         final MethodType type = desc.getMethodType();
 894         MethodHandle constructor = getConstructHandle(type);
 895 
 896         if (constructor == null) {
 897             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 898             return null;
 899         }
 900 
 901         final MethodType ctorType = constructor.type();
 902 
 903         // guard against primitive constructor return types
 904         constructor = MH.asType(constructor, constructor.type().changeReturnType(Object.class));
 905 
 906         // apply new filter
 907         final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); // drop self
 908         MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor);
 909 
 910         if (hasCalleeParameter()) {
 911             handle = MH.foldArguments(handle, ALLOCATE);
 912         } else {
 913             handle = MH.filterArguments(handle, 0, ALLOCATE);
 914         }
 915 
 916         final MethodHandle filterIn = MH.asType(pairArguments(handle, type), type);
 917         return new GuardedInvocation(filterIn, null, NashornGuards.getFunctionGuard(this));
 918     }
 919 
 920     @SuppressWarnings("unused")
 921     private static Object newFilter(final Object result, final Object allocation) {
 922         return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation;
 923     }
 924 
 925     @SuppressWarnings("unused")
 926     private static Object wrapFilter(final Object obj) {
 927         if (obj instanceof ScriptObject || !isPrimitiveThis(obj)) {
 928             return obj;
 929         }
 930         return ((GlobalObject) Context.getGlobalTrusted()).wrapAsObject(obj);


 941      * (b) method doesn't have callee parameter (builtin functions)
 942      *   (3) for local/scope calls, bind thiz and drop both callee and thiz.
 943      *   (4) for normal this-calls, drop callee.
 944      */
 945     @Override
 946     protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
 947         final MethodType type = desc.getMethodType();
 948 
 949         if (request.isCallSiteUnstable()) {
 950             // (this, callee, args...) => (this, callee, args[])
 951             final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
 952                     type.parameterCount() - 2);
 953 
 954             return new GuardedInvocation(collector,
 955                     desc.getMethodType().parameterType(0) == ScriptFunction.class ? null : NashornGuards.getScriptFunctionGuard());
 956         }
 957 
 958         MethodHandle boundHandle;
 959         MethodHandle guard = null;
 960 
 961         if (hasCalleeParameter()) {
 962             final MethodHandle callHandle = getBestSpecializedInvokeHandle(type);
 963 
 964             if(NashornCallSiteDescriptor.isScope(desc)) {
 965                 // (this, callee, args...) => (callee, args...) => (callee, [this], args...)
 966                 boundHandle = MH.bindTo(callHandle, isNonStrictFunction() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
 967                 boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
 968             } else {
 969                 // (this, callee, args...) permute => (callee, this, args...) which is what we get in
 970                 final MethodType oldType = callHandle.type();
 971                 final int[] reorder = new int[oldType.parameterCount()];
 972                 for (int i = 2; i < reorder.length; i++) {
 973                     reorder[i] = i;
 974                 }
 975                 reorder[0] = 1;
 976                 assert reorder[1] == 0;
 977                 final MethodType newType = oldType.changeParameterType(0, oldType.parameterType(1)).changeParameterType(1, oldType.parameterType(0));
 978                 boundHandle = MethodHandles.permuteArguments(callHandle, newType, reorder);
 979 
 980                 // For non-strict functions, check whether this-object is primitive type.
 981                 // If so add a to-object-wrapper argument filter.
 982                 // Else install a guard that will trigger a relink when the argument becomes primitive.
 983                 if (isNonStrictFunction()) {
 984                     if (isPrimitiveThis(request.getArguments()[1])) {
 985                         boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
 986                     } else {
 987                         guard = NashornGuards.getNonStrictFunctionGuard(this);
 988                     }
 989                 }
 990             }
 991         } else {
 992             final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1));
 993 
 994             if(NashornCallSiteDescriptor.isScope(desc)) {
 995                 boundHandle = MH.bindTo(callHandle, isNonStrictFunction() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
 996                 boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
 997             } else {
 998                 boundHandle = MH.dropArguments(callHandle, 0, Object.class);
 999             }
1000         }
1001 
1002         boundHandle = pairArguments(boundHandle, type);
1003         return new GuardedInvocation(boundHandle, guard == null ? NashornGuards.getFunctionGuard(this) : guard);
1004    }
1005 
1006     /**
1007      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
1008      *
1009      * These don't want a callee parameter, so bind that. Name binding is optional.
1010      */
1011     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
1012         MethodHandle methodHandle = getBestSpecializedInvokeHandle(type);
1013 
1014         if (bindName != null) {
1015             if (hasCalleeParameter()) {
1016                 methodHandle = MH.insertArguments(methodHandle, 1, this, bindName);
1017             } else {
1018                 methodHandle = MH.insertArguments(methodHandle, 1, bindName);
1019             }
1020         } else {
1021             if (hasCalleeParameter()) {
1022                 methodHandle = MH.insertArguments(methodHandle, 1, this);
1023             }
1024         }
1025 
1026         return pairArguments(methodHandle, type);
1027     }
1028 
1029     /**
1030      * Convert this argument for non-strict functions according to ES 10.4.3
1031      *
1032      * @param thiz the this argument
1033      *
1034      * @return the converted this object
1035      */
1036     protected Object convertThisObject(final Object thiz) {
1037         if (!(thiz instanceof ScriptObject) && isNonStrictFunction()) {
1038             if (JSType.nullOrUndefined(thiz)) {
1039                 return Context.getGlobalTrusted();
1040             }
1041 
1042             if (isPrimitiveThis(thiz)) {
1043                 return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
1044             }
1045         }
1046 
1047         return thiz;
1048     }
1049 
1050     private static boolean isPrimitiveThis(Object obj) {
1051         return obj instanceof String || obj instanceof ConsString ||
1052                obj instanceof Number || obj instanceof Boolean;
1053     }
1054 
1055     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
1056         final Class<?>   own = ScriptFunction.class;
1057         final MethodType mt  = MH.type(rtype, types);


  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.runtime.linker.MethodHandleFactory;
  41 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  42 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  43 import jdk.nashorn.internal.runtime.options.Options;
  44 import org.dynalang.dynalink.CallSiteDescriptor;
  45 import org.dynalang.dynalink.linker.GuardedInvocation;
  46 import org.dynalang.dynalink.linker.LinkRequest;
  47 
  48 /**
  49  * Runtime representation of a JavaScript function.
  50  */
  51 public abstract class ScriptFunction extends ScriptObject {
  52 
  53     /** Method handle for prototype getter for this ScriptFunction */
  54     public static final MethodHandle G$PROTOTYPE  = findOwnMH("G$prototype",  Object.class, Object.class);
  55 
  56     /** Method handle for prototype setter for this ScriptFunction */
  57     public static final MethodHandle S$PROTOTYPE  = findOwnMH("S$prototype",  void.class, Object.class, Object.class);
  58 
  59     /** Method handle for length getter for this ScriptFunction */
  60     public static final MethodHandle G$LENGTH     = findOwnMH("G$length",     int.class, Object.class);
  61 
  62     /** Method handle for name getter for this ScriptFunction */
  63     public static final MethodHandle G$NAME       = findOwnMH("G$name",       Object.class, Object.class);
  64 
  65     /** Method handle for allocate function for this ScriptFunction */
  66     public static final MethodHandle ALLOCATE     = findOwnMH("allocate", Object.class);
  67 
  68     private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
  69 
  70     private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
  71 


  72     /** method handle to scope getter for this ScriptFunction */
  73     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
  74 
  75     /** Should specialized function and specialized constructors for the builtin be used if available? */
  76     private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable");
  77 
  78     private final ScriptFunctionData data;













  79 
  80     /** Reference to constructor prototype. */
  81     protected Object prototype;
  82 






  83     /** The parent scope. */
  84     private final ScriptObject scope;
  85 









  86     /**
  87      * Constructor
  88      *
  89      * @param name         function name
  90      * @param methodHandle method handle to function (if specializations are present, assumed to be most generic)
  91      * @param map          property map
  92      * @param scope        scope
  93      * @param specs        specialized version of this function - other method handles

































  94      *










  95      */
  96     protected ScriptFunction(
  97             final String name,
  98             final MethodHandle methodHandle,
  99             final PropertyMap map,
 100             final ScriptObject scope,
 101             final MethodHandle[] specs,
 102             final boolean strict,
 103             final boolean builtin) {







 104 
 105         this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin), map, scope);

 106     }
 107 
 108     /**
 109      * Constructor
 110      *
 111      * @param data          static function data

 112      * @param map           property map
 113      * @param scope         scope




 114      */
 115     protected ScriptFunction(
 116             final ScriptFunctionData data,

 117             final PropertyMap map,
 118             final ScriptObject scope) {




 119 
 120         super(map);
 121 
 122         if (Context.DEBUG) {
 123             constructorCount++;
 124         }
 125 
 126         this.data = data;


 127         this.scope  = scope;















































































 128     }
 129 
 130     @Override
 131     public String getClassName() {
 132         return "Function";
 133     }
 134 
 135     /**
 136      * ECMA 15.3.5.3 [[HasInstance]] (V)
 137      * Step 3 if "prototype" value is not an Object, throw TypeError
 138      */
 139     @Override
 140     public boolean isInstance(final ScriptObject instance) {
 141         if (!(prototype instanceof ScriptObject)) {
 142             typeError("prototype.not.an.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(prototype));
 143         }
 144 
 145         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
 146             if (proto == prototype) {
 147                 return true;
 148             }
 149         }
 150 
 151         return false;
 152     }
 153 
 154     /**
 155      * Get the arity of this ScriptFunction
 156      * @return arity
 157      */
 158     public final int getArity() {
 159         return data.getArity();
 160     }
 161 
 162     /**
 163      * Set the arity of this ScriptFunction
 164      * @param arity arity
 165      */
 166     public final void setArity(final int arity) {
 167         data.setArity(arity);
 168     }
 169 
 170     /**
 171      * Is this a ECMAScript 'use strict' function?
 172      * @return true if function is in strict mode
 173      */
 174     public boolean isStrict() {
 175         return data.isStrict();
 176     }
 177 
 178     /**
 179      * Is this a ECMAScript built-in function (like parseInt, Array.isArray) ?
 180      * @return true if built-in
 181      */
 182     public boolean isBuiltin() {
 183         return data.isBuiltin();
 184     }
 185 
 186     /**
 187      * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
 188      * according to ECMA 10.4.3.
 189      * @return true if this argument must be an object
 190      */
 191     public boolean needsWrappedThis() {
 192         return data.needsWrappedThis();
 193     }
 194 
 195     /**
 196      * Execute this script function.
 197      * @param self  Target object.
 198      * @param arguments  Call arguments.
 199      * @return ScriptFunction result.
 200      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 201      */
 202     public Object invoke(final Object self, final Object... arguments) throws Throwable {
 203         if (Context.DEBUG) {
 204             invokes++;
 205         }
 206 
 207         final MethodHandle invoker = data.getGenericInvoker();
 208         final Object selfObj = convertThisObject(self);
 209         final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 210 
 211         if (data.isVarArg()) {
 212             if (data.needsCallee()) {
 213                 return invoker.invokeExact(selfObj, this, args);
 214             }
 215             return invoker.invokeExact(selfObj, args);
 216         }
 217 
 218         final int paramCount = invoker.type().parameterCount();
 219         if (data.needsCallee()) {
 220             switch (paramCount) {
 221             case 2:
 222                 return invoker.invokeExact(selfObj, this);
 223             case 3:
 224                 return invoker.invokeExact(selfObj, this, getArg(args, 0));
 225             case 4:
 226                 return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1));
 227             case 5:
 228                 return invoker.invokeExact(selfObj, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 229             default:
 230                 return invoker.invokeWithArguments(withArguments(selfObj, this, paramCount, args));
 231             }
 232         }
 233 
 234         switch (paramCount) {
 235         case 1:
 236             return invoker.invokeExact(selfObj);
 237         case 2:
 238             return invoker.invokeExact(selfObj, getArg(args, 0));
 239         case 3:
 240             return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
 241         case 4:
 242             return invoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 243         default:
 244             return invoker.invokeWithArguments(withArguments(selfObj, null, paramCount, args));
 245         }
 246     }
 247 
 248     private static Object getArg(final Object[] args, final int i) {
 249         return i < args.length ? args[i] : UNDEFINED;
 250     }
 251 
 252     /**
 253      * Construct new object using this constructor.
 254      * @param self  Target object.
 255      * @param args  Call arguments.
 256      * @return ScriptFunction result.
 257      * @throws Throwable if there is an exception/error with the constructor invocation or thrown from it
 258      */
 259     public Object construct(final Object self, final Object... args) throws Throwable {
 260         if (data.getConstructor() == null) {
 261             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 262         }
 263 
 264         final MethodHandle constructor = data.getGenericConstructor();
 265         if (data.isVarArg()) {
 266             if (data.needsCallee()) {
 267                 return constructor.invokeExact(self, this, args);
 268             }
 269             return constructor.invokeExact(self, args);
 270         }
 271 
 272         final int paramCount = constructor.type().parameterCount();
 273         if (data.needsCallee()) {
 274             switch (paramCount) {
 275             case 2:
 276                 return constructor.invokeExact(self, this);
 277             case 3:
 278                 return constructor.invokeExact(self, this, getArg(args, 0));
 279             case 4:
 280                 return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1));
 281             case 5:
 282                 return constructor.invokeExact(self, this, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 283             default:
 284                 return constructor.invokeWithArguments(withArguments(self, this, args));
 285             }
 286         }
 287 
 288         switch(paramCount) {
 289         case 1:
 290             return constructor.invokeExact(self);
 291         case 2:
 292             return constructor.invokeExact(self, getArg(args, 0));
 293         case 3:
 294             return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1));
 295         case 4:
 296             return constructor.invokeExact(self, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 297         default:
 298             return constructor.invokeWithArguments(withArguments(self, null, args));
 299         }
 300     }
 301 
 302     private static Object[] withArguments(final Object self, final ScriptFunction function, final Object... args) {
 303         return withArguments(self, function, args.length + (function == null ? 1 : 2), args); // + 2 to include self and function
 304     }
 305 
 306     private static Object[] withArguments(final Object self, final ScriptFunction function, final int paramCount, final Object... args) {
 307         final Object[] finalArgs = new Object[paramCount];
 308 
 309         finalArgs[0] = self;
 310         int nextArg = 1;
 311         if (function != null) {
 312             finalArgs[nextArg++] = function;
 313         }
 314 
 315         //don't add more args that there is paramcount in the handle (including self)
 316         final int maxArgs = Math.min(args.length, paramCount - (function == null ? 1 : 2));
 317         for (int i = 0; i < maxArgs;) {
 318             finalArgs[nextArg++] = args[i++];


 326         return finalArgs;
 327     }
 328 
 329     /**
 330      * Allocate function. Called from generated {@link ScriptObject} code
 331      * for allocation as a factory method
 332      *
 333      * @return a new instance of the {@link ScriptObject} whose allocator this is
 334      */
 335     public Object allocate() {
 336         if (Context.DEBUG) {
 337             allocations++;
 338         }
 339 
 340         if (getConstructHandle() == null) {
 341             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 342         }
 343 
 344         ScriptObject object = null;
 345 
 346         if (data.getAllocator() != null) {
 347             try {
 348                 object = (ScriptObject)data.getAllocator().invokeExact(data.getAllocatorMap());
 349             } catch (final RuntimeException | Error e) {
 350                 throw e;
 351             } catch (final Throwable t) {
 352                 throw new RuntimeException(t);
 353             }
 354         }
 355 
 356         if (object != null) {
 357             if (prototype instanceof ScriptObject) {
 358                 object.setProto((ScriptObject)prototype);
 359             }
 360 
 361             if (object.getProto() == null) {
 362                 object.setProto(getObjectPrototype());
 363             }
 364         }
 365 
 366         return object;
 367     }
 368 
 369     /**
 370      * Return Object.prototype - used by "allocate"
 371      * @return Object.prototype
 372      */
 373     protected abstract ScriptObject getObjectPrototype();
 374 
 375     /**
 376      * Creates a version of this function bound to a specific "self" and other argumentss
 377      * @param self the self to bind the function to
 378      * @param args other arguments (beside self) to bind the function to
 379      * @return the bound function
 380      */
 381     public abstract ScriptFunction makeBoundFunction(Object self, Object[] args);
 382 



















 383 
 384     @Override
 385     public final String safeToString() {
 386         return toSource();
 387     }
 388 
 389     @Override
 390     public String toString() {
 391         return data.toString();
















 392     }
 393 
 394     /**
 395      * Get this function as a String containing its source code. If no source code
 396      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 397      * @return string representation of this function's source
 398      */
 399     public final String toSource() {
 400         return data.toSource();




 401     }
 402 
 403     /**
 404      * Get the prototype object for this function
 405      * @return prototype
 406      */
 407     public final Object getPrototype() {
 408         return prototype;
 409     }
 410 
 411     /**
 412      * Set the prototype object for this function
 413      * @param prototype new prototype object
 414      * @return the prototype parameter
 415      */
 416     public final Object setPrototype(final Object prototype) {
 417         this.prototype = prototype;
 418         return prototype;
 419     }
 420 


 474             final int specWeight = weigh(specType);
 475             if (specWeight < minimumWeight) {
 476                 candidate = spec;
 477                 minimumWeight = specWeight;
 478             }
 479         }
 480 
 481         if (DISABLE_SPECIALIZATION && candidate != initialCandidate) {
 482             Context.err("### Specializing builtin " + getName() + " -> " + candidate + "?");
 483         }
 484 
 485         return candidate;
 486     }
 487 
 488     /**
 489      * Return the most appropriate invoke handle if there are specializations
 490      * @param type most specific method type to look for invocation with
 491      * @return invoke method handle
 492      */
 493     public final MethodHandle getBestSpecializedInvokeHandle(final MethodType type) {
 494         return candidateWithLowestWeight(type, getInvokeHandle(), data.getInvokeSpecializations());
 495     }
 496 
 497     /**
 498      * Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
 499      * method handle for this ScriptFunction
 500      * @see SpecializedFunction
 501      * @return invokeHandle
 502      */
 503     public final MethodHandle getInvokeHandle() {
 504         return data.getInvoker();
 505     }
 506 
 507     /**
 508      * Return the invoke handle bound to a given ScriptObject self reference.
 509      * If callee parameter is required result is rebound to this.
 510      *
 511      * @param self self reference
 512      * @return bound invoke handle
 513      */
 514     public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
 515         final MethodHandle bound = MH.bindTo(getInvokeHandle(), self);
 516         return data.needsCallee() ? MH.bindTo(bound, this) : bound;
 517     }
 518 










 519 
 520     /**
 521      * Get the construct handle - the most generic (and if no specializations are in place, only) constructor
 522      * method handle for this ScriptFunction
 523      * @see SpecializedConstructor
 524      * @param type type for wanted constructor
 525      * @return construct handle
 526      */
 527     public final MethodHandle getConstructHandle(final MethodType type) {
 528         return candidateWithLowestWeight(type, getConstructHandle(), data.getConstructSpecializations());
 529     }
 530 
 531     /**
 532      * Get a method handle to the constructor for this function
 533      * @return constructor handle
 534      */
 535     public final MethodHandle getConstructHandle() {
 536         return data.getConstructor();
 537     }
 538 
 539     /**
 540      * Set a method handle to the constructor for this function
 541      * @param constructHandle constructor handle
 542      */
 543     public final void setConstructHandle(final MethodHandle constructHandle) {
 544         data.setConstructor(constructHandle);

 545     }
 546 
 547     /**
 548      * Get the name for this function
 549      * @return the name
 550      */
 551     public final String getName() {
 552         return data.getName();
 553     }
 554 
 555     /**
 556      * Does this script function need to be compiled. This determined by
 557      * null checking invokeHandle
 558      *
 559      * @return true if this needs compilation
 560      */
 561     public final boolean needsCompilation() {
 562         return data.getInvoker() == null;
 563     }
 564 
 565     /**
 566      * Get token for this function
 567      * @return token
 568      */
 569     public final long getToken() {
 570         return data.getToken();
 571     }
 572 
 573     /**
 574      * Get the scope for this function
 575      * @return the scope
 576      */
 577     public final ScriptObject getScope() {
 578         return scope;
 579     }
 580 
 581     /**
 582      * Prototype getter for this ScriptFunction - follows the naming convention
 583      * used by Nasgen and the code generator
 584      *
 585      * @param self  self reference
 586      * @return self's prototype
 587      */
 588     public static Object G$prototype(final Object self) {
 589         return (self instanceof ScriptFunction) ?
 590             ((ScriptFunction)self).getPrototype() :


 674 
 675     @Override
 676     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
 677         final MethodType type = desc.getMethodType();
 678         MethodHandle constructor = getConstructHandle(type);
 679 
 680         if (constructor == null) {
 681             typeError("not.a.constructor", ScriptRuntime.safeToString(this));
 682             return null;
 683         }
 684 
 685         final MethodType ctorType = constructor.type();
 686 
 687         // guard against primitive constructor return types
 688         constructor = MH.asType(constructor, constructor.type().changeReturnType(Object.class));
 689 
 690         // apply new filter
 691         final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray(); // drop self
 692         MethodHandle handle = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), constructor);
 693 
 694         if (data.needsCallee()) {
 695             handle = MH.foldArguments(handle, ALLOCATE);
 696         } else {
 697             handle = MH.filterArguments(handle, 0, ALLOCATE);
 698         }
 699 
 700         final MethodHandle filterIn = MH.asType(pairArguments(handle, type), type);
 701         return new GuardedInvocation(filterIn, null, NashornGuards.getFunctionGuard(this));
 702     }
 703 
 704     @SuppressWarnings("unused")
 705     private static Object newFilter(final Object result, final Object allocation) {
 706         return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation;
 707     }
 708 
 709     @SuppressWarnings("unused")
 710     private static Object wrapFilter(final Object obj) {
 711         if (obj instanceof ScriptObject || !isPrimitiveThis(obj)) {
 712             return obj;
 713         }
 714         return ((GlobalObject) Context.getGlobalTrusted()).wrapAsObject(obj);


 725      * (b) method doesn't have callee parameter (builtin functions)
 726      *   (3) for local/scope calls, bind thiz and drop both callee and thiz.
 727      *   (4) for normal this-calls, drop callee.
 728      */
 729     @Override
 730     protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
 731         final MethodType type = desc.getMethodType();
 732 
 733         if (request.isCallSiteUnstable()) {
 734             // (this, callee, args...) => (this, callee, args[])
 735             final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
 736                     type.parameterCount() - 2);
 737 
 738             return new GuardedInvocation(collector,
 739                     desc.getMethodType().parameterType(0) == ScriptFunction.class ? null : NashornGuards.getScriptFunctionGuard());
 740         }
 741 
 742         MethodHandle boundHandle;
 743         MethodHandle guard = null;
 744 
 745         if (data.needsCallee()) {
 746             final MethodHandle callHandle = getBestSpecializedInvokeHandle(type);
 747 
 748             if(NashornCallSiteDescriptor.isScope(desc)) {
 749                 // (this, callee, args...) => (callee, args...) => (callee, [this], args...)
 750                 boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
 751                 boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
 752             } else {
 753                 // (this, callee, args...) permute => (callee, this, args...) which is what we get in
 754                 final MethodType oldType = callHandle.type();
 755                 final int[] reorder = new int[oldType.parameterCount()];
 756                 for (int i = 2; i < reorder.length; i++) {
 757                     reorder[i] = i;
 758                 }
 759                 reorder[0] = 1;
 760                 assert reorder[1] == 0;
 761                 final MethodType newType = oldType.changeParameterType(0, oldType.parameterType(1)).changeParameterType(1, oldType.parameterType(0));
 762                 boundHandle = MethodHandles.permuteArguments(callHandle, newType, reorder);
 763 
 764                 // For non-strict functions, check whether this-object is primitive type.
 765                 // If so add a to-object-wrapper argument filter.
 766                 // Else install a guard that will trigger a relink when the argument becomes primitive.
 767                 if (needsWrappedThis()) {
 768                     if (isPrimitiveThis(request.getArguments()[1])) {
 769                         boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
 770                     } else {
 771                         guard = NashornGuards.getNonStrictFunctionGuard(this);
 772                     }
 773                 }
 774             }
 775         } else {
 776             final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1));
 777 
 778             if(NashornCallSiteDescriptor.isScope(desc)) {
 779                 boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
 780                 boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
 781             } else {
 782                 boundHandle = MH.dropArguments(callHandle, 0, Object.class);
 783             }
 784         }
 785 
 786         boundHandle = pairArguments(boundHandle, type);
 787         return new GuardedInvocation(boundHandle, guard == null ? NashornGuards.getFunctionGuard(this) : guard);
 788    }
 789 
 790     /**
 791      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
 792      *
 793      * These don't want a callee parameter, so bind that. Name binding is optional.
 794      */
 795     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
 796         MethodHandle methodHandle = getBestSpecializedInvokeHandle(type);
 797 
 798         if (bindName != null) {
 799             if (data.needsCallee()) {
 800                 methodHandle = MH.insertArguments(methodHandle, 1, this, bindName);
 801             } else {
 802                 methodHandle = MH.insertArguments(methodHandle, 1, bindName);
 803             }
 804         } else {
 805             if (data.needsCallee()) {
 806                 methodHandle = MH.insertArguments(methodHandle, 1, this);
 807             }
 808         }
 809 
 810         return pairArguments(methodHandle, type);
 811     }
 812 
 813     /**
 814      * Convert this argument for non-strict functions according to ES 10.4.3
 815      *
 816      * @param thiz the this argument
 817      *
 818      * @return the converted this object
 819      */
 820     protected Object convertThisObject(final Object thiz) {
 821         if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
 822             if (JSType.nullOrUndefined(thiz)) {
 823                 return Context.getGlobalTrusted();
 824             }
 825 
 826             if (isPrimitiveThis(thiz)) {
 827                 return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
 828             }
 829         }
 830 
 831         return thiz;
 832     }
 833 
 834     private static boolean isPrimitiveThis(Object obj) {
 835         return obj instanceof String || obj instanceof ConsString ||
 836                obj instanceof Number || obj instanceof Boolean;
 837     }
 838 
 839     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
 840         final Class<?>   own = ScriptFunction.class;
 841         final MethodType mt  = MH.type(rtype, types);