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