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