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