1 /*
   2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.runtime;
  27 
  28 import static jdk.nashorn.internal.lookup.Lookup.MH;
  29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  31 
  32 import java.lang.invoke.MethodHandle;
  33 import java.lang.invoke.MethodHandles;
  34 import java.lang.invoke.MethodType;
  35 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
  36 
  37 /**
  38  * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime.
  39  * Instances of this class are created during codegen and stored in script classes'
  40  * constants array to reduce function instantiation overhead during runtime.
  41  */
  42 public abstract class ScriptFunctionData {
  43 
  44     /** Name of the function or "" for anonynous functions */
  45     protected final String name;
  46 
  47     /** All versions of this function that have been generated to code */
  48     protected final CompiledFunctions code;
  49 
  50     /** Function flags */
  51     protected int flags;
  52 
  53     private int arity;
  54 
  55     private static final MethodHandle NEWFILTER     = findOwnMH("newFilter", Object.class, Object.class, Object.class);
  56     private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
  57 
  58     /** Is this a strict mode function? */
  59     public static final int IS_STRICT      = 1 << 0;
  60     /** Is this a built-in function? */
  61     public static final int IS_BUILTIN     = 1 << 1;
  62     /** Is this a constructor function? */
  63     public static final int IS_CONSTRUCTOR = 1 << 2;
  64     /** Does this function expect a callee argument? */
  65     public static final int NEEDS_CALLEE   = 1 << 3;
  66     /** Does this function make use of the this-object argument? */
  67     public static final int USES_THIS      = 1 << 4;
  68 
  69     /** Flag for strict or built-in functions */
  70     public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
  71     /** Flag for built-in constructors */
  72     public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR;
  73     /** Flag for strict constructors */
  74     public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR;
  75 
  76     /**
  77      * Constructor
  78      *
  79      * @param name          script function name
  80      * @param arity         arity
  81      * @param flags         the function flags
  82      */
  83     ScriptFunctionData(final String name, final int arity, final int flags) {
  84         this.name  = name;
  85         this.arity = arity;
  86         this.code  = new CompiledFunctions();
  87         this.flags = flags;
  88     }
  89 
  90     final int getArity() {
  91         return arity;
  92     }
  93 
  94     /**
  95      * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final
  96      * @param arity new arity
  97      */
  98     void setArity(final int arity) {
  99         this.arity = arity;
 100     }
 101 
 102     CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
 103         final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args);
 104 
 105         //TODO the boundinvoker.type() could actually be more specific here
 106         if (isConstructor()) {
 107             ensureConstructor(originalInv);
 108             return new CompiledFunction(boundInvoker.type(), boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
 109         }
 110 
 111         return new CompiledFunction(boundInvoker.type(), boundInvoker);
 112     }
 113 
 114     /**
 115      * Is this a ScriptFunction generated with strict semantics?
 116      * @return true if strict, false otherwise
 117      */
 118     public boolean isStrict() {
 119         return (flags & IS_STRICT) != 0;
 120     }
 121 
 122     boolean isBuiltin() {
 123         return (flags & IS_BUILTIN) != 0;
 124     }
 125 
 126     boolean isConstructor() {
 127         return (flags & IS_CONSTRUCTOR) != 0;
 128     }
 129 
 130     boolean needsCallee() {
 131         // we don't know if we need a callee or not unless code has been compiled
 132         ensureCompiled();
 133         return (flags & NEEDS_CALLEE) != 0;
 134     }
 135 
 136     /**
 137      * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
 138      * according to ECMA 10.4.3.
 139      * @return true if this argument must be an object
 140      */
 141     boolean needsWrappedThis() {
 142         return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0;
 143     }
 144 
 145     String toSource() {
 146         return "function " + (name == null ? "" : name) + "() { [native code] }";
 147     }
 148 
 149     String getName() {
 150         return name;
 151     }
 152 
 153     /**
 154      * Get this function as a String containing its source code. If no source code
 155      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 156      *
 157      * @return string representation of this function
 158      */
 159     @Override
 160     public String toString() {
 161         final StringBuilder sb = new StringBuilder();
 162 
 163         sb.append("name='").
 164                 append(name.isEmpty() ? "<anonymous>" : name).
 165                 append("' ").
 166                 append(code.size()).
 167                 append(" invokers=").
 168                 append(code);
 169 
 170         return sb.toString();
 171     }
 172 
 173     /**
 174      * Pick the best invoker, i.e. the one version of this method with as narrow and specific
 175      * types as possible. If the call site arguments are objects, but boxed primitives we can
 176      * also try to get a primitive version of the method and do an unboxing filter, but then
 177      * we need to insert a guard that checks the argument is really always a boxed primitive
 178      * and not suddenly a "real" object
 179      *
 180      * @param callSiteType callsite type
 181      * @param args         arguments at callsite on first trampoline invocation
 182      * @return method handle to best invoker
 183      */
 184     MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
 185         return getBest(callSiteType).getInvoker();
 186     }
 187 
 188     MethodHandle getBestInvoker(final MethodType callSiteType) {
 189         return getBestInvoker(callSiteType, null);
 190     }
 191 
 192     MethodHandle getBestConstructor(final MethodType callSiteType, final Object[] args) {
 193         if (!isConstructor()) {
 194             throw typeError("not.a.constructor", toSource());
 195         }
 196         ensureCodeGenerated();
 197 
 198         final CompiledFunction best = getBest(callSiteType);
 199         ensureConstructor(best);
 200         return best.getConstructor();
 201     }
 202 
 203     MethodHandle getBestConstructor(final MethodType callSiteType) {
 204         return getBestConstructor(callSiteType, null);
 205     }
 206 
 207     /**
 208      * Subclass responsibility. If we can have lazy code generation, this is a hook to ensure that
 209      * code exists before performing an operation.
 210      */
 211     protected void ensureCodeGenerated() {
 212         //empty
 213     }
 214 
 215     /**
 216      * If we can have lazy code generation, this is a hook to ensure that the code has been compiled.
 217      * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance;
 218      * use {@link #ensureCodeGenerated()} to install the actual method handles.
 219      */
 220     protected void ensureCompiled() {
 221         //empty
 222     }
 223 
 224     /**
 225      * Return a generic Object/Object invoker for this method. It will ensure code
 226      * is generated, get the most generic of all versions of this function and adapt it
 227      * to Objects.
 228      *
 229      * TODO this is only public because {@link JavaAdapterFactory} can't supply us with
 230      * a MethodType that we can use for lookup due to boostrapping problems. Can be fixed
 231      *
 232      * @return generic invoker of this script function
 233      */
 234     public final MethodHandle getGenericInvoker() {
 235         ensureCodeGenerated();
 236         return code.generic().getInvoker();
 237     }
 238 
 239     final MethodHandle getGenericConstructor() {
 240         ensureCodeGenerated();
 241         ensureConstructor(code.generic());
 242         return code.generic().getConstructor();
 243     }
 244 
 245     private CompiledFunction getBest(final MethodType callSiteType) {
 246         ensureCodeGenerated();
 247         return code.best(callSiteType);
 248     }
 249 
 250     /**
 251      * Allocates an object using this function's allocator.
 252      *
 253      * @param map the property map for the allocated object.
 254      * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator.
 255      */
 256     ScriptObject allocate(final PropertyMap map) {
 257         return null;
 258     }
 259 
 260     /**
 261      * Get the property map to use for objects allocated by this function.
 262      *
 263      * @return the property map for allocated objects.
 264      */
 265     PropertyMap getAllocatorMap() {
 266         return null;
 267     }
 268 
 269     /**
 270      * This method is used to create the immutable portion of a bound function.
 271      * See {@link ScriptFunction#makeBoundFunction(Object, Object[])}
 272      *
 273      * @param fn the original function being bound
 274      * @param self this reference to bind. Can be null.
 275      * @param args additional arguments to bind. Can be null.
 276      */
 277     ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) {
 278         ensureCodeGenerated();
 279 
 280         final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
 281         final int length = args == null ? 0 : args.length;
 282         // Clear the callee and this flags
 283         final int boundFlags = flags & ~NEEDS_CALLEE & ~USES_THIS;
 284 
 285         CompiledFunctions boundList = new CompiledFunctions();
 286         if (code.size() == 1) {
 287             // only one variant - bind that
 288             boundList.add(bind(code.first(), fn, self, allArgs));
 289         } else {
 290             // There are specialized versions. Get the most generic one.
 291             // This is to avoid ambiguous overloaded versions of bound and
 292             // specialized variants and choosing wrong overload.
 293             final MethodHandle genInvoker = getGenericInvoker();
 294             final CompiledFunction inv = new CompiledFunction(genInvoker.type(), genInvoker, getGenericConstructor());
 295             boundList.add(bind(inv, fn, self, allArgs));
 296         }
 297 
 298         return new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, boundFlags);
 299     }
 300 
 301     /**
 302      * Compose a constructor given a primordial constructor handle.
 303      *
 304      * @param ctor primordial constructor handle
 305      * @return the composed constructor
 306      */
 307     protected MethodHandle composeConstructor(final MethodHandle ctor) {
 308         // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having
 309         // "this" in the first argument position is what allows the elegant folded composition of
 310         // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor
 311         // always returns Object.
 312         final boolean needsCallee = needsCallee(ctor);
 313         MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor;
 314 
 315         composedCtor = changeReturnTypeToObject(composedCtor);
 316 
 317         final MethodType ctorType = composedCtor.type();
 318 
 319         // Construct a dropping type list for NEWFILTER, but don't include constructor "this" into it, so it's actually
 320         // captured as "allocation" parameter of NEWFILTER after we fold the constructor into it.
 321         // (this, [callee, ]args...) => ([callee, ]args...)
 322         final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray();
 323 
 324         // Fold constructor into newFilter that replaces the return value from the constructor with the originally
 325         // allocated value when the originally allocated value is a primitive.
 326         // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...)
 327         composedCtor = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), composedCtor);
 328 
 329         // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject...
 330         if (needsCallee) {
 331             // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and
 332             // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...),
 333             // or...
 334             return MH.foldArguments(composedCtor, ScriptFunction.ALLOCATE);
 335         }
 336 
 337         // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee
 338         // (this, args...) filter (callee) => (callee, args...)
 339         return MH.filterArguments(composedCtor, 0, ScriptFunction.ALLOCATE);
 340     }
 341 
 342     /**
 343      * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed
 344      * method handle. If this function's method handles don't need a callee parameter, returns the original method
 345      * handle unchanged.
 346      *
 347      * @param mh a method handle with order of arguments {@code (callee, this, args...)}
 348      *
 349      * @return a method handle with order of arguments {@code (this, callee, args...)}
 350      */
 351     private static MethodHandle swapCalleeAndThis(final MethodHandle mh) {
 352         final MethodType type = mh.type();
 353         assert type.parameterType(0) == ScriptFunction.class : type;
 354         assert type.parameterType(1) == Object.class : type;
 355         final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class);
 356         final int[] reorder = new int[type.parameterCount()];
 357         reorder[0] = 1;
 358         assert reorder[1] == 0;
 359         for (int i = 2; i < reorder.length; ++i) {
 360             reorder[i] = i;
 361         }
 362         return MethodHandles.permuteArguments(mh, newType, reorder);
 363     }
 364 
 365     /**
 366      * Convert this argument for non-strict functions according to ES 10.4.3
 367      *
 368      * @param thiz the this argument
 369      *
 370      * @return the converted this object
 371      */
 372     private Object convertThisObject(final Object thiz) {
 373         if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
 374             if (JSType.nullOrUndefined(thiz)) {
 375                 return Context.getGlobalTrusted();
 376             }
 377 
 378             if (isPrimitiveThis(thiz)) {
 379                 return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
 380             }
 381         }
 382 
 383         return thiz;
 384     }
 385 
 386     static boolean isPrimitiveThis(final Object obj) {
 387         return obj instanceof String || obj instanceof ConsString ||
 388                obj instanceof Number || obj instanceof Boolean;
 389     }
 390 
 391     /**
 392      * Creates an invoker method handle for a bound function.
 393      *
 394      * @param targetFn the function being bound
 395      * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or
 396      * any of its specializations.
 397      * @param self the "this" value being bound
 398      * @param args additional arguments being bound
 399      *
 400      * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting
 401      * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting
 402      * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed
 403      * to the original invoker on invocation.
 404      */
 405     private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) {
 406         // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound
 407         // in the target and will be ignored anyway.
 408         final boolean isTargetBound = targetFn.isBoundFunction();
 409 
 410         final boolean needsCallee = needsCallee(originalInvoker);
 411         assert needsCallee == needsCallee() : "callee contract violation 2";
 412         assert !(isTargetBound && needsCallee); // already bound functions don't need a callee
 413 
 414         final Object boundSelf = isTargetBound ? null : convertThisObject(self);
 415         final MethodHandle boundInvoker;
 416 
 417         if (isVarArg(originalInvoker)) {
 418             // First, bind callee and this without arguments
 419             final MethodHandle noArgBoundInvoker;
 420 
 421             if (isTargetBound) {
 422                 // Don't bind either callee or this
 423                 noArgBoundInvoker = originalInvoker;
 424             } else if (needsCallee) {
 425                 // Bind callee and this
 426                 noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf);
 427             } else {
 428                 // Only bind this
 429                 noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf);
 430             }
 431             // Now bind arguments
 432             if (args.length > 0) {
 433                 boundInvoker = varArgBinder(noArgBoundInvoker, args);
 434             } else {
 435                 boundInvoker = noArgBoundInvoker;
 436             }
 437         } else {
 438             // If target is already bound, insert additional bound arguments after "this" argument, at position 1.
 439             final int argInsertPos = isTargetBound ? 1 : 0;
 440             final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : (needsCallee  ? 2 : 1)))];
 441             int next = 0;
 442             if (!isTargetBound) {
 443                 if (needsCallee) {
 444                     boundArgs[next++] = targetFn;
 445                 }
 446                 boundArgs[next++] = boundSelf;
 447             }
 448             // If more bound args were specified than the function can take, we'll just drop those.
 449             System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next);
 450             // If target is already bound, insert additional bound arguments after "this" argument, at position 1;
 451             // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions
 452             // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args
 453             // start at position 1. If the function is not bound, we start inserting arguments at position 0.
 454             boundInvoker = MH.insertArguments(originalInvoker, argInsertPos, boundArgs);
 455         }
 456 
 457         if (isTargetBound) {
 458             return boundInvoker;
 459         }
 460 
 461         // If the target is not already bound, add a dropArguments that'll throw away the passed this
 462         return MH.dropArguments(boundInvoker, 0, Object.class);
 463     }
 464 
 465     /**
 466      * Creates a constructor method handle for a bound function using the passed constructor handle.
 467      *
 468      * @param originalConstructor the constructor handle to bind. It must be a composed constructor.
 469      * @param fn the function being bound
 470      * @param args arguments being bound
 471      *
 472      * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never
 473      * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor
 474      * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if
 475      * this script function data object has no constructor handle, null is returned.
 476      */
 477     private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) {
 478         assert originalConstructor != null;
 479 
 480         // If target function is already bound, don't bother binding the callee.
 481         final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor :
 482             MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class);
 483 
 484         if (args.length == 0) {
 485             return calleeBoundConstructor;
 486         }
 487 
 488         if (isVarArg(calleeBoundConstructor)) {
 489             return varArgBinder(calleeBoundConstructor, args);
 490         }
 491 
 492         final Object[] boundArgs;
 493 
 494         final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1;
 495         if (args.length <= maxArgCount) {
 496             boundArgs = args;
 497         } else {
 498             boundArgs = new Object[maxArgCount];
 499             System.arraycopy(args, 0, boundArgs, 0, maxArgCount);
 500         }
 501 
 502         return MH.insertArguments(calleeBoundConstructor, 1, boundArgs);
 503     }
 504 
 505     /**
 506      * Execute this script function.
 507      *
 508      * @param self  Target object.
 509      * @param arguments  Call arguments.
 510      * @return ScriptFunction result.
 511      *
 512      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 513      */
 514     Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable {
 515         final MethodHandle mh  = getGenericInvoker();
 516         final Object   selfObj = convertThisObject(self);
 517         final Object[] args    = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 518 
 519         if (isVarArg(mh)) {
 520             if (needsCallee(mh)) {
 521                 return mh.invokeExact(fn, selfObj, args);
 522             }
 523             return mh.invokeExact(selfObj, args);
 524         }
 525 
 526         final int paramCount = mh.type().parameterCount();
 527         if (needsCallee(mh)) {
 528             switch (paramCount) {
 529             case 2:
 530                 return mh.invokeExact(fn, selfObj);
 531             case 3:
 532                 return mh.invokeExact(fn, selfObj, getArg(args, 0));
 533             case 4:
 534                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1));
 535             case 5:
 536                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 537             case 6:
 538                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 539             case 7:
 540                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 541             case 8:
 542                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 543             default:
 544                 return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args));
 545             }
 546         }
 547 
 548         switch (paramCount) {
 549         case 1:
 550             return mh.invokeExact(selfObj);
 551         case 2:
 552             return mh.invokeExact(selfObj, getArg(args, 0));
 553         case 3:
 554             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
 555         case 4:
 556             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 557         case 5:
 558             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 559         case 6:
 560             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 561         case 7:
 562             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 563         default:
 564             return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args));
 565         }
 566     }
 567 
 568     Object construct(final ScriptFunction fn, final Object... arguments) throws Throwable {
 569         final MethodHandle mh   = getGenericConstructor();
 570         final Object[]     args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 571 
 572         if (isVarArg(mh)) {
 573             if (needsCallee(mh)) {
 574                 return mh.invokeExact(fn, args);
 575             }
 576             return mh.invokeExact(args);
 577         }
 578 
 579         final int paramCount = mh.type().parameterCount();
 580         if (needsCallee(mh)) {
 581             switch (paramCount) {
 582             case 1:
 583                 return mh.invokeExact(fn);
 584             case 2:
 585                 return mh.invokeExact(fn, getArg(args, 0));
 586             case 3:
 587                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1));
 588             case 4:
 589                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 590             case 5:
 591                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 592             case 6:
 593                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 594             case 7:
 595                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 596             default:
 597                 return mh.invokeWithArguments(withArguments(fn, paramCount, args));
 598             }
 599         }
 600 
 601         switch (paramCount) {
 602         case 0:
 603             return mh.invokeExact();
 604         case 1:
 605             return mh.invokeExact(getArg(args, 0));
 606         case 2:
 607             return mh.invokeExact(getArg(args, 0), getArg(args, 1));
 608         case 3:
 609             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2));
 610         case 4:
 611             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 612         case 5:
 613             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 614         case 6:
 615             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 616         default:
 617             return mh.invokeWithArguments(withArguments(null, paramCount, args));
 618         }
 619     }
 620 
 621     private static Object getArg(final Object[] args, final int i) {
 622         return i < args.length ? args[i] : UNDEFINED;
 623     }
 624 
 625     private static Object[] withArguments(final ScriptFunction fn, final int argCount, final Object[] args) {
 626         final Object[] finalArgs = new Object[argCount];
 627 
 628         int nextArg = 0;
 629         if (fn != null) {
 630             //needs callee
 631             finalArgs[nextArg++] = fn;
 632         }
 633 
 634         // Don't add more args that there is argCount in the handle (including self and callee).
 635         for (int i = 0; i < args.length && nextArg < argCount;) {
 636             finalArgs[nextArg++] = args[i++];
 637         }
 638 
 639         // If we have fewer args than argCount, pad with undefined.
 640         while (nextArg < argCount) {
 641             finalArgs[nextArg++] = UNDEFINED;
 642         }
 643 
 644         return finalArgs;
 645     }
 646 
 647     private static Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) {
 648         final Object[] finalArgs = new Object[argCount];
 649 
 650         int nextArg = 0;
 651         if (fn != null) {
 652             //needs callee
 653             finalArgs[nextArg++] = fn;
 654         }
 655         finalArgs[nextArg++] = self;
 656 
 657         // Don't add more args that there is argCount in the handle (including self and callee).
 658         for (int i = 0; i < args.length && nextArg < argCount;) {
 659             finalArgs[nextArg++] = args[i++];
 660         }
 661 
 662         // If we have fewer args than argCount, pad with undefined.
 663         while (nextArg < argCount) {
 664             finalArgs[nextArg++] = UNDEFINED;
 665         }
 666 
 667         return finalArgs;
 668     }
 669     /**
 670      * Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the
 671      * vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on
 672      * invocation
 673      *
 674      * @param mh the handle
 675      * @param args the bound arguments
 676      *
 677      * @return the bound method handle
 678      */
 679     private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) {
 680         assert args != null;
 681         assert args.length > 0;
 682         return MH.filterArguments(mh, mh.type().parameterCount() - 1, MH.bindTo(BIND_VAR_ARGS, args));
 683     }
 684 
 685     /**
 686      * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already
 687      * {@code Object}, the handle is returned unchanged.
 688      *
 689      * @param mh the handle to adapt
 690      * @return the adapted handle
 691      */
 692     private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) {
 693         final MethodType type = mh.type();
 694         return (type.returnType() == Object.class) ? mh : MH.asType(mh, type.changeReturnType(Object.class));
 695     }
 696 
 697     private void ensureConstructor(final CompiledFunction inv) {
 698         if (!inv.hasConstructor()) {
 699             inv.setConstructor(composeConstructor(inv.getInvoker()));
 700         }
 701     }
 702 
 703     /**
 704      * Heuristic to figure out if the method handle has a callee argument. If it's type is
 705      * {@code (ScriptFunction, ...)}, then we'll assume it has a callee argument. We need this as
 706      * the constructor above is not passed this information, and can't just blindly assume it's false
 707      * (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
 708      * they also always receive a callee).
 709      *
 710      * @param mh the examined method handle
 711      *
 712      * @return true if the method handle expects a callee, false otherwise
 713      */
 714     protected static boolean needsCallee(final MethodHandle mh) {
 715         final MethodType type = mh.type();
 716         return (type.parameterCount() > 0 && type.parameterType(0) == ScriptFunction.class);
 717     }
 718 
 719     /**
 720      * Check if a javascript function methodhandle is a vararg handle
 721      *
 722      * @param mh method handle to check
 723      *
 724      * @return true if vararg
 725      */
 726     protected static boolean isVarArg(final MethodHandle mh) {
 727         final MethodType type = mh.type();
 728         return type.parameterType(type.parameterCount() - 1).isArray();
 729     }
 730 
 731     @SuppressWarnings("unused")
 732     private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) {
 733         if (array2 == null) {
 734             // Must clone it, as we can't allow the receiving method to alter the array
 735             return array1.clone();
 736         }
 737 
 738         final int l2 = array2.length;
 739         if (l2 == 0) {
 740             return array1.clone();
 741         }
 742 
 743         final int l1 = array1.length;
 744         final Object[] concat = new Object[l1 + l2];
 745         System.arraycopy(array1, 0, concat, 0, l1);
 746         System.arraycopy(array2, 0, concat, l1, l2);
 747 
 748         return concat;
 749     }
 750 
 751     @SuppressWarnings("unused")
 752     private static Object newFilter(final Object result, final Object allocation) {
 753         return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation;
 754     }
 755 
 756     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
 757         return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types));
 758     }
 759 }