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