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