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.objects.Global;
  42 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  43 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  44 
  45 /**
  46  * Runtime representation of a JavaScript function.
  47  */
  48 public abstract class ScriptFunction extends ScriptObject {
  49 
  50     /** Method handle for prototype getter for this ScriptFunction */
  51     public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class);
  52 
  53     /** Method handle for prototype setter for this ScriptFunction */
  54     public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class);
  55 
  56     /** Method handle for length getter for this ScriptFunction */
  57     public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class);
  58 
  59     /** Method handle for name getter for this ScriptFunction */
  60     public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
  61 
  62     /** Method handle used for implementing sync() in mozilla_compat */
  63     public static final MethodHandle INVOKE_SYNC = findOwnMH("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
  64 
  65     /** Method handle for allocate function for this ScriptFunction */
  66     static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
  67 
  68     private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
  69 
  70     private static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class);
  71 
  72     /** method handle to scope getter for this ScriptFunction */
  73     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
  74 
  75     private static final MethodHandle IS_FUNCTION_MH  = findOwnMH("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
  76 
  77     private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
  78 
  79     private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH("addZerothElement", Object[].class, Object[].class, Object.class);
  80 
  81     /** The parent scope. */
  82     private final ScriptObject scope;
  83 
  84     private final ScriptFunctionData data;
  85 
  86     /** The property map used for newly allocated object when function is used as constructor. */
  87     protected PropertyMap allocatorMap;
  88 
  89     /**
  90      * Constructor
  91      *
  92      * @param name          function name
  93      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
  94      * @param map           property map
  95      * @param scope         scope
  96      * @param specs         specialized version of this function - other method handles
  97      * @param flags         {@link ScriptFunctionData} flags
  98      */
  99     protected ScriptFunction(
 100             final String name,
 101             final MethodHandle methodHandle,
 102             final PropertyMap map,
 103             final ScriptObject scope,
 104             final MethodHandle[] specs,
 105             final int flags) {
 106 
 107         this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
 108     }
 109 
 110     /**
 111      * Constructor
 112      *
 113      * @param data          static function data
 114      * @param map           property map
 115      * @param scope         scope
 116      */
 117     protected ScriptFunction(
 118             final ScriptFunctionData data,
 119             final PropertyMap map,
 120             final ScriptObject scope) {
 121 
 122         super(map);
 123 
 124         if (Context.DEBUG) {
 125             constructorCount++;
 126         }
 127 
 128         this.data  = data;
 129         this.scope = scope;
 130         this.allocatorMap = data.getAllocatorMap();
 131     }
 132 
 133     @Override
 134     public String getClassName() {
 135         return "Function";
 136     }
 137 
 138     /**
 139      * ECMA 15.3.5.3 [[HasInstance]] (V)
 140      * Step 3 if "prototype" value is not an Object, throw TypeError
 141      */
 142     @Override
 143     public boolean isInstance(final ScriptObject instance) {
 144         final Object basePrototype = getTargetFunction().getPrototype();
 145         if (!(basePrototype instanceof ScriptObject)) {
 146             throw typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype));
 147         }
 148 
 149         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
 150             if (proto == basePrototype) {
 151                 return true;
 152             }
 153         }
 154 
 155         return false;
 156     }
 157 
 158     /**
 159      * Returns the target function for this function. If the function was not created using
 160      * {@link #makeBoundFunction(Object, Object[])}, its target function is itself. If it is bound, its target function
 161      * is the target function of the function it was made from (therefore, the target function is always the final,
 162      * unbound recipient of the calls).
 163      * @return the target function for this function.
 164      */
 165     protected ScriptFunction getTargetFunction() {
 166         return this;
 167     }
 168 
 169     boolean isBoundFunction() {
 170         return getTargetFunction() != this;
 171     }
 172 
 173     /**
 174      * Set the arity of this ScriptFunction
 175      * @param arity arity
 176      */
 177     public final void setArity(final int arity) {
 178         data.setArity(arity);
 179     }
 180 
 181     /**
 182      * Is this a ECMAScript 'use strict' function?
 183      * @return true if function is in strict mode
 184      */
 185     public boolean isStrict() {
 186         return data.isStrict();
 187     }
 188 
 189     /**
 190      * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
 191      * according to ECMA 10.4.3.
 192      * @return true if this argument must be an object
 193      */
 194     public boolean needsWrappedThis() {
 195         return data.needsWrappedThis();
 196     }
 197 
 198     /**
 199      * Execute this script function.
 200      * @param self  Target object.
 201      * @param arguments  Call arguments.
 202      * @return ScriptFunction result.
 203      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 204      */
 205     Object invoke(final Object self, final Object... arguments) throws Throwable {
 206         if (Context.DEBUG) {
 207             invokes++;
 208         }
 209         return data.invoke(this, self, arguments);
 210     }
 211 
 212     /**
 213      * Execute this script function as a constructor.
 214      * @param arguments  Call arguments.
 215      * @return Newly constructed result.
 216      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 217      */
 218     Object construct(final Object... arguments) throws Throwable {
 219         return data.construct(this, arguments);
 220     }
 221 
 222     /**
 223      * Allocate function. Called from generated {@link ScriptObject} code
 224      * for allocation as a factory method
 225      *
 226      * @return a new instance of the {@link ScriptObject} whose allocator this is
 227      */
 228     @SuppressWarnings("unused")
 229     private Object allocate() {
 230         if (Context.DEBUG) {
 231             allocations++;
 232         }
 233         assert !isBoundFunction(); // allocate never invoked on bound functions
 234 
 235         final ScriptObject object = data.allocate(allocatorMap);
 236 
 237         if (object != null) {
 238             Object prototype = getPrototype();
 239             if (prototype instanceof ScriptObject) {
 240                 object.setInitialProto((ScriptObject)prototype);
 241             }
 242 
 243             if (object.getProto() == null) {
 244                 object.setInitialProto(getObjectPrototype());
 245             }
 246         }
 247 
 248         return object;
 249     }
 250 
 251     /**
 252      * Return Object.prototype - used by "allocate"
 253      * @return Object.prototype
 254      */
 255     protected abstract ScriptObject getObjectPrototype();
 256 
 257     /**
 258      * Creates a version of this function bound to a specific "self" and other arguments, as per
 259      * {@code Function.prototype.bind} functionality in ECMAScript 5.1 section 15.3.4.5.
 260      * @param self the self to bind to this function. Can be null (in which case, null is bound as this).
 261      * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
 262      * @return a function with the specified self and parameters bound.
 263      */
 264     protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
 265         return makeBoundFunction(data.makeBoundFunctionData(this, self, args));
 266     }
 267 
 268     /**
 269      * Create a version of this function as in {@link ScriptFunction#makeBoundFunction(Object, Object[])},
 270      * but using a {@link ScriptFunctionData} for the bound data.
 271      *
 272      * @param boundData ScriptFuntionData for the bound function
 273      * @return a function with the bindings performed according to the given data
 274      */
 275     protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData);
 276 
 277     @Override
 278     public final String safeToString() {
 279         return toSource();
 280     }
 281 
 282     @Override
 283     public String toString() {
 284         return data.toString();
 285     }
 286 
 287     /**
 288      * Get this function as a String containing its source code. If no source code
 289      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 290      * @return string representation of this function's source
 291      */
 292     public final String toSource() {
 293         return data.toSource();
 294     }
 295 
 296     /**
 297      * Get the prototype object for this function
 298      * @return prototype
 299      */
 300     public abstract Object getPrototype();
 301 
 302     /**
 303      * Set the prototype object for this function
 304      * @param prototype new prototype object
 305      */
 306     public abstract void setPrototype(Object prototype);
 307 
 308     /**
 309      * Create a function that invokes this function synchronized on {@code sync} or the self object
 310      * of the invocation.
 311      * @param sync the Object to synchronize on, or undefined
 312      * @return synchronized function
 313      */
 314     public abstract ScriptFunction makeSynchronizedFunction(Object sync);
 315 
 316     /**
 317      * Return the most appropriate invoke handle if there are specializations
 318      * @param type most specific method type to look for invocation with
 319      * @param args args for trampoline invocation
 320      * @return invoke method handle
 321      */
 322     private MethodHandle getBestInvoker(final MethodType type, final Object[] args) {
 323         return data.getBestInvoker(type, args);
 324     }
 325 
 326     /**
 327      * Return the most appropriate invoke handle if there are specializations
 328      * @param type most specific method type to look for invocation with
 329      * @return invoke method handle
 330      */
 331     public MethodHandle getBestInvoker(final MethodType type) {
 332         return getBestInvoker(type, null);
 333     }
 334 
 335     /**
 336      * Return the invoke handle bound to a given ScriptObject self reference.
 337      * If callee parameter is required result is rebound to this.
 338      *
 339      * @param self self reference
 340      * @return bound invoke handle
 341      */
 342     public final MethodHandle getBoundInvokeHandle(final Object self) {
 343         return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker()), self);
 344     }
 345 
 346     /**
 347      * Bind the method handle to this {@code ScriptFunction} instance if it needs a callee parameter. If this function's
 348      * method handles don't have a callee parameter, the handle is returned unchanged.
 349      * @param methodHandle the method handle to potentially bind to this function instance.
 350      * @return the potentially bound method handle
 351      */
 352     private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
 353         return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
 354 
 355     }
 356 
 357     /**
 358      * Get the name for this function
 359      * @return the name
 360      */
 361     public final String getName() {
 362         return data.getName();
 363     }
 364 
 365 
 366     /**
 367      * Get the scope for this function
 368      * @return the scope
 369      */
 370     public final ScriptObject getScope() {
 371         return scope;
 372     }
 373 
 374     /**
 375      * Prototype getter for this ScriptFunction - follows the naming convention
 376      * used by Nasgen and the code generator
 377      *
 378      * @param self  self reference
 379      * @return self's prototype
 380      */
 381     public static Object G$prototype(final Object self) {
 382         return (self instanceof ScriptFunction) ?
 383             ((ScriptFunction)self).getPrototype() :
 384             UNDEFINED;
 385     }
 386 
 387     /**
 388      * Prototype setter for this ScriptFunction - follows the naming convention
 389      * used by Nasgen and the code generator
 390      *
 391      * @param self  self reference
 392      * @param prototype prototype to set
 393      */
 394     public static void S$prototype(final Object self, final Object prototype) {
 395         if (self instanceof ScriptFunction) {
 396             ((ScriptFunction)self).setPrototype(prototype);
 397         }
 398     }
 399 
 400     /**
 401      * Length getter - ECMA 15.3.3.2: Function.length
 402      * @param self self reference
 403      * @return length
 404      */
 405     public static int G$length(final Object self) {
 406         if (self instanceof ScriptFunction) {
 407             return ((ScriptFunction)self).data.getArity();
 408         }
 409 
 410         return 0;
 411     }
 412 
 413     /**
 414      * Name getter - ECMA Function.name
 415      * @param self self refence
 416      * @return the name, or undefined if none
 417      */
 418     public static Object G$name(final Object self) {
 419         if (self instanceof ScriptFunction) {
 420             return ((ScriptFunction)self).getName();
 421         }
 422 
 423         return UNDEFINED;
 424     }
 425 
 426     /**
 427      * Get the prototype for this ScriptFunction
 428      * @param constructor constructor
 429      * @return prototype, or null if given constructor is not a ScriptFunction
 430      */
 431     public static ScriptObject getPrototype(final Object constructor) {
 432         if (constructor instanceof ScriptFunction) {
 433             final Object proto = ((ScriptFunction)constructor).getPrototype();
 434             if (proto instanceof ScriptObject) {
 435                 return (ScriptObject)proto;
 436             }
 437         }
 438 
 439         return null;
 440     }
 441 
 442     // These counters are updated only in debug mode.
 443     private static int constructorCount;
 444     private static int invokes;
 445     private static int allocations;
 446 
 447     /**
 448      * @return the constructorCount
 449      */
 450     public static int getConstructorCount() {
 451         return constructorCount;
 452     }
 453 
 454     /**
 455      * @return the invokes
 456      */
 457     public static int getInvokes() {
 458         return invokes;
 459     }
 460 
 461     /**
 462      * @return the allocations
 463      */
 464     public static int getAllocations() {
 465         return allocations;
 466     }
 467 
 468     @Override
 469     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
 470         final MethodType type = desc.getMethodType();
 471         return new GuardedInvocation(pairArguments(data.getBestConstructor(type.changeParameterType(0, ScriptFunction.class), null), type), null, getFunctionGuard(this));
 472     }
 473 
 474     @SuppressWarnings("unused")
 475     private static Object wrapFilter(final Object obj) {
 476         if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
 477             return obj;
 478         }
 479         return Context.getGlobal().wrapAsObject(obj);
 480     }
 481 
 482 
 483     @SuppressWarnings("unused")
 484     private static Object globalFilter(final Object object) {
 485         // replace whatever we get with the current global object
 486         return Context.getGlobal();
 487     }
 488 
 489     /**
 490      * dyn:call call site signature: (callee, thiz, [args...])
 491      * generated method signature:   (callee, thiz, [args...])
 492      *
 493      * cases:
 494      * (a) method has callee parameter
 495      *   (1) for local/scope calls, we just bind thiz and drop the second argument.
 496      *   (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
 497      * (b) method doesn't have callee parameter (builtin functions)
 498      *   (3) for local/scope calls, bind thiz and drop both callee and thiz.
 499      *   (4) for normal this-calls, drop callee.
 500      */
 501     @Override
 502     protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
 503         final MethodType type = desc.getMethodType();
 504         final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
 505 
 506         if (request.isCallSiteUnstable()) {
 507             // (callee, this, args...) => (callee, this, args[])
 508             final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
 509 
 510             // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
 511             // generic "is this a ScriptFunction?" guard.
 512             return new GuardedInvocation(collector, ScriptFunction.class.isAssignableFrom(desc.getMethodType().parameterType(0))
 513                     ? null : NashornGuards.getScriptFunctionGuard());
 514         }
 515 
 516         MethodHandle boundHandle;
 517         MethodHandle guard = null;
 518 
 519         if (data.needsCallee()) {
 520             final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
 521             if (scopeCall && needsWrappedThis()) {
 522                 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
 523                 // (callee, this, args...) => (callee, [this], args...)
 524                 boundHandle = MH.filterArguments(callHandle, 1, GLOBALFILTER);
 525             } else {
 526                 // It's already (callee, this, args...), just what we need
 527                 boundHandle = callHandle;
 528             }
 529         } else {
 530             final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments());
 531             if (data.isBuiltin() && "extend".equals(data.getName())) {
 532                 // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
 533                 // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
 534                 boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, Object.class, Object.class);
 535             } else if (scopeCall && needsWrappedThis()) {
 536                 // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
 537                 // (this, args...) => ([this], args...)
 538                 boundHandle = MH.filterArguments(callHandle, 0, GLOBALFILTER);
 539                 // ([this], args...) => ([callee], [this], args...)
 540                 boundHandle = MH.dropArguments(boundHandle, 0, Object.class);
 541             } else {
 542                 // (this, args...) => ([callee], this, args...)
 543                 boundHandle = MH.dropArguments(callHandle, 0, Object.class);
 544             }
 545         }
 546 
 547         // For non-strict functions, check whether this-object is primitive type.
 548         // If so add a to-object-wrapper argument filter.
 549         // Else install a guard that will trigger a relink when the argument becomes primitive.
 550         if (!scopeCall && needsWrappedThis()) {
 551             if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
 552                 boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
 553             } else {
 554                 guard = getNonStrictFunctionGuard(this);
 555             }
 556         }
 557 
 558         boundHandle = pairArguments(boundHandle, type);
 559 
 560         return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard);
 561    }
 562 
 563     /**
 564      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
 565      *
 566      * These don't want a callee parameter, so bind that. Name binding is optional.
 567      */
 568     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
 569         return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type, null)), bindName), type);
 570     }
 571 
 572     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
 573         if (bindName == null) {
 574             return methodHandle;
 575         }
 576 
 577         // if it is vararg method, we need to extend argument array with
 578         // a new zeroth element that is set to bindName value.
 579         final MethodType methodType = methodHandle.type();
 580         final int parameterCount = methodType.parameterCount();
 581         final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
 582 
 583         if (isVarArg) {
 584             return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
 585         }
 586         return MH.insertArguments(methodHandle, 1, bindName);
 587     }
 588 
 589     /**
 590      * Get the guard that checks if a {@link ScriptFunction} is equal to
 591      * a known ScriptFunction, using reference comparison
 592      *
 593      * @param function The ScriptFunction to check against. This will be bound to the guard method handle
 594      *
 595      * @return method handle for guard
 596      */
 597     private static MethodHandle getFunctionGuard(final ScriptFunction function) {
 598         assert function.data != null;
 599         return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
 600     }
 601 
 602     /**
 603      * Get a guard that checks if a {@link ScriptFunction} is equal to
 604      * a known ScriptFunction using reference comparison, and whether the type of
 605      * the second argument (this-object) is not a JavaScript primitive type.
 606      *
 607      * @param function The ScriptFunction to check against. This will be bound to the guard method handle
 608      *
 609      * @return method handle for guard
 610      */
 611     private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
 612         assert function.data != null;
 613         return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
 614     }
 615 
 616     @SuppressWarnings("unused")
 617     private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
 618         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data;
 619     }
 620 
 621     @SuppressWarnings("unused")
 622     private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
 623         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
 624     }
 625 
 626     @SuppressWarnings("unused")
 627     private static Object[] addZerothElement(final Object[] args, final Object value) {
 628         // extends input array with by adding new zeroth element
 629         final Object[] src = (args == null)? ScriptRuntime.EMPTY_ARRAY : args;
 630         final Object[] result = new Object[src.length + 1];
 631         System.arraycopy(src, 0, result, 1, src.length);
 632         result[0] = value;
 633         return result;
 634     }
 635 
 636     @SuppressWarnings("unused")
 637     private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
 638             throws Throwable {
 639         final Object syncObj = sync == UNDEFINED ? self : sync;
 640         synchronized (syncObj) {
 641             return func.invoke(self, args);
 642         }
 643     }
 644 
 645     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
 646         final Class<?>   own = ScriptFunction.class;
 647         final MethodType mt  = MH.type(rtype, types);
 648         try {
 649             return MH.findStatic(MethodHandles.lookup(), own, name, mt);
 650         } catch (final MethodHandleFactory.LookupException e) {
 651             return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
 652         }
 653     }
 654 }
 655