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