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