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.codegen.CompilerConstants.virtualCallNoLookup;
  29 import static jdk.nashorn.internal.lookup.Lookup.MH;
  30 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  31 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  32 
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import jdk.internal.dynalink.CallSiteDescriptor;
  37 import jdk.internal.dynalink.linker.GuardedInvocation;
  38 import jdk.internal.dynalink.linker.LinkRequest;
  39 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
  40 import jdk.nashorn.internal.lookup.MethodHandleFactory;
  41 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  42 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  43 
  44 /**
  45  * Runtime representation of a JavaScript function.
  46  */
  47 public abstract class ScriptFunction extends ScriptObject {
  48 
  49     /** Method handle for prototype getter for this ScriptFunction */
  50     public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class);
  51 
  52     /** Method handle for prototype setter for this ScriptFunction */
  53     public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class);
  54 
  55     /** Method handle for length getter for this ScriptFunction */
  56     public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class);
  57 
  58     /** Method handle for name getter for this ScriptFunction */
  59     public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
  60 
  61     /** Method handle used for implementing sync() in mozilla_compat */
  62     public static final MethodHandle INVOKE_SYNC = findOwnMH("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
  63 
  64     /** Method handle for allocate function for this ScriptFunction */
  65     static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
  66 
  67     private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
  68 


  69     /** method handle to scope getter for this ScriptFunction */
  70     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
  71 
  72     private static final MethodHandle IS_FUNCTION_MH  = findOwnMH("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
  73 
  74     private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
  75 
  76     private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH("addZerothElement", Object[].class, Object[].class, Object.class);
  77 
  78     /** The parent scope. */
  79     private final ScriptObject scope;
  80 
  81     private final ScriptFunctionData data;
  82 
  83     /** The property map used for newly allocated object when function is used as constructor. */
  84     protected PropertyMap allocatorMap;
  85 
  86     /**
  87      * Constructor
  88      *
  89      * @param name          function name
  90      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
  91      * @param map           property map
  92      * @param scope         scope
  93      * @param specs         specialized version of this function - other method handles
  94      * @param strict        is this a strict mode function?
  95      * @param builtin       is this a built in function?
  96      * @param isConstructor is this a constructor?
  97      */
  98     protected ScriptFunction(
  99             final String name,
 100             final MethodHandle methodHandle,
 101             final PropertyMap map,
 102             final ScriptObject scope,
 103             final MethodHandle[] specs,
 104             final boolean strict,
 105             final boolean builtin,
 106             final boolean isConstructor) {
 107 
 108         this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
 109     }
 110 
 111     /**
 112      * Constructor
 113      *
 114      * @param data          static function data
 115      * @param map           property map
 116      * @param scope         scope
 117      */
 118     protected ScriptFunction(
 119             final ScriptFunctionData data,
 120             final PropertyMap map,
 121             final ScriptObject scope) {
 122 
 123         super(map);
 124 
 125         if (Context.DEBUG) {
 126             constructorCount++;
 127         }
 128 
 129         this.data  = data;
 130         this.scope = scope;
 131         this.allocatorMap = data.getAllocatorMap();
 132     }
 133 
 134     @Override
 135     public String getClassName() {
 136         return "Function";
 137     }
 138 
 139     /**
 140      * ECMA 15.3.5.3 [[HasInstance]] (V)
 141      * Step 3 if "prototype" value is not an Object, throw TypeError
 142      */
 143     @Override
 144     public boolean isInstance(final ScriptObject instance) {
 145         final Object basePrototype = getTargetFunction().getPrototype();
 146         if (!(basePrototype instanceof ScriptObject)) {
 147             throw typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype));
 148         }
 149 
 150         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
 151             if (proto == basePrototype) {
 152                 return true;
 153             }
 154         }
 155 
 156         return false;
 157     }
 158 
 159     /**
 160      * Returns the target function for this function. If the function was not created using
 161      * {@link #makeBoundFunction(Object, Object[])}, its target function is itself. If it is bound, its target function
 162      * is the target function of the function it was made from (therefore, the target function is always the final,
 163      * unbound recipient of the calls).
 164      * @return the target function for this function.
 165      */
 166     protected ScriptFunction getTargetFunction() {
 167         return this;
 168     }
 169 
 170     boolean isBoundFunction() {
 171         return getTargetFunction() != this;
 172     }
 173 
 174     /**
 175      * Set the arity of this ScriptFunction
 176      * @param arity arity
 177      */
 178     public final void setArity(final int arity) {
 179         data.setArity(arity);
 180     }
 181 
 182     /**
 183      * Is this a ECMAScript 'use strict' function?
 184      * @return true if function is in strict mode
 185      */
 186     public boolean isStrict() {
 187         return data.isStrict();
 188     }
 189 
 190     /**
 191      * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
 192      * according to ECMA 10.4.3.
 193      * @return true if this argument must be an object
 194      */
 195     public boolean needsWrappedThis() {
 196         return data.needsWrappedThis();
 197     }
 198 
 199     /**
 200      * Execute this script function.
 201      * @param self  Target object.
 202      * @param arguments  Call arguments.
 203      * @return ScriptFunction result.
 204      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 205      */
 206     Object invoke(final Object self, final Object... arguments) throws Throwable {
 207         if (Context.DEBUG) {
 208             invokes++;
 209         }
 210         return data.invoke(this, self, arguments);
 211     }
 212 
 213     /**
 214      * Execute this script function as a constructor.
 215      * @param arguments  Call arguments.
 216      * @return Newly constructed result.
 217      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 218      */
 219     Object construct(final Object... arguments) throws Throwable {
 220         return data.construct(this, arguments);
 221     }
 222 
 223     /**
 224      * Allocate function. Called from generated {@link ScriptObject} code
 225      * for allocation as a factory method
 226      *
 227      * @return a new instance of the {@link ScriptObject} whose allocator this is
 228      */
 229     @SuppressWarnings("unused")
 230     private Object allocate() {
 231         if (Context.DEBUG) {
 232             allocations++;
 233         }
 234         assert !isBoundFunction(); // allocate never invoked on bound functions
 235 
 236         final ScriptObject object = data.allocate(allocatorMap);
 237 
 238         if (object != null) {
 239             Object prototype = getPrototype();
 240             if (prototype instanceof ScriptObject) {
 241                 object.setInitialProto((ScriptObject)prototype);
 242             }
 243 
 244             if (object.getProto() == null) {
 245                 object.setInitialProto(getObjectPrototype());
 246             }
 247         }
 248 
 249         return object;
 250     }
 251 
 252     /**
 253      * Return Object.prototype - used by "allocate"
 254      * @return Object.prototype
 255      */
 256     protected abstract ScriptObject getObjectPrototype();
 257 
 258     /**
 259      * Creates a version of this function bound to a specific "self" and other arguments, as per
 260      * {@code Function.prototype.bind} functionality in ECMAScript 5.1 section 15.3.4.5.
 261      * @param self the self to bind to this function. Can be null (in which case, null is bound as this).
 262      * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
 263      * @return a function with the specified self and parameters bound.
 264      */
 265     protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
 266         return makeBoundFunction(data.makeBoundFunctionData(this, self, args));
 267     }
 268 
 269     /**
 270      * Create a version of this function as in {@link ScriptFunction#makeBoundFunction(Object, Object[])},
 271      * but using a {@link ScriptFunctionData} for the bound data.
 272      *
 273      * @param boundData ScriptFuntionData for the bound function
 274      * @return a function with the bindings performed according to the given data
 275      */
 276     protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData);
 277 
 278     @Override
 279     public final String safeToString() {
 280         return toSource();
 281     }
 282 
 283     @Override
 284     public String toString() {
 285         return data.toString();
 286     }
 287 
 288     /**
 289      * Get this function as a String containing its source code. If no source code
 290      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 291      * @return string representation of this function's source
 292      */
 293     public final String toSource() {
 294         return data.toSource();
 295     }
 296 
 297     /**
 298      * Get the prototype object for this function
 299      * @return prototype
 300      */
 301     public abstract Object getPrototype();
 302 
 303     /**
 304      * Set the prototype object for this function
 305      * @param prototype new prototype object
 306      */
 307     public abstract void setPrototype(Object prototype);
 308 
 309     /**
 310      * Create a function that invokes this function synchronized on {@code sync} or the self object
 311      * of the invocation.
 312      * @param sync the Object to synchronize on, or undefined
 313      * @return synchronized function
 314      */
 315     public abstract ScriptFunction makeSynchronizedFunction(Object sync);
 316 
 317     /**
 318      * Return the most appropriate invoke handle if there are specializations
 319      * @param type most specific method type to look for invocation with
 320      * @param args args for trampoline invocation
 321      * @return invoke method handle
 322      */
 323     private MethodHandle getBestInvoker(final MethodType type, final Object[] args) {
 324         return data.getBestInvoker(type, args);
 325     }
 326 
 327     /**
 328      * Return the most appropriate invoke handle if there are specializations
 329      * @param type most specific method type to look for invocation with
 330      * @return invoke method handle
 331      */
 332     public MethodHandle getBestInvoker(final MethodType type) {
 333         return getBestInvoker(type, null);
 334     }
 335 
 336     /**
 337      * Return the invoke handle bound to a given ScriptObject self reference.
 338      * If callee parameter is required result is rebound to this.
 339      *
 340      * @param self self reference
 341      * @return bound invoke handle
 342      */
 343     public final MethodHandle getBoundInvokeHandle(final Object self) {
 344         return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker()), self);
 345     }
 346 
 347     /**
 348      * Bind the method handle to this {@code ScriptFunction} instance if it needs a callee parameter. If this function's
 349      * method handles don't have a callee parameter, the handle is returned unchanged.
 350      * @param methodHandle the method handle to potentially bind to this function instance.
 351      * @return the potentially bound method handle
 352      */
 353     private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
 354         return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
 355 
 356     }
 357 
 358     /**
 359      * Get the name for this function
 360      * @return the name
 361      */
 362     public final String getName() {
 363         return data.getName();
 364     }
 365 
 366 
 367     /**
 368      * Get the scope for this function
 369      * @return the scope
 370      */
 371     public final ScriptObject getScope() {
 372         return scope;
 373     }
 374 
 375     /**
 376      * Prototype getter for this ScriptFunction - follows the naming convention
 377      * used by Nasgen and the code generator
 378      *
 379      * @param self  self reference
 380      * @return self's prototype
 381      */
 382     public static Object G$prototype(final Object self) {
 383         return (self instanceof ScriptFunction) ?
 384             ((ScriptFunction)self).getPrototype() :
 385             UNDEFINED;
 386     }
 387 
 388     /**
 389      * Prototype setter for this ScriptFunction - follows the naming convention
 390      * used by Nasgen and the code generator
 391      *
 392      * @param self  self reference
 393      * @param prototype prototype to set
 394      */
 395     public static void S$prototype(final Object self, final Object prototype) {
 396         if (self instanceof ScriptFunction) {
 397             ((ScriptFunction)self).setPrototype(prototype);
 398         }
 399     }
 400 
 401     /**
 402      * Length getter - ECMA 15.3.3.2: Function.length
 403      * @param self self reference
 404      * @return length
 405      */
 406     public static int G$length(final Object self) {
 407         if (self instanceof ScriptFunction) {
 408             return ((ScriptFunction)self).data.getArity();
 409         }
 410 
 411         return 0;
 412     }
 413 
 414     /**
 415      * Name getter - ECMA Function.name
 416      * @param self self refence
 417      * @return the name, or undefined if none
 418      */
 419     public static Object G$name(final Object self) {
 420         if (self instanceof ScriptFunction) {
 421             return ((ScriptFunction)self).getName();
 422         }
 423 
 424         return UNDEFINED;
 425     }
 426 
 427     /**
 428      * Get the prototype for this ScriptFunction
 429      * @param constructor constructor
 430      * @return prototype, or null if given constructor is not a ScriptFunction
 431      */
 432     public static ScriptObject getPrototype(final Object constructor) {
 433         if (constructor instanceof ScriptFunction) {
 434             final Object proto = ((ScriptFunction)constructor).getPrototype();
 435             if (proto instanceof ScriptObject) {
 436                 return (ScriptObject)proto;
 437             }
 438         }
 439 
 440         return null;
 441     }
 442 
 443     // These counters are updated only in debug mode.
 444     private static int constructorCount;
 445     private static int invokes;
 446     private static int allocations;
 447 
 448     /**
 449      * @return the constructorCount
 450      */
 451     public static int getConstructorCount() {
 452         return constructorCount;
 453     }
 454 
 455     /**
 456      * @return the invokes
 457      */
 458     public static int getInvokes() {
 459         return invokes;
 460     }
 461 
 462     /**
 463      * @return the allocations
 464      */
 465     public static int getAllocations() {
 466         return allocations;
 467     }
 468 
 469     @Override
 470     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
 471         final MethodType type = desc.getMethodType();
 472         return new GuardedInvocation(pairArguments(data.getBestConstructor(type.changeParameterType(0, ScriptFunction.class), null), type), null, getFunctionGuard(this));
 473     }
 474 
 475     @SuppressWarnings("unused")
 476     private static Object wrapFilter(final Object obj) {
 477         if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
 478             return obj;
 479         }
 480         return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
 481     }
 482 







 483     /**
 484      * dyn:call call site signature: (callee, thiz, [args...])
 485      * generated method signature:   (callee, thiz, [args...])
 486      *
 487      * cases:
 488      * (a) method has callee parameter
 489      *   (1) for local/scope calls, we just bind thiz and drop the second argument.
 490      *   (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
 491      * (b) method doesn't have callee parameter (builtin functions)
 492      *   (3) for local/scope calls, bind thiz and drop both callee and thiz.
 493      *   (4) for normal this-calls, drop callee.
 494      */
 495     @Override
 496     protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
 497         final MethodType type = desc.getMethodType();

 498 
 499         if (request.isCallSiteUnstable()) {
 500             // (this, callee, args...) => (this, callee, args[])
 501             final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
 502                     type.parameterCount() - 2);
 503 
 504             // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
 505             // generic "is this a ScriptFunction?" guard.
 506             return new GuardedInvocation(collector, ScriptFunction.class.isAssignableFrom(desc.getMethodType().parameterType(0))
 507                     ? null : NashornGuards.getScriptFunctionGuard());
 508         }
 509 
 510         MethodHandle boundHandle;
 511         MethodHandle guard = null;
 512 
 513         final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
 514 
 515         if (data.needsCallee()) {
 516             final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
 517             if (scopeCall) {
 518                 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
 519                 // (callee, this, args...) => (callee, args...)
 520                 boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
 521                 // (callee, args...) => (callee, [this], args...)
 522                 boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
 523 
 524             } else {
 525                 // It's already (callee, this, args...), just what we need
 526                 boundHandle = callHandle;
 527             }
 528         } else {
 529             final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments());
 530             if (data.isBuiltin() && "extend".equals(data.getName())) {
 531                 // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
 532                 // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
 533                 boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, Object.class, Object.class);
 534             } else if (scopeCall) {
 535                 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
 536                 // (this, args...) => (args...)
 537                 boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
 538                 // (args...) => ([callee], [this], args...)
 539                 boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
 540             } else {
 541                 // (this, args...) => ([callee], this, args...)
 542                 boundHandle = MH.dropArguments(callHandle, 0, Object.class);
 543             }
 544         }
 545 
 546         // For non-strict functions, check whether this-object is primitive type.
 547         // If so add a to-object-wrapper argument filter.
 548         // Else install a guard that will trigger a relink when the argument becomes primitive.
 549         if (!scopeCall && needsWrappedThis()) {
 550             if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
 551                 boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
 552             } else {
 553                 guard = getNonStrictFunctionGuard(this);
 554             }
 555         }
 556 
 557         boundHandle = pairArguments(boundHandle, type);
 558 
 559         return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard);
 560    }
 561 
 562     /**
 563      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
 564      *
 565      * These don't want a callee parameter, so bind that. Name binding is optional.
 566      */
 567     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
 568         return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type, null)), bindName), type);
 569     }
 570 
 571     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
 572         if (bindName == null) {
 573             return methodHandle;
 574         }
 575 
 576         // if it is vararg method, we need to extend argument array with
 577         // a new zeroth element that is set to bindName value.
 578         final MethodType methodType = methodHandle.type();
 579         final int parameterCount = methodType.parameterCount();
 580         final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
 581 
 582         if (isVarArg) {
 583             return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
 584         }
 585         return MH.insertArguments(methodHandle, 1, bindName);
 586     }
 587 
 588     /**
 589      * Get the guard that checks if a {@link ScriptFunction} is equal to
 590      * a known ScriptFunction, using reference comparison
 591      *
 592      * @param function The ScriptFunction to check against. This will be bound to the guard method handle
 593      *
 594      * @return method handle for guard
 595      */
 596     private static MethodHandle getFunctionGuard(final ScriptFunction function) {
 597         assert function.data != null;
 598         return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
 599     }
 600 
 601     /**
 602      * Get a guard that checks if a {@link ScriptFunction} is equal to
 603      * a known ScriptFunction using reference comparison, and whether the type of
 604      * the second argument (this-object) is not a JavaScript primitive type.
 605      *
 606      * @param function The ScriptFunction to check against. This will be bound to the guard method handle
 607      *
 608      * @return method handle for guard
 609      */
 610     private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
 611         assert function.data != null;
 612         return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
 613     }
 614 
 615     @SuppressWarnings("unused")
 616     private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
 617         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data;
 618     }
 619 
 620     @SuppressWarnings("unused")
 621     private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
 622         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
 623     }
 624 
 625     @SuppressWarnings("unused")
 626     private static Object[] addZerothElement(final Object[] args, final Object value) {
 627         // extends input array with by adding new zeroth element
 628         final Object[] src = (args == null)? ScriptRuntime.EMPTY_ARRAY : args;
 629         final Object[] result = new Object[src.length + 1];
 630         System.arraycopy(src, 0, result, 1, src.length);
 631         result[0] = value;
 632         return result;
 633     }
 634 
 635     @SuppressWarnings("unused")
 636     private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
 637             throws Throwable {
 638         final Object syncObj = sync == UNDEFINED ? self : sync;
 639         synchronized (syncObj) {
 640             return func.invoke(self, args);
 641         }
 642     }
 643 
 644     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
 645         final Class<?>   own = ScriptFunction.class;
 646         final MethodType mt  = MH.type(rtype, types);
 647         try {
 648             return MH.findStatic(MethodHandles.lookup(), own, name, mt);
 649         } catch (final MethodHandleFactory.LookupException e) {
 650             return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
 651         }
 652     }
 653 }
 654 
--- EOF ---