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.io.IOException;
  33 import java.io.ObjectInputStream;
  34 import java.io.Serializable;
  35 import java.lang.invoke.MethodHandle;
  36 import java.lang.invoke.MethodHandles;
  37 import java.lang.invoke.MethodType;
  38 import java.util.Collection;
  39 import java.util.LinkedList;
  40 import java.util.List;
  41 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
  42 
  43 
  44 /**
  45  * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime.
  46  * Instances of this class are created during codegen and stored in script classes'
  47  * constants array to reduce function instantiation overhead during runtime.
  48  */
  49 public abstract class ScriptFunctionData implements Serializable {
  50     static final int MAX_ARITY = LinkerCallSite.ARGLIMIT;
  51     static {
  52         // Assert it fits in a byte, as that's what we store it in. It's just a size optimization though, so if needed
  53         // "byte arity" field can be widened.
  54         assert MAX_ARITY < 256;
  55     }
  56 
  57     /** Name of the function or "" for anonymous functions */
  58     protected final String name;
  59 
  60     /**
  61      * A list of code versions of a function sorted in ascending order of generic descriptors.
  62      */
  63     protected transient LinkedList<CompiledFunction> code = new LinkedList<>();
  64 
  65     /** Function flags */
  66     protected int flags;
  67 
  68     // Parameter arity of the function, corresponding to "f.length". E.g. "function f(a, b, c) { ... }" arity is 3, and
  69     // some built-in ECMAScript functions have their arity declared by the specification. Note that regardless of this
  70     // value, the function might still be capable of receiving variable number of arguments, see isVariableArity.
  71     private int arity;
  72 
  73     // this may be null, if not available
  74     private String documentation;
  75 
  76     /**
  77      * A pair of method handles used for generic invoker and constructor. Field is volatile as it can be initialized by
  78      * multiple threads concurrently, but we still tolerate a race condition in it as all values stored into it are
  79      * idempotent.
  80      */
  81     private volatile transient GenericInvokers genericInvokers;
  82 
  83     private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
  84 
  85     /** Is this a strict mode function? */
  86     public static final int IS_STRICT            = 1 << 0;
  87     /** Is this a built-in function? */
  88     public static final int IS_BUILTIN           = 1 << 1;
  89     /** Is this a constructor function? */
  90     public static final int IS_CONSTRUCTOR       = 1 << 2;
  91     /** Does this function expect a callee argument? */
  92     public static final int NEEDS_CALLEE         = 1 << 3;
  93     /** Does this function make use of the this-object argument? */
  94     public static final int USES_THIS            = 1 << 4;
  95     /** Is this a variable arity function? */
  96     public static final int IS_VARIABLE_ARITY    = 1 << 5;
  97     /** Is this a object literal property getter or setter? */
  98     public static final int IS_PROPERTY_ACCESSOR = 1 << 6;
  99 
 100     /** Flag for strict or built-in functions */
 101     public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
 102     /** Flag for built-in constructors */
 103     public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR;
 104 
 105     private static final long serialVersionUID = 4252901245508769114L;
 106 
 107     /**
 108      * Constructor
 109      *
 110      * @param name  script function name
 111      * @param arity arity
 112      * @param flags the function flags
 113      */
 114     ScriptFunctionData(final String name, final int arity, final int flags) {
 115         this.name  = name;
 116         this.flags = flags;
 117         setArity(arity);
 118     }
 119 
 120     final int getArity() {
 121         return arity;
 122     }
 123 
 124     final String getDocumentation() {
 125         return documentation != null? documentation : toSource();
 126     }
 127 
 128     final boolean isVariableArity() {
 129         return (flags & IS_VARIABLE_ARITY) != 0;
 130     }
 131 
 132     final boolean isPropertyAccessor() {
 133         return (flags & IS_PROPERTY_ACCESSOR) != 0;
 134     }
 135 
 136     /**
 137      * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final
 138      * @param arity new arity
 139      */
 140     void setArity(final int arity) {
 141         if(arity < 0 || arity > MAX_ARITY) {
 142             throw new IllegalArgumentException(String.valueOf(arity));
 143         }
 144         this.arity = arity;
 145     }
 146 
 147     /**
 148      * Used from nasgen generated code.
 149      *
 150      * @param doc documentation for this function
 151      */
 152     void setDocumentation(final String doc) {
 153         this.documentation = doc;
 154     }
 155 
 156     CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
 157         final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
 158 
 159         if (isConstructor()) {
 160             return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args), null);
 161         }
 162 
 163         return new CompiledFunction(boundInvoker);
 164     }
 165 
 166     /**
 167      * Is this a ScriptFunction generated with strict semantics?
 168      * @return true if strict, false otherwise
 169      */
 170     public final boolean isStrict() {
 171         return (flags & IS_STRICT) != 0;
 172     }
 173 
 174     /**
 175      * Return the complete internal function name for this
 176      * data, not anonymous or similar. May be identical
 177      * @return internal function name
 178      */
 179     protected String getFunctionName() {
 180         return getName();
 181     }
 182 
 183     final boolean isBuiltin() {
 184         return (flags & IS_BUILTIN) != 0;
 185     }
 186 
 187     final boolean isConstructor() {
 188         return (flags & IS_CONSTRUCTOR) != 0;
 189     }
 190 
 191     abstract boolean needsCallee();
 192 
 193     /**
 194      * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
 195      * according to ECMA 10.4.3.
 196      * @return true if this argument must be an object
 197      */
 198     final boolean needsWrappedThis() {
 199         return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0;
 200     }
 201 
 202     String toSource() {
 203         return "function " + (name == null ? "" : name) + "() { [native code] }";
 204     }
 205 
 206     String getName() {
 207         return name;
 208     }
 209 
 210     /**
 211      * Get this function as a String containing its source code. If no source code
 212      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 213      *
 214      * @return string representation of this function
 215      */
 216     @Override
 217     public String toString() {
 218         return name.isEmpty() ? "<anonymous>" : name;
 219     }
 220 
 221     /**
 222      * Verbose description of data
 223      * @return verbose description
 224      */
 225     public String toStringVerbose() {
 226         final StringBuilder sb = new StringBuilder();
 227 
 228         sb.append("name='").
 229                 append(name.isEmpty() ? "<anonymous>" : name).
 230                 append("' ").
 231                 append(code.size()).
 232                 append(" invokers=").
 233                 append(code);
 234 
 235         return sb.toString();
 236     }
 237 
 238     /**
 239      * Pick the best invoker, i.e. the one version of this method with as narrow and specific
 240      * types as possible. If the call site arguments are objects, but boxed primitives we can
 241      * also try to get a primitive version of the method and do an unboxing filter, but then
 242      * we need to insert a guard that checks the argument is really always a boxed primitive
 243      * and not suddenly a "real" object
 244      *
 245      * @param callSiteType callsite type
 246      * @return compiled function object representing the best invoker.
 247      */
 248     final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
 249         return getBestInvoker(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS);
 250     }
 251 
 252     final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
 253         final CompiledFunction cf = getBest(callSiteType, runtimeScope, forbidden);
 254         assert cf != null;
 255         return cf;
 256     }
 257 
 258     final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
 259         if (!isConstructor()) {
 260             throw typeError("not.a.constructor", toSource());
 261         }
 262         // Constructor call sites don't have a "this", but getBest is meant to operate on "callee, this, ..." style
 263         final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope, forbidden);
 264         return cf;
 265     }
 266 
 267     /**
 268      * If we can have lazy code generation, this is a hook to ensure that the code has been compiled.
 269      * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance
 270      */
 271     protected void ensureCompiled() {
 272         //empty
 273     }
 274 
 275     /**
 276      * Return a generic Object/Object invoker for this method. It will ensure code
 277      * is generated, get the most generic of all versions of this function and adapt it
 278      * to Objects.
 279      *
 280      * @param runtimeScope the runtime scope. It can be used to evaluate types of scoped variables to guide the
 281      * optimistic compilation, should the call to this method trigger code compilation. Can be null if current runtime
 282      * scope is not known, but that might cause compilation of code that will need more deoptimization passes.
 283      * @return generic invoker of this script function
 284      */
 285     final MethodHandle getGenericInvoker(final ScriptObject runtimeScope) {
 286         // This method has race conditions both on genericsInvoker and genericsInvoker.invoker, but even if invoked
 287         // concurrently, they'll create idempotent results, so it doesn't matter. We could alternatively implement this
 288         // using java.util.concurrent.AtomicReferenceFieldUpdater, but it's hardly worth it.
 289         final GenericInvokers lgenericInvokers = ensureGenericInvokers();
 290         MethodHandle invoker = lgenericInvokers.invoker;
 291         if(invoker == null) {
 292             lgenericInvokers.invoker = invoker = createGenericInvoker(runtimeScope);
 293         }
 294         return invoker;
 295     }
 296 
 297     private MethodHandle createGenericInvoker(final ScriptObject runtimeScope) {
 298         return makeGenericMethod(getGeneric(runtimeScope).createComposableInvoker());
 299     }
 300 
 301     final MethodHandle getGenericConstructor(final ScriptObject runtimeScope) {
 302         // This method has race conditions both on genericsInvoker and genericsInvoker.constructor, but even if invoked
 303         // concurrently, they'll create idempotent results, so it doesn't matter. We could alternatively implement this
 304         // using java.util.concurrent.AtomicReferenceFieldUpdater, but it's hardly worth it.
 305         final GenericInvokers lgenericInvokers = ensureGenericInvokers();
 306         MethodHandle constructor = lgenericInvokers.constructor;
 307         if(constructor == null) {
 308             lgenericInvokers.constructor = constructor = createGenericConstructor(runtimeScope);
 309         }
 310         return constructor;
 311     }
 312 
 313     private MethodHandle createGenericConstructor(final ScriptObject runtimeScope) {
 314         return makeGenericMethod(getGeneric(runtimeScope).createComposableConstructor());
 315     }
 316 
 317     private GenericInvokers ensureGenericInvokers() {
 318         GenericInvokers lgenericInvokers = genericInvokers;
 319         if(lgenericInvokers == null) {
 320             genericInvokers = lgenericInvokers = new GenericInvokers();
 321         }
 322         return lgenericInvokers;
 323     }
 324 
 325     private static MethodType widen(final MethodType cftype) {
 326         final Class<?>[] paramTypes = new Class<?>[cftype.parameterCount()];
 327         for (int i = 0; i < cftype.parameterCount(); i++) {
 328             paramTypes[i] = cftype.parameterType(i).isPrimitive() ? cftype.parameterType(i) : Object.class;
 329         }
 330         return MH.type(cftype.returnType(), paramTypes);
 331     }
 332 
 333     /**
 334      * Used to find an apply to call version that fits this callsite.
 335      * We cannot just, as in the normal matcher case, return e.g. (Object, Object, int)
 336      * for (Object, Object, int, int, int) or we will destroy the semantics and get
 337      * a function that, when padded with undefined values, behaves differently
 338      * @param type actual call site type
 339      * @return apply to call that perfectly fits this callsite or null if none found
 340      */
 341     CompiledFunction lookupExactApplyToCall(final MethodType type) {
 342         for (final CompiledFunction cf : code) {
 343             if (!cf.isApplyToCall()) {
 344                 continue;
 345             }
 346 
 347             final MethodType cftype = cf.type();
 348             if (cftype.parameterCount() != type.parameterCount()) {
 349                 continue;
 350             }
 351 
 352             if (widen(cftype).equals(widen(type))) {
 353                 return cf;
 354             }
 355         }
 356 
 357         return null;
 358     }
 359 
 360     CompiledFunction pickFunction(final MethodType callSiteType, final boolean canPickVarArg) {
 361         for (final CompiledFunction candidate : code) {
 362             if (candidate.matchesCallSite(callSiteType, canPickVarArg)) {
 363                 return candidate;
 364             }
 365         }
 366         return null;
 367     }
 368 
 369     /**
 370      * Returns the best function for the specified call site type.
 371      * @param callSiteType The call site type. Call site types are expected to have the form
 372      * {@code (callee, this[, args...])}.
 373      * @param runtimeScope the runtime scope. It can be used to evaluate types of scoped variables to guide the
 374      * optimistic compilation, should the call to this method trigger code compilation. Can be null if current runtime
 375      * scope is not known, but that might cause compilation of code that will need more deoptimization passes.
 376      * @return the best function for the specified call site type.
 377      */
 378     abstract CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden);
 379 
 380     boolean isValidCallSite(final MethodType callSiteType) {
 381         return callSiteType.parameterCount() >= 2  && // Must have at least (callee, this)
 382                callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class); // Callee must be assignable from script function
 383     }
 384 
 385     CompiledFunction getGeneric(final ScriptObject runtimeScope) {
 386         return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
 387     }
 388 
 389     /**
 390      * Get a method type for a generic invoker.
 391      * @return the method type for the generic invoker
 392      */
 393     abstract MethodType getGenericType();
 394 
 395     /**
 396      * Allocates an object using this function's allocator.
 397      *
 398      * @param map the property map for the allocated object.
 399      * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator.
 400      */
 401     ScriptObject allocate(final PropertyMap map) {
 402         return null;
 403     }
 404 
 405     /**
 406      * Get the property map to use for objects allocated by this function.
 407      *
 408      * @param prototype the prototype of the allocated object
 409      * @return the property map for allocated objects.
 410      */
 411     PropertyMap getAllocatorMap(final ScriptObject prototype) {
 412         return null;
 413     }
 414 
 415     /**
 416      * This method is used to create the immutable portion of a bound function.
 417      * See {@link ScriptFunction#createBound(Object, Object[])}
 418      *
 419      * @param fn the original function being bound
 420      * @param self this reference to bind. Can be null.
 421      * @param args additional arguments to bind. Can be null.
 422      */
 423     ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) {
 424         final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
 425         final int length = args == null ? 0 : args.length;
 426         // Clear the callee and this flags
 427         final int boundFlags = flags & ~NEEDS_CALLEE & ~USES_THIS;
 428 
 429         final List<CompiledFunction> boundList = new LinkedList<>();
 430         final ScriptObject runtimeScope = fn.getScope();
 431         final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope), null);
 432         boundList.add(bind(bindTarget, fn, self, allArgs));
 433 
 434         return new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, boundFlags);
 435     }
 436 
 437     /**
 438      * Convert this argument for non-strict functions according to ES 10.4.3
 439      *
 440      * @param thiz the this argument
 441      *
 442      * @return the converted this object
 443      */
 444     private Object convertThisObject(final Object thiz) {
 445         return needsWrappedThis() ? wrapThis(thiz) : thiz;
 446     }
 447 
 448     static Object wrapThis(final Object thiz) {
 449         if (!(thiz instanceof ScriptObject)) {
 450             if (JSType.nullOrUndefined(thiz)) {
 451                 return Context.getGlobal();
 452             }
 453 
 454             if (isPrimitiveThis(thiz)) {
 455                 return Context.getGlobal().wrapAsObject(thiz);
 456             }
 457         }
 458 
 459         return thiz;
 460     }
 461 
 462     static boolean isPrimitiveThis(final Object obj) {
 463         return JSType.isString(obj) || obj instanceof Number || obj instanceof Boolean;
 464     }
 465 
 466     /**
 467      * Creates an invoker method handle for a bound function.
 468      *
 469      * @param targetFn the function being bound
 470      * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or
 471      * any of its specializations.
 472      * @param self the "this" value being bound
 473      * @param args additional arguments being bound
 474      *
 475      * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting
 476      * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting
 477      * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed
 478      * to the original invoker on invocation.
 479      */
 480     private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) {
 481         // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound
 482         // in the target and will be ignored anyway.
 483         final boolean isTargetBound = targetFn.isBoundFunction();
 484 
 485         final boolean needsCallee = needsCallee(originalInvoker);
 486         assert needsCallee == needsCallee() : "callee contract violation 2";
 487         assert !(isTargetBound && needsCallee); // already bound functions don't need a callee
 488 
 489         final Object boundSelf = isTargetBound ? null : convertThisObject(self);
 490         final MethodHandle boundInvoker;
 491 
 492         if (isVarArg(originalInvoker)) {
 493             // First, bind callee and this without arguments
 494             final MethodHandle noArgBoundInvoker;
 495 
 496             if (isTargetBound) {
 497                 // Don't bind either callee or this
 498                 noArgBoundInvoker = originalInvoker;
 499             } else if (needsCallee) {
 500                 // Bind callee and this
 501                 noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf);
 502             } else {
 503                 // Only bind this
 504                 noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf);
 505             }
 506             // Now bind arguments
 507             if (args.length > 0) {
 508                 boundInvoker = varArgBinder(noArgBoundInvoker, args);
 509             } else {
 510                 boundInvoker = noArgBoundInvoker;
 511             }
 512         } else {
 513             // If target is already bound, insert additional bound arguments after "this" argument, at position 1.
 514             final int argInsertPos = isTargetBound ? 1 : 0;
 515             final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : needsCallee  ? 2 : 1))];
 516             int next = 0;
 517             if (!isTargetBound) {
 518                 if (needsCallee) {
 519                     boundArgs[next++] = targetFn;
 520                 }
 521                 boundArgs[next++] = boundSelf;
 522             }
 523             // If more bound args were specified than the function can take, we'll just drop those.
 524             System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next);
 525             // If target is already bound, insert additional bound arguments after "this" argument, at position 1;
 526             // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions
 527             // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args
 528             // start at position 1. If the function is not bound, we start inserting arguments at position 0.
 529             boundInvoker = MH.insertArguments(originalInvoker, argInsertPos, boundArgs);
 530         }
 531 
 532         if (isTargetBound) {
 533             return boundInvoker;
 534         }
 535 
 536         // If the target is not already bound, add a dropArguments that'll throw away the passed this
 537         return MH.dropArguments(boundInvoker, 0, Object.class);
 538     }
 539 
 540     /**
 541      * Creates a constructor method handle for a bound function using the passed constructor handle.
 542      *
 543      * @param originalConstructor the constructor handle to bind. It must be a composed constructor.
 544      * @param fn the function being bound
 545      * @param args arguments being bound
 546      *
 547      * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never
 548      * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor
 549      * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if
 550      * this script function data object has no constructor handle, null is returned.
 551      */
 552     private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) {
 553         assert originalConstructor != null;
 554 
 555         // If target function is already bound, don't bother binding the callee.
 556         final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor :
 557             MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class);
 558 
 559         if (args.length == 0) {
 560             return calleeBoundConstructor;
 561         }
 562 
 563         if (isVarArg(calleeBoundConstructor)) {
 564             return varArgBinder(calleeBoundConstructor, args);
 565         }
 566 
 567         final Object[] boundArgs;
 568 
 569         final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1;
 570         if (args.length <= maxArgCount) {
 571             boundArgs = args;
 572         } else {
 573             boundArgs = new Object[maxArgCount];
 574             System.arraycopy(args, 0, boundArgs, 0, maxArgCount);
 575         }
 576 
 577         return MH.insertArguments(calleeBoundConstructor, 1, boundArgs);
 578     }
 579 
 580     /**
 581      * Takes a method handle, and returns a potentially different method handle that can be used in
 582      * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}.
 583      * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into
 584      * {@code Object} as well, except for the following ones:
 585      * <ul>
 586      *   <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
 587      *   <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself
 588      *   (callee) as an argument.</li>
 589      * </ul>
 590      *
 591      * @param mh the original method handle
 592      *
 593      * @return the new handle, conforming to the rules above.
 594      */
 595     private static MethodHandle makeGenericMethod(final MethodHandle mh) {
 596         final MethodType type = mh.type();
 597         final MethodType newType = makeGenericType(type);
 598         return type.equals(newType) ? mh : mh.asType(newType);
 599     }
 600 
 601     private static MethodType makeGenericType(final MethodType type) {
 602         MethodType newType = type.generic();
 603         if (isVarArg(type)) {
 604             newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
 605         }
 606         if (needsCallee(type)) {
 607             newType = newType.changeParameterType(0, ScriptFunction.class);
 608         }
 609         return newType;
 610     }
 611 
 612     /**
 613      * Execute this script function.
 614      *
 615      * @param self  Target object.
 616      * @param arguments  Call arguments.
 617      * @return ScriptFunction result.
 618      *
 619      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 620      */
 621     Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable {
 622         final MethodHandle mh      = getGenericInvoker(fn.getScope());
 623         final Object       selfObj = convertThisObject(self);
 624         final Object[]     args    = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 625 
 626         DebuggerSupport.notifyInvoke(mh);
 627 
 628         if (isVarArg(mh)) {
 629             if (needsCallee(mh)) {
 630                 return mh.invokeExact(fn, selfObj, args);
 631             }
 632             return mh.invokeExact(selfObj, args);
 633         }
 634 
 635         final int paramCount = mh.type().parameterCount();
 636         if (needsCallee(mh)) {
 637             switch (paramCount) {
 638             case 2:
 639                 return mh.invokeExact(fn, selfObj);
 640             case 3:
 641                 return mh.invokeExact(fn, selfObj, getArg(args, 0));
 642             case 4:
 643                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1));
 644             case 5:
 645                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 646             case 6:
 647                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 648             case 7:
 649                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 650             case 8:
 651                 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 652             default:
 653                 return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args));
 654             }
 655         }
 656 
 657         switch (paramCount) {
 658         case 1:
 659             return mh.invokeExact(selfObj);
 660         case 2:
 661             return mh.invokeExact(selfObj, getArg(args, 0));
 662         case 3:
 663             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
 664         case 4:
 665             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 666         case 5:
 667             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 668         case 6:
 669             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 670         case 7:
 671             return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 672         default:
 673             return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args));
 674         }
 675     }
 676 
 677     Object construct(final ScriptFunction fn, final Object... arguments) throws Throwable {
 678         final MethodHandle mh   = getGenericConstructor(fn.getScope());
 679         final Object[]     args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
 680 
 681         DebuggerSupport.notifyInvoke(mh);
 682 
 683         if (isVarArg(mh)) {
 684             if (needsCallee(mh)) {
 685                 return mh.invokeExact(fn, args);
 686             }
 687             return mh.invokeExact(args);
 688         }
 689 
 690         final int paramCount = mh.type().parameterCount();
 691         if (needsCallee(mh)) {
 692             switch (paramCount) {
 693             case 1:
 694                 return mh.invokeExact(fn);
 695             case 2:
 696                 return mh.invokeExact(fn, getArg(args, 0));
 697             case 3:
 698                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1));
 699             case 4:
 700                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2));
 701             case 5:
 702                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 703             case 6:
 704                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 705             case 7:
 706                 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 707             default:
 708                 return mh.invokeWithArguments(withArguments(fn, paramCount, args));
 709             }
 710         }
 711 
 712         switch (paramCount) {
 713         case 0:
 714             return mh.invokeExact();
 715         case 1:
 716             return mh.invokeExact(getArg(args, 0));
 717         case 2:
 718             return mh.invokeExact(getArg(args, 0), getArg(args, 1));
 719         case 3:
 720             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2));
 721         case 4:
 722             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
 723         case 5:
 724             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
 725         case 6:
 726             return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
 727         default:
 728             return mh.invokeWithArguments(withArguments(null, paramCount, args));
 729         }
 730     }
 731 
 732     private static Object getArg(final Object[] args, final int i) {
 733         return i < args.length ? args[i] : UNDEFINED;
 734     }
 735 
 736     private static Object[] withArguments(final ScriptFunction fn, final int argCount, final Object[] args) {
 737         final Object[] finalArgs = new Object[argCount];
 738 
 739         int nextArg = 0;
 740         if (fn != null) {
 741             //needs callee
 742             finalArgs[nextArg++] = fn;
 743         }
 744 
 745         // Don't add more args that there is argCount in the handle (including self and callee).
 746         for (int i = 0; i < args.length && nextArg < argCount;) {
 747             finalArgs[nextArg++] = args[i++];
 748         }
 749 
 750         // If we have fewer args than argCount, pad with undefined.
 751         while (nextArg < argCount) {
 752             finalArgs[nextArg++] = UNDEFINED;
 753         }
 754 
 755         return finalArgs;
 756     }
 757 
 758     private static Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) {
 759         final Object[] finalArgs = new Object[argCount];
 760 
 761         int nextArg = 0;
 762         if (fn != null) {
 763             //needs callee
 764             finalArgs[nextArg++] = fn;
 765         }
 766         finalArgs[nextArg++] = self;
 767 
 768         // Don't add more args that there is argCount in the handle (including self and callee).
 769         for (int i = 0; i < args.length && nextArg < argCount;) {
 770             finalArgs[nextArg++] = args[i++];
 771         }
 772 
 773         // If we have fewer args than argCount, pad with undefined.
 774         while (nextArg < argCount) {
 775             finalArgs[nextArg++] = UNDEFINED;
 776         }
 777 
 778         return finalArgs;
 779     }
 780     /**
 781      * Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the
 782      * vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on
 783      * invocation
 784      *
 785      * @param mh the handle
 786      * @param args the bound arguments
 787      *
 788      * @return the bound method handle
 789      */
 790     private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) {
 791         assert args != null;
 792         assert args.length > 0;
 793         return MH.filterArguments(mh, mh.type().parameterCount() - 1, MH.bindTo(BIND_VAR_ARGS, args));
 794     }
 795 
 796     /**
 797      * Heuristic to figure out if the method handle has a callee argument. If it's type is
 798      * {@code (ScriptFunction, ...)}, then we'll assume it has a callee argument. We need this as
 799      * the constructor above is not passed this information, and can't just blindly assume it's false
 800      * (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
 801      * they also always receive a callee).
 802      *
 803      * @param mh the examined method handle
 804      *
 805      * @return true if the method handle expects a callee, false otherwise
 806      */
 807     protected static boolean needsCallee(final MethodHandle mh) {
 808         return needsCallee(mh.type());
 809     }
 810 
 811     static boolean needsCallee(final MethodType type) {
 812         final int length = type.parameterCount();
 813 
 814         if (length == 0) {
 815             return false;
 816         }
 817 
 818         final Class<?> param0 = type.parameterType(0);
 819         return param0 == ScriptFunction.class || param0 == boolean.class && length > 1 && type.parameterType(1) == ScriptFunction.class;
 820     }
 821 
 822     /**
 823      * Check if a javascript function methodhandle is a vararg handle
 824      *
 825      * @param mh method handle to check
 826      *
 827      * @return true if vararg
 828      */
 829     protected static boolean isVarArg(final MethodHandle mh) {
 830         return isVarArg(mh.type());
 831     }
 832 
 833     static boolean isVarArg(final MethodType type) {
 834         return type.parameterType(type.parameterCount() - 1).isArray();
 835     }
 836 
 837     /**
 838      * Is this ScriptFunction declared in a dynamic context
 839      * @return true if in dynamic context, false if not or irrelevant
 840      */
 841     public boolean inDynamicContext() {
 842         return false;
 843     }
 844 
 845     @SuppressWarnings("unused")
 846     private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) {
 847         if (array2 == null) {
 848             // Must clone it, as we can't allow the receiving method to alter the array
 849             return array1.clone();
 850         }
 851 
 852         final int l2 = array2.length;
 853         if (l2 == 0) {
 854             return array1.clone();
 855         }
 856 
 857         final int l1 = array1.length;
 858         final Object[] concat = new Object[l1 + l2];
 859         System.arraycopy(array1, 0, concat, 0, l1);
 860         System.arraycopy(array2, 0, concat, l1, l2);
 861 
 862         return concat;
 863     }
 864 
 865     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
 866         return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types));
 867     }
 868 
 869     /**
 870      * This class is used to hold the generic invoker and generic constructor pair. It is structured in this way since
 871      * most functions will never use them, so this way ScriptFunctionData only pays storage cost for one null reference
 872      * to the GenericInvokers object, instead of two null references for the two method handles.
 873      */
 874     private static final class GenericInvokers {
 875         volatile MethodHandle invoker;
 876         volatile MethodHandle constructor;
 877     }
 878 
 879     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
 880         in.defaultReadObject();
 881         code = new LinkedList<>();
 882     }
 883 }