Thu, 10 Sep 2015 19:09:23 +0530
8135332: ScriptFunction constructor should use is bound and is strict check rather than checking for 'arguments' and 'caller'
Reviewed-by: attila, hannesw
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 package jdk.nashorn.internal.runtime;
27 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
28 import static jdk.nashorn.internal.lookup.Lookup.MH;
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
31 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
32 import java.lang.invoke.MethodHandle;
33 import java.lang.invoke.MethodHandles;
34 import java.lang.invoke.MethodType;
35 import java.lang.invoke.SwitchPoint;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.concurrent.atomic.LongAdder;
43 import jdk.internal.dynalink.CallSiteDescriptor;
44 import jdk.internal.dynalink.linker.GuardedInvocation;
45 import jdk.internal.dynalink.linker.LinkRequest;
46 import jdk.internal.dynalink.support.Guards;
47 import jdk.nashorn.internal.codegen.ApplySpecialization;
48 import jdk.nashorn.internal.codegen.Compiler;
49 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
50 import jdk.nashorn.internal.objects.Global;
51 import jdk.nashorn.internal.objects.NativeFunction;
52 import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
53 import jdk.nashorn.internal.runtime.linker.Bootstrap;
54 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
55 import jdk.nashorn.internal.runtime.logging.DebugLogger;
57 /**
58 * Runtime representation of a JavaScript function. This class has only private
59 * and protected constructors. There are no *public* constructors - but only
60 * factory methods that follow the naming pattern "createXYZ".
61 */
62 public class ScriptFunction extends ScriptObject {
64 /**
65 * Method handle for prototype getter for this ScriptFunction
66 */
67 public static final MethodHandle G$PROTOTYPE = findOwnMH_S("G$prototype", Object.class, Object.class);
69 /**
70 * Method handle for prototype setter for this ScriptFunction
71 */
72 public static final MethodHandle S$PROTOTYPE = findOwnMH_S("S$prototype", void.class, Object.class, Object.class);
74 /**
75 * Method handle for length getter for this ScriptFunction
76 */
77 public static final MethodHandle G$LENGTH = findOwnMH_S("G$length", int.class, Object.class);
79 /**
80 * Method handle for name getter for this ScriptFunction
81 */
82 public static final MethodHandle G$NAME = findOwnMH_S("G$name", Object.class, Object.class);
84 /**
85 * Method handle used for implementing sync() in mozilla_compat
86 */
87 public static final MethodHandle INVOKE_SYNC = findOwnMH_S("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
89 /**
90 * Method handle for allocate function for this ScriptFunction
91 */
92 static final MethodHandle ALLOCATE = findOwnMH_V("allocate", Object.class);
94 private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class);
96 private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
98 /**
99 * method handle to scope getter for this ScriptFunction
100 */
101 public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
103 private static final MethodHandle IS_FUNCTION_MH = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
105 private static final MethodHandle IS_APPLY_FUNCTION = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class);
107 private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH_S("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
109 private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH_S("addZerothElement", Object[].class, Object[].class, Object.class);
111 private static final MethodHandle WRAP_THIS = MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, "wrapThis", MH.type(Object.class, Object.class));
113 // various property maps used for different kinds of functions
114 // property map for anonymous function that serves as Function.prototype
115 private static final PropertyMap anonmap$;
116 // property map for strict mode functions
117 private static final PropertyMap strictmodemap$;
118 // property map for bound functions
119 private static final PropertyMap boundfunctionmap$;
120 // property map for non-strict, non-bound functions.
121 private static final PropertyMap map$;
123 // Marker object for lazily initialized prototype object
124 private static final Object LAZY_PROTOTYPE = new Object();
126 private static PropertyMap createStrictModeMap(final PropertyMap map) {
127 final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
128 PropertyMap newMap = map;
129 // Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
130 newMap = newMap.addPropertyNoHistory(map.newUserAccessors("arguments", flags));
131 newMap = newMap.addPropertyNoHistory(map.newUserAccessors("caller", flags));
132 return newMap;
133 }
135 private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) {
136 // Bound function map is same as strict function map, but additionally lacks the "prototype" property, see
137 // ECMAScript 5.1 section 15.3.4.5
138 return strictModeMap.deleteProperty(strictModeMap.findProperty("prototype"));
139 }
141 static {
142 anonmap$ = PropertyMap.newMap();
143 final ArrayList<Property> properties = new ArrayList<>(3);
144 properties.add(AccessorProperty.create("prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE));
145 properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null));
146 properties.add(AccessorProperty.create("name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null));
147 map$ = PropertyMap.newMap(properties);
148 strictmodemap$ = createStrictModeMap(map$);
149 boundfunctionmap$ = createBoundFunctionMap(strictmodemap$);
150 }
152 private static boolean isStrict(final int flags) {
153 return (flags & ScriptFunctionData.IS_STRICT) != 0;
154 }
156 // Choose the map based on strict mode!
157 private static PropertyMap getMap(final boolean strict) {
158 return strict ? strictmodemap$ : map$;
159 }
161 /**
162 * The parent scope.
163 */
164 private final ScriptObject scope;
166 private final ScriptFunctionData data;
168 /**
169 * The property map used for newly allocated object when function is used as
170 * constructor.
171 */
172 protected PropertyMap allocatorMap;
174 /**
175 * Reference to constructor prototype.
176 */
177 protected Object prototype;
179 /**
180 * Constructor
181 *
182 * @param data static function data
183 * @param map property map
184 * @param scope scope
185 */
186 private ScriptFunction(
187 final ScriptFunctionData data,
188 final PropertyMap map,
189 final ScriptObject scope,
190 final Global global) {
192 super(map);
194 if (Context.DEBUG) {
195 constructorCount.increment();
196 }
198 this.data = data;
199 this.scope = scope;
200 this.setInitialProto(global.getFunctionPrototype());
201 this.prototype = LAZY_PROTOTYPE;
203 // We have to fill user accessor functions late as these are stored
204 // in this object rather than in the PropertyMap of this object.
205 assert objectSpill == null;
206 if (isStrict() || isBoundFunction()) {
207 final ScriptFunction typeErrorThrower = global.getTypeErrorThrower();
208 initUserAccessors("arguments", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
209 initUserAccessors("caller", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
210 }
211 }
213 /**
214 * Constructor
215 *
216 * @param name function name
217 * @param methodHandle method handle to function (if specializations are
218 * present, assumed to be most generic)
219 * @param map property map
220 * @param scope scope
221 * @param specs specialized version of this function - other method handles
222 * @param flags {@link ScriptFunctionData} flags
223 */
224 private ScriptFunction(
225 final String name,
226 final MethodHandle methodHandle,
227 final PropertyMap map,
228 final ScriptObject scope,
229 final Specialization[] specs,
230 final int flags,
231 final Global global) {
232 this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope, global);
233 }
235 /**
236 * Constructor
237 *
238 * @param name name of function
239 * @param methodHandle handle for invocation
240 * @param scope scope object
241 * @param specs specialized versions of this method, if available, null
242 * otherwise
243 * @param flags {@link ScriptFunctionData} flags
244 */
245 private ScriptFunction(
246 final String name,
247 final MethodHandle methodHandle,
248 final ScriptObject scope,
249 final Specialization[] specs,
250 final int flags) {
251 this(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags, Global.instance());
252 }
254 /**
255 * Constructor called by Nasgen generated code, zero added members, use the
256 * default map. Creates builtin functions only.
257 *
258 * @param name name of function
259 * @param invokeHandle handle for invocation
260 * @param specs specialized versions of this method, if available, null
261 * otherwise
262 */
263 protected ScriptFunction(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
264 this(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR, Global.instance());
265 }
267 /**
268 * Constructor called by Nasgen generated code, non zero member count, use
269 * the map passed as argument. Creates builtin functions only.
270 *
271 * @param name name of function
272 * @param invokeHandle handle for invocation
273 * @param map initial property map
274 * @param specs specialized versions of this method, if available, null
275 * otherwise
276 */
277 protected ScriptFunction(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
278 this(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR, Global.instance());
279 }
281 // Factory methods to create various functions
282 /**
283 * Factory method called by compiler generated code for functions that need
284 * parent scope.
285 *
286 * @param constants the generated class' constant array
287 * @param index the index of the {@code RecompilableScriptFunctionData}
288 * object in the constants array.
289 * @param scope the parent scope object
290 * @return a newly created function object
291 */
292 public static ScriptFunction create(final Object[] constants, final int index, final ScriptObject scope) {
293 final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constants[index];
294 return new ScriptFunction(data, getMap(data.isStrict()), scope, Global.instance());
295 }
297 /**
298 * Factory method called by compiler generated code for functions that don't
299 * need parent scope.
300 *
301 * @param constants the generated class' constant array
302 * @param index the index of the {@code RecompilableScriptFunctionData}
303 * object in the constants array.
304 * @return a newly created function object
305 */
306 public static ScriptFunction create(final Object[] constants, final int index) {
307 return create(constants, index, null);
308 }
310 /**
311 * Create anonymous function that serves as Function.prototype
312 *
313 * @return anonymous function object
314 */
315 public static ScriptFunction createAnonymous() {
316 return new ScriptFunction("", GlobalFunctions.ANONYMOUS, anonmap$, null);
317 }
319 // builtin function create helper factory
320 private static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
321 final ScriptFunction func = new ScriptFunction(name, methodHandle, null, specs, flags);
322 func.setPrototype(UNDEFINED);
323 // Non-constructor built-in functions do not have "prototype" property
324 func.deleteOwnProperty(func.getMap().findProperty("prototype"));
326 return func;
327 }
329 /**
330 * Factory method for non-constructor built-in functions
331 *
332 * @param name function name
333 * @param methodHandle handle for invocation
334 * @param specs specialized versions of function if available, null
335 * otherwise
336 * @return new ScriptFunction
337 */
338 public static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
339 return ScriptFunction.createBuiltin(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
340 }
342 /**
343 * Factory method for non-constructor built-in functions
344 *
345 * @param name function name
346 * @param methodHandle handle for invocation
347 * @return new ScriptFunction
348 */
349 public static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle) {
350 return ScriptFunction.createBuiltin(name, methodHandle, null);
351 }
353 /**
354 * Factory method for non-constructor built-in, strict functions
355 *
356 * @param name function name
357 * @param methodHandle handle for invocation
358 * @return new ScriptFunction
359 */
360 public static ScriptFunction createStrictBuiltin(final String name, final MethodHandle methodHandle) {
361 return ScriptFunction.createBuiltin(name, methodHandle, null, ScriptFunctionData.IS_BUILTIN | ScriptFunctionData.IS_STRICT);
362 }
364 // Subclass to represent bound functions
365 private static class Bound extends ScriptFunction {
366 private final ScriptFunction target;
368 Bound(final ScriptFunctionData boundData, final ScriptFunction target) {
369 super(boundData, boundfunctionmap$, null, Global.instance());
370 setPrototype(ScriptRuntime.UNDEFINED);
371 this.target = target;
372 }
374 @Override
375 protected ScriptFunction getTargetFunction() {
376 return target;
377 }
378 }
380 /**
381 * Creates a version of this function bound to a specific "self" and other
382 * arguments, as per {@code Function.prototype.bind} functionality in
383 * ECMAScript 5.1 section 15.3.4.5.
384 *
385 * @param self the self to bind to this function. Can be null (in which
386 * case, null is bound as this).
387 * @param args additional arguments to bind to this function. Can be null or
388 * empty to not bind additional arguments.
389 * @return a function with the specified self and parameters bound.
390 */
391 public final ScriptFunction createBound(final Object self, final Object[] args) {
392 return new Bound(data.makeBoundFunctionData(this, self, args), getTargetFunction());
393 }
395 /**
396 * Create a function that invokes this function synchronized on {@code sync}
397 * or the self object of the invocation.
398 *
399 * @param sync the Object to synchronize on, or undefined
400 * @return synchronized function
401 */
402 public final ScriptFunction createSynchronized(final Object sync) {
403 final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync);
404 return createBuiltin(getName(), mh);
405 }
407 @Override
408 public String getClassName() {
409 return "Function";
410 }
412 /**
413 * ECMA 15.3.5.3 [[HasInstance]] (V) Step 3 if "prototype" value is not an
414 * Object, throw TypeError
415 */
416 @Override
417 public boolean isInstance(final ScriptObject instance) {
418 final Object basePrototype = getTargetFunction().getPrototype();
419 if (!(basePrototype instanceof ScriptObject)) {
420 throw typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype));
421 }
423 for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
424 if (proto == basePrototype) {
425 return true;
426 }
427 }
429 return false;
430 }
432 /**
433 * Returns the target function for this function. If the function was not
434 * created using {@link #createBound(Object, Object[])}, its target
435 * function is itself. If it is bound, its target function is the target
436 * function of the function it was made from (therefore, the target function
437 * is always the final, unbound recipient of the calls).
438 *
439 * @return the target function for this function.
440 */
441 protected ScriptFunction getTargetFunction() {
442 return this;
443 }
445 final boolean isBoundFunction() {
446 return getTargetFunction() != this;
447 }
449 /**
450 * Set the arity of this ScriptFunction
451 *
452 * @param arity arity
453 */
454 public final void setArity(final int arity) {
455 data.setArity(arity);
456 }
458 /**
459 * Is this a ECMAScript 'use strict' function?
460 *
461 * @return true if function is in strict mode
462 */
463 public final boolean isStrict() {
464 return data.isStrict();
465 }
467 /**
468 * Returns true if this is a non-strict, non-built-in function that requires
469 * non-primitive this argument according to ECMA 10.4.3.
470 *
471 * @return true if this argument must be an object
472 */
473 public final boolean needsWrappedThis() {
474 return data.needsWrappedThis();
475 }
477 private static boolean needsWrappedThis(final Object fn) {
478 return fn instanceof ScriptFunction ? ((ScriptFunction) fn).needsWrappedThis() : false;
479 }
481 /**
482 * Execute this script function.
483 *
484 * @param self Target object.
485 * @param arguments Call arguments.
486 * @return ScriptFunction result.
487 * @throws Throwable if there is an exception/error with the invocation or
488 * thrown from it
489 */
490 final Object invoke(final Object self, final Object... arguments) throws Throwable {
491 if (Context.DEBUG) {
492 invokes.increment();
493 }
494 return data.invoke(this, self, arguments);
495 }
497 /**
498 * Execute this script function as a constructor.
499 *
500 * @param arguments Call arguments.
501 * @return Newly constructed result.
502 * @throws Throwable if there is an exception/error with the invocation or
503 * thrown from it
504 */
505 final Object construct(final Object... arguments) throws Throwable {
506 return data.construct(this, arguments);
507 }
509 /**
510 * Allocate function. Called from generated {@link ScriptObject} code for
511 * allocation as a factory method
512 *
513 * @return a new instance of the {@link ScriptObject} whose allocator this
514 * is
515 */
516 @SuppressWarnings("unused")
517 private Object allocate() {
518 if (Context.DEBUG) {
519 allocations.increment();
520 }
522 assert !isBoundFunction(); // allocate never invoked on bound functions
524 final ScriptObject object = data.allocate(getAllocatorMap());
526 if (object != null) {
527 final Object prototype = getPrototype();
528 if (prototype instanceof ScriptObject) {
529 object.setInitialProto((ScriptObject) prototype);
530 }
532 if (object.getProto() == null) {
533 object.setInitialProto(getObjectPrototype());
534 }
535 }
537 return object;
538 }
540 private PropertyMap getAllocatorMap() {
541 if (allocatorMap == null) {
542 allocatorMap = data.getAllocatorMap();
543 }
544 return allocatorMap;
545 }
547 /**
548 * Return Object.prototype - used by "allocate"
549 *
550 * @return Object.prototype
551 */
552 protected final ScriptObject getObjectPrototype() {
553 return Global.objectPrototype();
554 }
556 @Override
557 public final String safeToString() {
558 return toSource();
559 }
561 @Override
562 public final String toString() {
563 return data.toString();
564 }
566 /**
567 * Get this function as a String containing its source code. If no source
568 * code exists in this ScriptFunction, its contents will be displayed as
569 * {@code [native code]}
570 *
571 * @return string representation of this function's source
572 */
573 public final String toSource() {
574 return data.toSource();
575 }
577 /**
578 * Get the prototype object for this function
579 *
580 * @return prototype
581 */
582 public final Object getPrototype() {
583 if (prototype == LAZY_PROTOTYPE) {
584 prototype = new PrototypeObject(this);
585 }
586 return prototype;
587 }
589 /**
590 * Set the prototype object for this function
591 *
592 * @param newPrototype new prototype object
593 */
594 public final void setPrototype(Object newPrototype) {
595 if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
596 // Replace our current allocator map with one that is associated with the new prototype.
597 allocatorMap = allocatorMap.changeProto((ScriptObject) newPrototype);
598 }
599 this.prototype = newPrototype;
600 }
602 /**
603 * Return the invoke handle bound to a given ScriptObject self reference. If
604 * callee parameter is required result is rebound to this.
605 *
606 * @param self self reference
607 * @return bound invoke handle
608 */
609 public final MethodHandle getBoundInvokeHandle(final Object self) {
610 return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), self);
611 }
613 /**
614 * Bind the method handle to this {@code ScriptFunction} instance if it
615 * needs a callee parameter. If this function's method handles don't have a
616 * callee parameter, the handle is returned unchanged.
617 *
618 * @param methodHandle the method handle to potentially bind to this
619 * function instance.
620 * @return the potentially bound method handle
621 */
622 private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
623 return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
625 }
627 /**
628 * Get the name for this function
629 *
630 * @return the name
631 */
632 public final String getName() {
633 return data.getName();
634 }
636 /**
637 * Get the scope for this function
638 *
639 * @return the scope
640 */
641 public final ScriptObject getScope() {
642 return scope;
643 }
645 /**
646 * Prototype getter for this ScriptFunction - follows the naming convention
647 * used by Nasgen and the code generator
648 *
649 * @param self self reference
650 * @return self's prototype
651 */
652 public static Object G$prototype(final Object self) {
653 return self instanceof ScriptFunction
654 ? ((ScriptFunction) self).getPrototype()
655 : UNDEFINED;
656 }
658 /**
659 * Prototype setter for this ScriptFunction - follows the naming convention
660 * used by Nasgen and the code generator
661 *
662 * @param self self reference
663 * @param prototype prototype to set
664 */
665 public static void S$prototype(final Object self, final Object prototype) {
666 if (self instanceof ScriptFunction) {
667 ((ScriptFunction) self).setPrototype(prototype);
668 }
669 }
671 /**
672 * Length getter - ECMA 15.3.3.2: Function.length
673 *
674 * @param self self reference
675 * @return length
676 */
677 public static int G$length(final Object self) {
678 if (self instanceof ScriptFunction) {
679 return ((ScriptFunction) self).data.getArity();
680 }
682 return 0;
683 }
685 /**
686 * Name getter - ECMA Function.name
687 *
688 * @param self self refence
689 * @return the name, or undefined if none
690 */
691 public static Object G$name(final Object self) {
692 if (self instanceof ScriptFunction) {
693 return ((ScriptFunction) self).getName();
694 }
696 return UNDEFINED;
697 }
699 /**
700 * Get the prototype for this ScriptFunction
701 *
702 * @param constructor constructor
703 * @return prototype, or null if given constructor is not a ScriptFunction
704 */
705 public static ScriptObject getPrototype(final ScriptFunction constructor) {
706 if (constructor != null) {
707 final Object proto = constructor.getPrototype();
708 if (proto instanceof ScriptObject) {
709 return (ScriptObject) proto;
710 }
711 }
713 return null;
714 }
716 // These counters are updated only in debug mode.
717 private static LongAdder constructorCount;
718 private static LongAdder invokes;
719 private static LongAdder allocations;
721 static {
722 if (Context.DEBUG) {
723 constructorCount = new LongAdder();
724 invokes = new LongAdder();
725 allocations = new LongAdder();
726 }
727 }
729 /**
730 * @return the constructorCount
731 */
732 public static long getConstructorCount() {
733 return constructorCount.longValue();
734 }
736 /**
737 * @return the invokes
738 */
739 public static long getInvokes() {
740 return invokes.longValue();
741 }
743 /**
744 * @return the allocations
745 */
746 public static long getAllocations() {
747 return allocations.longValue();
748 }
750 @Override
751 protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
752 final MethodType type = desc.getMethodType();
753 assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
754 final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
755 final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
756 //TODO - ClassCastException
757 return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
758 }
760 private static Object wrapFilter(final Object obj) {
761 if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
762 return obj;
763 }
764 return Context.getGlobal().wrapAsObject(obj);
765 }
767 @SuppressWarnings("unused")
768 private static Object globalFilter(final Object object) {
769 // replace whatever we get with the current global object
770 return Context.getGlobal();
771 }
773 /**
774 * Some receivers are primitive, in that case, according to the Spec we
775 * create a new native object per callsite with the wrap filter. We can only
776 * apply optimistic builtins if there is no per instance state saved for
777 * these wrapped objects (e.g. currently NativeStrings), otherwise we can't
778 * create optimistic versions
779 *
780 * @param self receiver
781 * @param linkLogicClass linkLogicClass, or null if no link logic exists
782 * @return link logic instance, or null if one could not be constructed for
783 * this receiver
784 */
785 private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
786 if (linkLogicClass == null) {
787 return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
788 }
790 if (!Context.getContextTrusted().getEnv()._optimistic_types) {
791 return null; //if optimistic types are off, optimistic builtins are too
792 }
794 final Object wrappedSelf = wrapFilter(self);
795 if (wrappedSelf instanceof OptimisticBuiltins) {
796 if (wrappedSelf != self && ((OptimisticBuiltins) wrappedSelf).hasPerInstanceAssumptions()) {
797 return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
798 }
799 return ((OptimisticBuiltins) wrappedSelf).getLinkLogic(linkLogicClass);
800 }
801 return null;
802 }
804 /**
805 * dyn:call call site signature: (callee, thiz, [args...]) generated method
806 * signature: (callee, thiz, [args...])
807 *
808 * cases:
809 * (a) method has callee parameter
810 * (1) for local/scope calls, we just bind thiz and drop the second argument.
811 * (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
812 * (b) method doesn't have callee parameter (builtin functions)
813 * (3) for local/scope calls, bind thiz and drop both callee and thiz.
814 * (4) for normal this-calls, drop callee.
815 *
816 * @return guarded invocation for call
817 */
818 @Override
819 protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
820 final MethodType type = desc.getMethodType();
822 final String name = getName();
823 final boolean isUnstable = request.isCallSiteUnstable();
824 final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
825 final boolean isCall = !scopeCall && data.isBuiltin() && "call".equals(name);
826 final boolean isApply = !scopeCall && data.isBuiltin() && "apply".equals(name);
828 final boolean isApplyOrCall = isCall | isApply;
830 if (isUnstable && !isApplyOrCall) {
831 //megamorphic - replace call with apply
832 final MethodHandle handle;
833 //ensure that the callsite is vararg so apply can consume it
834 if (type.parameterCount() == 3 && type.parameterType(2) == Object[].class) {
835 // Vararg call site
836 handle = ScriptRuntime.APPLY.methodHandle();
837 } else {
838 // (callee, this, args...) => (callee, this, args[])
839 handle = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
840 }
842 // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
843 // generic "is this a ScriptFunction?" guard.
844 return new GuardedInvocation(
845 handle,
846 null,
847 (SwitchPoint) null,
848 ClassCastException.class);
849 }
851 MethodHandle boundHandle;
852 MethodHandle guard = null;
854 // Special handling of Function.apply and Function.call. Note we must be invoking
855 if (isApplyOrCall && !isUnstable) {
856 final Object[] args = request.getArguments();
857 if (Bootstrap.isCallable(args[1])) {
858 return createApplyOrCallCall(isApply, desc, request, args);
859 }
860 } //else just fall through and link as ordinary function or unstable apply
862 int programPoint = INVALID_PROGRAM_POINT;
863 if (NashornCallSiteDescriptor.isOptimistic(desc)) {
864 programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
865 }
867 CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
868 final Object self = request.getArguments()[1];
869 final Collection<CompiledFunction> forbidden = new HashSet<>();
871 //check for special fast versions of the compiled function
872 final List<SwitchPoint> sps = new ArrayList<>();
873 Class<? extends Throwable> exceptionGuard = null;
875 while (cf.isSpecialization()) {
876 final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
877 //if linklogic is null, we can always link with the standard mechanism, it's still a specialization
878 final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
880 if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
881 final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
883 if (log.isEnabled()) {
884 log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
885 }
887 exceptionGuard = linkLogic.getRelinkException();
889 break;
890 }
892 //could not link this specialization because link check failed
893 forbidden.add(cf);
894 final CompiledFunction oldCf = cf;
895 cf = data.getBestInvoker(type, scope, forbidden);
896 assert oldCf != cf;
897 }
899 final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
900 final MethodHandle callHandle = bestInvoker.getInvocation();
902 if (data.needsCallee()) {
903 if (scopeCall && needsWrappedThis()) {
904 // (callee, this, args...) => (callee, [this], args...)
905 boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER);
906 } else {
907 // It's already (callee, this, args...), just what we need
908 boundHandle = callHandle;
909 }
910 } else if (data.isBuiltin() && "extend".equals(data.getName())) {
911 // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
912 // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
913 boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, type.parameterType(0), type.parameterType(1));
914 } else if (scopeCall && needsWrappedThis()) {
915 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
916 // (this, args...) => ([this], args...)
917 boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER);
918 // ([this], args...) => ([callee], [this], args...)
919 boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0));
920 } else {
921 // (this, args...) => ([callee], this, args...)
922 boundHandle = MH.dropArguments(callHandle, 0, type.parameterType(0));
923 }
925 // For non-strict functions, check whether this-object is primitive type.
926 // If so add a to-object-wrapper argument filter.
927 // Else install a guard that will trigger a relink when the argument becomes primitive.
928 if (!scopeCall && needsWrappedThis()) {
929 if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
930 boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
931 } else {
932 guard = getNonStrictFunctionGuard(this);
933 }
934 }
936 boundHandle = pairArguments(boundHandle, type);
938 if (bestInvoker.getSwitchPoints() != null) {
939 sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
940 }
941 final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
943 return new GuardedInvocation(
944 boundHandle,
945 guard == null ?
946 getFunctionGuard(
947 this,
948 cf.getFlags()) :
949 guard,
950 spsArray,
951 exceptionGuard);
952 }
954 private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
955 final MethodType descType = desc.getMethodType();
956 final int paramCount = descType.parameterCount();
957 if (descType.parameterType(paramCount - 1).isArray()) {
958 // This is vararg invocation of apply or call. This can normally only happen when we do a recursive
959 // invocation of createApplyOrCallCall (because we're doing apply-of-apply). In this case, create delegate
960 // linkage by unpacking the vararg invocation and use pairArguments to introduce the necessary spreader.
961 return createVarArgApplyOrCallCall(isApply, desc, request, args);
962 }
964 final boolean passesThis = paramCount > 2;
965 final boolean passesArgs = paramCount > 3;
966 final int realArgCount = passesArgs ? paramCount - 3 : 0;
968 final Object appliedFn = args[1];
969 final boolean appliedFnNeedsWrappedThis = needsWrappedThis(appliedFn);
971 //box call back to apply
972 CallSiteDescriptor appliedDesc = desc;
973 final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
974 //enough to change the proto switchPoint here
976 final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
977 final boolean isFailedApplyToCall = isApplyToCall && applyToCallSwitchPoint.hasBeenInvalidated();
979 // R(apply|call, ...) => R(...)
980 MethodType appliedType = descType.dropParameterTypes(0, 1);
981 if (!passesThis) {
982 // R() => R(this)
983 appliedType = appliedType.insertParameterTypes(1, Object.class);
984 } else if (appliedFnNeedsWrappedThis) {
985 appliedType = appliedType.changeParameterType(1, Object.class);
986 }
988 /*
989 * dropArgs is a synthetic method handle that contains any args that we need to
990 * get rid of that come after the arguments array in the apply case. We adapt
991 * the callsite to ask for 3 args only and then dropArguments on the method handle
992 * to make it fit the extraneous args.
993 */
994 MethodType dropArgs = MH.type(void.class);
995 if (isApply && !isFailedApplyToCall) {
996 final int pc = appliedType.parameterCount();
997 for (int i = 3; i < pc; i++) {
998 dropArgs = dropArgs.appendParameterTypes(appliedType.parameterType(i));
999 }
1000 if (pc > 3) {
1001 appliedType = appliedType.dropParameterTypes(3, pc);
1002 }
1003 }
1005 if (isApply || isFailedApplyToCall) {
1006 if (passesArgs) {
1007 // R(this, args) => R(this, Object[])
1008 appliedType = appliedType.changeParameterType(2, Object[].class);
1009 // drop any extraneous arguments for the apply fail case
1010 if (isFailedApplyToCall) {
1011 appliedType = appliedType.dropParameterTypes(3, paramCount - 1);
1012 }
1013 } else {
1014 // R(this) => R(this, Object[])
1015 appliedType = appliedType.insertParameterTypes(2, Object[].class);
1016 }
1017 }
1019 appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
1021 // Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
1022 final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
1023 appliedArgs[0] = appliedFn;
1024 appliedArgs[1] = passesThis ? appliedFnNeedsWrappedThis ? ScriptFunctionData.wrapThis(args[2]) : args[2] : ScriptRuntime.UNDEFINED;
1025 if (isApply && !isFailedApplyToCall) {
1026 appliedArgs[2] = passesArgs ? NativeFunction.toApplyArgs(args[3]) : ScriptRuntime.EMPTY_ARRAY;
1027 } else {
1028 if (passesArgs) {
1029 if (isFailedApplyToCall) {
1030 final Object[] tmp = new Object[args.length - 3];
1031 System.arraycopy(args, 3, tmp, 0, tmp.length);
1032 appliedArgs[2] = NativeFunction.toApplyArgs(tmp);
1033 } else {
1034 assert !isApply;
1035 System.arraycopy(args, 3, appliedArgs, 2, args.length - 3);
1036 }
1037 } else if (isFailedApplyToCall) {
1038 appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
1039 }
1040 }
1042 // Ask the linker machinery for an invocation of the target function
1043 final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
1045 GuardedInvocation appliedInvocation;
1046 try {
1047 appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
1048 } catch (final RuntimeException | Error e) {
1049 throw e;
1050 } catch (final Exception e) {
1051 throw new RuntimeException(e);
1052 }
1053 assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
1055 final Class<?> applyFnType = descType.parameterType(0);
1056 MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation
1058 if (isApply && !isFailedApplyToCall) {
1059 if (passesArgs) {
1060 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
1061 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
1062 } else {
1063 // If the original call site doesn't pass argArray, pass in an empty array
1064 inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY);
1065 }
1066 }
1068 if (isApplyToCall) {
1069 if (isFailedApplyToCall) {
1070 //take the real arguments that were passed to a call and force them into the apply instead
1071 Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
1072 inv = MH.asCollector(inv, Object[].class, realArgCount);
1073 } else {
1074 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
1075 }
1076 }
1078 if (!passesThis) {
1079 // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
1080 inv = bindImplicitThis(appliedFn, inv);
1081 } else if (appliedFnNeedsWrappedThis) {
1082 // target function needs a wrapped this, so make sure we filter for that
1083 inv = MH.filterArguments(inv, 1, WRAP_THIS);
1084 }
1085 inv = MH.dropArguments(inv, 0, applyFnType);
1087 /*
1088 * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
1089 * is when we need to add arguments to the callsite to catch and ignore the synthetic
1090 * extra args that someone has added to the command line.
1091 */
1092 for (int i = 0; i < dropArgs.parameterCount(); i++) {
1093 inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
1094 }
1096 MethodHandle guard = appliedInvocation.getGuard();
1097 // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one
1098 if (!passesThis && guard.type().parameterCount() > 1) {
1099 guard = bindImplicitThis(appliedFn, guard);
1100 }
1101 final MethodType guardType = guard.type();
1103 // We need to account for the dropped (apply|call) function argument.
1104 guard = MH.dropArguments(guard, 0, descType.parameterType(0));
1105 // Take the "isApplyFunction" guard, and bind it to this function.
1106 MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
1107 // Adapt the guard to receive all the arguments that the original guard does.
1108 applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
1109 // Fold the original function guard into our apply guard.
1110 guard = MH.foldArguments(applyFnGuard, guard);
1112 return appliedInvocation.replaceMethods(inv, guard);
1113 }
1115 /*
1116 * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity
1117 * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with
1118 * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method.
1119 * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back
1120 * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to
1121 * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity
1122 * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already
1123 * solved by createApplyOrCallCall) non-vararg call site linking.
1124 */
1125 private GuardedInvocation createVarArgApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc,
1126 final LinkRequest request, final Object[] args) {
1127 final MethodType descType = desc.getMethodType();
1128 final int paramCount = descType.parameterCount();
1129 final Object[] varArgs = (Object[]) args[paramCount - 1];
1130 // -1 'cause we're not passing the vararg array itself
1131 final int copiedArgCount = args.length - 1;
1132 final int varArgCount = varArgs.length;
1134 // Spread arguments for the delegate createApplyOrCallCall invocation.
1135 final Object[] spreadArgs = new Object[copiedArgCount + varArgCount];
1136 System.arraycopy(args, 0, spreadArgs, 0, copiedArgCount);
1137 System.arraycopy(varArgs, 0, spreadArgs, copiedArgCount, varArgCount);
1139 // Spread call site descriptor for the delegate createApplyOrCallCall invocation. We drop vararg array and
1140 // replace it with a list of Object.class.
1141 final MethodType spreadType = descType.dropParameterTypes(paramCount - 1, paramCount).appendParameterTypes(
1142 Collections.<Class<?>>nCopies(varArgCount, Object.class));
1143 final CallSiteDescriptor spreadDesc = desc.changeMethodType(spreadType);
1145 // Delegate back to createApplyOrCallCall with the spread (that is, reverted to non-vararg) request/
1146 final LinkRequest spreadRequest = request.replaceArguments(spreadDesc, spreadArgs);
1147 final GuardedInvocation spreadInvocation = createApplyOrCallCall(isApply, spreadDesc, spreadRequest, spreadArgs);
1149 // Add spreader combinators to returned invocation and guard.
1150 return spreadInvocation.replaceMethods(
1151 // Use standard ScriptObject.pairArguments on the invocation
1152 pairArguments(spreadInvocation.getInvocation(), descType),
1153 // Use our specialized spreadGuardArguments on the guard (see below).
1154 spreadGuardArguments(spreadInvocation.getGuard(), descType));
1155 }
1157 private static MethodHandle spreadGuardArguments(final MethodHandle guard, final MethodType descType) {
1158 final MethodType guardType = guard.type();
1159 final int guardParamCount = guardType.parameterCount();
1160 final int descParamCount = descType.parameterCount();
1161 final int spreadCount = guardParamCount - descParamCount + 1;
1162 if (spreadCount <= 0) {
1163 // Guard doesn't dip into the varargs
1164 return guard;
1165 }
1167 final MethodHandle arrayConvertingGuard;
1168 // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
1169 // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
1170 // with ClassCastException of NativeArray to Object[].
1171 if (guardType.parameterType(guardParamCount - 1).isArray()) {
1172 arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
1173 } else {
1174 arrayConvertingGuard = guard;
1175 }
1177 return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount);
1178 }
1180 private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) {
1181 final MethodHandle bound;
1182 if (fn instanceof ScriptFunction && ((ScriptFunction) fn).needsWrappedThis()) {
1183 bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
1184 } else {
1185 bound = mh;
1186 }
1187 return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
1188 }
1190 /**
1191 * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
1192 *
1193 * These don't want a callee parameter, so bind that. Name binding is
1194 * optional.
1195 */
1196 MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
1197 return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
1198 }
1200 private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
1201 if (bindName == null) {
1202 return methodHandle;
1203 }
1205 // if it is vararg method, we need to extend argument array with
1206 // a new zeroth element that is set to bindName value.
1207 final MethodType methodType = methodHandle.type();
1208 final int parameterCount = methodType.parameterCount();
1209 final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
1211 if (isVarArg) {
1212 return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
1213 }
1214 return MH.insertArguments(methodHandle, 1, bindName);
1215 }
1217 /**
1218 * Get the guard that checks if a {@link ScriptFunction} is equal to a known
1219 * ScriptFunction, using reference comparison
1220 *
1221 * @param function The ScriptFunction to check against. This will be bound
1222 * to the guard method handle
1223 *
1224 * @return method handle for guard
1225 */
1226 private static MethodHandle getFunctionGuard(final ScriptFunction function, final int flags) {
1227 assert function.data != null;
1228 // Built-in functions have a 1-1 correspondence to their ScriptFunctionData, so we can use a cheaper identity
1229 // comparison for them.
1230 if (function.data.isBuiltin()) {
1231 return Guards.getIdentityGuard(function);
1232 }
1233 return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
1234 }
1236 /**
1237 * Get a guard that checks if a {@link ScriptFunction} is equal to a known
1238 * ScriptFunction using reference comparison, and whether the type of the
1239 * second argument (this-object) is not a JavaScript primitive type.
1240 *
1241 * @param function The ScriptFunction to check against. This will be bound
1242 * to the guard method handle
1243 *
1244 * @return method handle for guard
1245 */
1246 private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
1247 assert function.data != null;
1248 return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
1249 }
1251 @SuppressWarnings("unused")
1252 private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
1253 return self instanceof ScriptFunction && ((ScriptFunction) self).data == data;
1254 }
1256 @SuppressWarnings("unused")
1257 private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
1258 return self instanceof ScriptFunction && ((ScriptFunction) self).data == data && arg instanceof ScriptObject;
1259 }
1261 //TODO this can probably be removed given that we have builtin switchpoints in the context
1262 @SuppressWarnings("unused")
1263 private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
1264 // NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
1265 return appliedFnCondition && self == expectedSelf;
1266 }
1268 @SuppressWarnings("unused")
1269 private static Object[] addZerothElement(final Object[] args, final Object value) {
1270 // extends input array with by adding new zeroth element
1271 final Object[] src = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
1272 final Object[] result = new Object[src.length + 1];
1273 System.arraycopy(src, 0, result, 1, src.length);
1274 result[0] = value;
1275 return result;
1276 }
1278 @SuppressWarnings("unused")
1279 private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
1280 throws Throwable {
1281 final Object syncObj = sync == UNDEFINED ? self : sync;
1282 synchronized (syncObj) {
1283 return func.invoke(self, args);
1284 }
1285 }
1287 private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
1288 return MH.findStatic(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
1289 }
1291 private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
1292 return MH.findVirtual(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
1293 }
1294 }