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