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