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 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
  33 import java.lang.invoke.MethodHandle;
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodType;
  36 import java.lang.invoke.SwitchPoint;
  37 import java.util.ArrayList;
  38 import java.util.Arrays;
  39 import java.util.Collection;
  40 import java.util.Collections;
  41 import java.util.HashSet;
  42 import java.util.List;
  43 import jdk.internal.dynalink.CallSiteDescriptor;
  44 import jdk.internal.dynalink.linker.GuardedInvocation;
  45 import jdk.internal.dynalink.linker.LinkRequest;
  46 import jdk.internal.dynalink.support.Guards;
  47 import jdk.nashorn.internal.codegen.ApplySpecialization;
  48 import jdk.nashorn.internal.codegen.Compiler;
  49 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
  50 import jdk.nashorn.internal.objects.Global;
  51 import jdk.nashorn.internal.objects.NativeFunction;
  52 import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
  53 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  54 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  55 import jdk.nashorn.internal.runtime.logging.DebugLogger;
  56 
  57 /**
  58  * Runtime representation of a JavaScript function.
  59  */
  60 public abstract class ScriptFunction extends ScriptObject {
  61 
  62     /** Method handle for prototype getter for this ScriptFunction */
  63     public static final MethodHandle G$PROTOTYPE = findOwnMH_S("G$prototype", Object.class, Object.class);
  64 
  65     /** Method handle for prototype setter for this ScriptFunction */
  66     public static final MethodHandle S$PROTOTYPE = findOwnMH_S("S$prototype", void.class, Object.class, Object.class);
  67 
  68     /** Method handle for length getter for this ScriptFunction */
  69     public static final MethodHandle G$LENGTH = findOwnMH_S("G$length", int.class, Object.class);
  70 
  71     /** Method handle for name getter for this ScriptFunction */
  72     public static final MethodHandle G$NAME = findOwnMH_S("G$name", Object.class, Object.class);
  73 
  74     /** Method handle used for implementing sync() in mozilla_compat */
  75     public static final MethodHandle INVOKE_SYNC = findOwnMH_S("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
  76 
  77     /** Method handle for allocate function for this ScriptFunction */
  78     static final MethodHandle ALLOCATE = findOwnMH_V("allocate", Object.class);
  79 
  80     private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class);
  81 
  82     private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
  83 
  84     /** method handle to scope getter for this ScriptFunction */
  85     public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
  86 
  87     private static final MethodHandle IS_FUNCTION_MH  = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
  88 
  89     private static final MethodHandle IS_APPLY_FUNCTION  = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class);
  90 
  91     private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH_S("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
  92 
  93     private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH_S("addZerothElement", Object[].class, Object[].class, Object.class);
  94 
  95     private static final MethodHandle WRAP_THIS = MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, "wrapThis", MH.type(Object.class, Object.class));
  96 
  97     /** The parent scope. */
  98     private final ScriptObject scope;
  99 
 100     private final ScriptFunctionData data;
 101 
 102     /** The property map used for newly allocated object when function is used as constructor. */
 103     protected PropertyMap allocatorMap;
 104 
 105     /**
 106      * Constructor
 107      *
 108      * @param name          function name
 109      * @param methodHandle  method handle to function (if specializations are present, assumed to be most generic)
 110      * @param map           property map
 111      * @param scope         scope
 112      * @param specs         specialized version of this function - other method handles
 113      * @param flags         {@link ScriptFunctionData} flags
 114      */
 115     protected ScriptFunction(
 116             final String name,
 117             final MethodHandle methodHandle,
 118             final PropertyMap map,
 119             final ScriptObject scope,
 120             final Specialization[] specs,
 121             final int flags) {
 122 
 123         this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
 124     }
 125 
 126     /**
 127      * Constructor
 128      *
 129      * @param data          static function data
 130      * @param map           property map
 131      * @param scope         scope
 132      */
 133     protected ScriptFunction(
 134             final ScriptFunctionData data,
 135             final PropertyMap map,
 136             final ScriptObject scope) {
 137 
 138         super(map);
 139 
 140         if (Context.DEBUG) {
 141             constructorCount++;
 142         }
 143 
 144         this.data  = data;
 145         this.scope = scope;
 146         this.allocatorMap = data.getAllocatorMap();
 147     }
 148 
 149     @Override
 150     public String getClassName() {
 151         return "Function";
 152     }
 153 
 154     /**
 155      * ECMA 15.3.5.3 [[HasInstance]] (V)
 156      * Step 3 if "prototype" value is not an Object, throw TypeError
 157      */
 158     @Override
 159     public boolean isInstance(final ScriptObject instance) {
 160         final Object basePrototype = getTargetFunction().getPrototype();
 161         if (!(basePrototype instanceof ScriptObject)) {
 162             throw typeError("prototype.not.an.object", ScriptRuntime.safeToString(getTargetFunction()), ScriptRuntime.safeToString(basePrototype));
 163         }
 164 
 165         for (ScriptObject proto = instance.getProto(); proto != null; proto = proto.getProto()) {
 166             if (proto == basePrototype) {
 167                 return true;
 168             }
 169         }
 170 
 171         return false;
 172     }
 173 
 174     /**
 175      * Returns the target function for this function. If the function was not created using
 176      * {@link #makeBoundFunction(Object, Object[])}, its target function is itself. If it is bound, its target function
 177      * is the target function of the function it was made from (therefore, the target function is always the final,
 178      * unbound recipient of the calls).
 179      * @return the target function for this function.
 180      */
 181     protected ScriptFunction getTargetFunction() {
 182         return this;
 183     }
 184 
 185     boolean isBoundFunction() {
 186         return getTargetFunction() != this;
 187     }
 188 
 189     /**
 190      * Set the arity of this ScriptFunction
 191      * @param arity arity
 192      */
 193     public final void setArity(final int arity) {
 194         data.setArity(arity);
 195     }
 196 
 197     /**
 198      * Is this a ECMAScript 'use strict' function?
 199      * @return true if function is in strict mode
 200      */
 201     public boolean isStrict() {
 202         return data.isStrict();
 203     }
 204 
 205     /**
 206      * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
 207      * according to ECMA 10.4.3.
 208      * @return true if this argument must be an object
 209      */
 210     public boolean needsWrappedThis() {
 211         return data.needsWrappedThis();
 212     }
 213 
 214     private static boolean needsWrappedThis(final Object fn) {
 215         return fn instanceof ScriptFunction ? ((ScriptFunction)fn).needsWrappedThis() : false;
 216     }
 217 
 218     /**
 219      * Execute this script function.
 220      * @param self  Target object.
 221      * @param arguments  Call arguments.
 222      * @return ScriptFunction result.
 223      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 224      */
 225     Object invoke(final Object self, final Object... arguments) throws Throwable {
 226         if (Context.DEBUG) {
 227             invokes++;
 228         }
 229         return data.invoke(this, self, arguments);
 230     }
 231 
 232     /**
 233      * Execute this script function as a constructor.
 234      * @param arguments  Call arguments.
 235      * @return Newly constructed result.
 236      * @throws Throwable if there is an exception/error with the invocation or thrown from it
 237      */
 238     Object construct(final Object... arguments) throws Throwable {
 239         return data.construct(this, arguments);
 240     }
 241 
 242     /**
 243      * Allocate function. Called from generated {@link ScriptObject} code
 244      * for allocation as a factory method
 245      *
 246      * @return a new instance of the {@link ScriptObject} whose allocator this is
 247      */
 248     @SuppressWarnings("unused")
 249     private Object allocate() {
 250         if (Context.DEBUG) {
 251             allocations++;
 252         }
 253 
 254         assert !isBoundFunction(); // allocate never invoked on bound functions
 255 
 256         final ScriptObject object = data.allocate(allocatorMap);
 257 
 258         if (object != null) {
 259             final Object prototype = getPrototype();
 260             if (prototype instanceof ScriptObject) {
 261                 object.setInitialProto((ScriptObject)prototype);
 262             }
 263 
 264             if (object.getProto() == null) {
 265                 object.setInitialProto(getObjectPrototype());
 266             }
 267         }
 268 
 269         return object;
 270     }
 271 
 272     /**
 273      * Return Object.prototype - used by "allocate"
 274      * @return Object.prototype
 275      */
 276     protected abstract ScriptObject getObjectPrototype();
 277 
 278     /**
 279      * Creates a version of this function bound to a specific "self" and other arguments, as per
 280      * {@code Function.prototype.bind} functionality in ECMAScript 5.1 section 15.3.4.5.
 281      * @param self the self to bind to this function. Can be null (in which case, null is bound as this).
 282      * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
 283      * @return a function with the specified self and parameters bound.
 284      */
 285     protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
 286         return makeBoundFunction(data.makeBoundFunctionData(this, self, args));
 287     }
 288 
 289     /**
 290      * Create a version of this function as in {@link ScriptFunction#makeBoundFunction(Object, Object[])},
 291      * but using a {@link ScriptFunctionData} for the bound data.
 292      *
 293      * @param boundData ScriptFuntionData for the bound function
 294      * @return a function with the bindings performed according to the given data
 295      */
 296     protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData);
 297 
 298     @Override
 299     public final String safeToString() {
 300         return toSource();
 301     }
 302 
 303     @Override
 304     public String toString() {
 305         return data.toString();
 306     }
 307 
 308     /**
 309      * Get this function as a String containing its source code. If no source code
 310      * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
 311      * @return string representation of this function's source
 312      */
 313     public final String toSource() {
 314         return data.toSource();
 315     }
 316 
 317     /**
 318      * Get the prototype object for this function
 319      * @return prototype
 320      */
 321     public abstract Object getPrototype();
 322 
 323     /**
 324      * Set the prototype object for this function
 325      * @param prototype new prototype object
 326      */
 327     public abstract void setPrototype(Object prototype);
 328 
 329     /**
 330      * Create a function that invokes this function synchronized on {@code sync} or the self object
 331      * of the invocation.
 332      * @param sync the Object to synchronize on, or undefined
 333      * @return synchronized function
 334      */
 335    public abstract ScriptFunction makeSynchronizedFunction(Object sync);
 336 
 337     /**
 338      * Return the invoke handle bound to a given ScriptObject self reference.
 339      * If callee parameter is required result is rebound to this.
 340      *
 341      * @param self self reference
 342      * @return bound invoke handle
 343      */
 344     public final MethodHandle getBoundInvokeHandle(final Object self) {
 345         return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), self);
 346     }
 347 
 348     /**
 349      * Bind the method handle to this {@code ScriptFunction} instance if it needs a callee parameter. If this function's
 350      * method handles don't have a callee parameter, the handle is returned unchanged.
 351      * @param methodHandle the method handle to potentially bind to this function instance.
 352      * @return the potentially bound method handle
 353      */
 354     private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
 355         return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
 356 
 357     }
 358 
 359     /**
 360      * Get the name for this function
 361      * @return the name
 362      */
 363     public final String getName() {
 364         return data.getName();
 365     }
 366 
 367 
 368     /**
 369      * Get the scope for this function
 370      * @return the scope
 371      */
 372     public final ScriptObject getScope() {
 373         return scope;
 374     }
 375 
 376     /**
 377      * Prototype getter for this ScriptFunction - follows the naming convention
 378      * used by Nasgen and the code generator
 379      *
 380      * @param self  self reference
 381      * @return self's prototype
 382      */
 383     public static Object G$prototype(final Object self) {
 384         return self instanceof ScriptFunction ?
 385             ((ScriptFunction)self).getPrototype() :
 386             UNDEFINED;
 387     }
 388 
 389     /**
 390      * Prototype setter for this ScriptFunction - follows the naming convention
 391      * used by Nasgen and the code generator
 392      *
 393      * @param self  self reference
 394      * @param prototype prototype to set
 395      */
 396     public static void S$prototype(final Object self, final Object prototype) {
 397         if (self instanceof ScriptFunction) {
 398             ((ScriptFunction)self).setPrototype(prototype);
 399         }
 400     }
 401 
 402     /**
 403      * Length getter - ECMA 15.3.3.2: Function.length
 404      * @param self self reference
 405      * @return length
 406      */
 407     public static int G$length(final Object self) {
 408         if (self instanceof ScriptFunction) {
 409             return ((ScriptFunction)self).data.getArity();
 410         }
 411 
 412         return 0;
 413     }
 414 
 415     /**
 416      * Name getter - ECMA Function.name
 417      * @param self self refence
 418      * @return the name, or undefined if none
 419      */
 420     public static Object G$name(final Object self) {
 421         if (self instanceof ScriptFunction) {
 422             return ((ScriptFunction)self).getName();
 423         }
 424 
 425         return UNDEFINED;
 426     }
 427 
 428     /**
 429      * Get the prototype for this ScriptFunction
 430      * @param constructor constructor
 431      * @return prototype, or null if given constructor is not a ScriptFunction
 432      */
 433     public static ScriptObject getPrototype(final ScriptFunction constructor) {
 434         if (constructor != null) {
 435             final Object proto = constructor.getPrototype();
 436             if (proto instanceof ScriptObject) {
 437                 return (ScriptObject)proto;
 438             }
 439         }
 440 
 441         return null;
 442     }
 443 
 444     // These counters are updated only in debug mode.
 445     private static int constructorCount;
 446     private static int invokes;
 447     private static int allocations;
 448 
 449     /**
 450      * @return the constructorCount
 451      */
 452     public static int getConstructorCount() {
 453         return constructorCount;
 454     }
 455 
 456     /**
 457      * @return the invokes
 458      */
 459     public static int getInvokes() {
 460         return invokes;
 461     }
 462 
 463     /**
 464      * @return the allocations
 465      */
 466     public static int getAllocations() {
 467         return allocations;
 468     }
 469 
 470     @Override
 471     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
 472         final MethodType type = desc.getMethodType();
 473         assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
 474         final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
 475         final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
 476         //TODO - ClassCastException
 477         return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
 478     }
 479 
 480     private static Object wrapFilter(final Object obj) {
 481         if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
 482             return obj;
 483         }
 484         return Context.getGlobal().wrapAsObject(obj);
 485     }
 486 
 487 
 488     @SuppressWarnings("unused")
 489     private static Object globalFilter(final Object object) {
 490         // replace whatever we get with the current global object
 491         return Context.getGlobal();
 492     }
 493 
 494     /**
 495      * Some receivers are primitive, in that case, according to the Spec we create a new
 496      * native object per callsite with the wrap filter. We can only apply optimistic builtins
 497      * if there is no per instance state saved for these wrapped objects (e.g. currently NativeStrings),
 498      * otherwise we can't create optimistic versions
 499      *
 500      * @param self            receiver
 501      * @param linkLogicClass  linkLogicClass, or null if no link logic exists
 502      * @return link logic instance, or null if one could not be constructed for this receiver
 503      */
 504     private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
 505         if (linkLogicClass == null) {
 506             return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
 507         }
 508 
 509         if (!Context.getContextTrusted().getEnv()._optimistic_types) {
 510             return null; //if optimistic types are off, optimistic builtins are too
 511         }
 512 
 513         final Object wrappedSelf = wrapFilter(self);
 514         if (wrappedSelf instanceof OptimisticBuiltins) {
 515             if (wrappedSelf != self && ((OptimisticBuiltins)wrappedSelf).hasPerInstanceAssumptions()) {
 516                 return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
 517             }
 518             return ((OptimisticBuiltins)wrappedSelf).getLinkLogic(linkLogicClass);
 519         }
 520         return null;
 521     }
 522 
 523     /**
 524      * dyn:call call site signature: (callee, thiz, [args...])
 525      * generated method signature:   (callee, thiz, [args...])
 526      *
 527      * cases:
 528      * (a) method has callee parameter
 529      *   (1) for local/scope calls, we just bind thiz and drop the second argument.
 530      *   (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
 531      * (b) method doesn't have callee parameter (builtin functions)
 532      *   (3) for local/scope calls, bind thiz and drop both callee and thiz.
 533      *   (4) for normal this-calls, drop callee.
 534      *
 535      * @return guarded invocation for call
 536      */
 537     @Override
 538     protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
 539         final MethodType type = desc.getMethodType();
 540 
 541         final String  name       = getName();
 542         final boolean isUnstable = request.isCallSiteUnstable();
 543         final boolean scopeCall  = NashornCallSiteDescriptor.isScope(desc);
 544         final boolean isCall     = !scopeCall && data.isBuiltin() && "call".equals(name);
 545         final boolean isApply    = !scopeCall && data.isBuiltin() && "apply".equals(name);
 546 
 547         final boolean isApplyOrCall = isCall | isApply;
 548 
 549         if (isUnstable && !isApplyOrCall) {
 550             //megamorphic - replace call with apply
 551             final MethodHandle handle;
 552             //ensure that the callsite is vararg so apply can consume it
 553             if (type.parameterCount() == 3 && type.parameterType(2) == Object[].class) {
 554                 // Vararg call site
 555                 handle = ScriptRuntime.APPLY.methodHandle();
 556             } else {
 557                 // (callee, this, args...) => (callee, this, args[])
 558                 handle = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
 559             }
 560 
 561             // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
 562             // generic "is this a ScriptFunction?" guard.
 563             return new GuardedInvocation(
 564                     handle,
 565                     null,
 566                     (SwitchPoint)null,
 567                     ClassCastException.class);
 568         }
 569 
 570         MethodHandle boundHandle;
 571         MethodHandle guard = null;
 572 
 573         // Special handling of Function.apply and Function.call. Note we must be invoking
 574         if (isApplyOrCall && !isUnstable) {
 575             final Object[] args = request.getArguments();
 576             if (Bootstrap.isCallable(args[1])) {
 577                 return createApplyOrCallCall(isApply, desc, request, args);
 578             }
 579         } //else just fall through and link as ordinary function or unstable apply
 580 
 581         int programPoint = INVALID_PROGRAM_POINT;
 582         if (NashornCallSiteDescriptor.isOptimistic(desc)) {
 583             programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
 584         }
 585 
 586         CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
 587         final Object self = request.getArguments()[1];
 588         final Collection<CompiledFunction> forbidden = new HashSet<>();
 589 
 590         //check for special fast versions of the compiled function
 591         final List<SwitchPoint> sps = new ArrayList<>();
 592         Class<? extends Throwable> exceptionGuard = null;
 593 
 594         while (cf.isSpecialization()) {
 595             final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
 596             //if linklogic is null, we can always link with the standard mechanism, it's still a specialization
 597             final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
 598 
 599             if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
 600                 final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
 601 
 602                 if (log.isEnabled()) {
 603                     log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
 604                 }
 605 
 606                 exceptionGuard = linkLogic.getRelinkException();
 607 
 608                 break;
 609             }
 610 
 611             //could not link this specialization because link check failed
 612             forbidden.add(cf);
 613             final CompiledFunction oldCf = cf;
 614             cf = data.getBestInvoker(type, scope, forbidden);
 615             assert oldCf != cf;
 616         }
 617 
 618         final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
 619         final MethodHandle callHandle = bestInvoker.getInvocation();
 620 
 621         if (data.needsCallee()) {
 622             if (scopeCall && needsWrappedThis()) {
 623                 // (callee, this, args...) => (callee, [this], args...)
 624                 boundHandle = MH.filterArguments(callHandle, 1, SCRIPTFUNCTION_GLOBALFILTER);
 625             } else {
 626                 // It's already (callee, this, args...), just what we need
 627                 boundHandle = callHandle;
 628             }
 629         } else if (data.isBuiltin() && "extend".equals(data.getName())) {
 630             // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
 631             // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
 632             boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, type.parameterType(0), type.parameterType(1));
 633         } else if (scopeCall && needsWrappedThis()) {
 634             // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
 635             // (this, args...) => ([this], args...)
 636             boundHandle = MH.filterArguments(callHandle, 0, SCRIPTFUNCTION_GLOBALFILTER);
 637             // ([this], args...) => ([callee], [this], args...)
 638             boundHandle = MH.dropArguments(boundHandle, 0, type.parameterType(0));
 639         } else {
 640             // (this, args...) => ([callee], this, args...)
 641             boundHandle = MH.dropArguments(callHandle, 0, type.parameterType(0));
 642         }
 643 
 644         // For non-strict functions, check whether this-object is primitive type.
 645         // If so add a to-object-wrapper argument filter.
 646         // Else install a guard that will trigger a relink when the argument becomes primitive.
 647         if (!scopeCall && needsWrappedThis()) {
 648             if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
 649                 boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
 650             } else {
 651                 guard = getNonStrictFunctionGuard(this);
 652             }
 653         }
 654 
 655         boundHandle = pairArguments(boundHandle, type);
 656 
 657         if (bestInvoker.getSwitchPoints() != null) {
 658             sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
 659         }
 660         final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
 661 
 662         return new GuardedInvocation(
 663                 boundHandle,
 664                 guard == null ?
 665                         getFunctionGuard(
 666                                 this,
 667                                 cf.getFlags()) :
 668                         guard,
 669                         spsArray,
 670                 exceptionGuard);
 671     }
 672 
 673     private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
 674         final MethodType descType = desc.getMethodType();
 675         final int paramCount = descType.parameterCount();
 676         if(descType.parameterType(paramCount - 1).isArray()) {
 677             // This is vararg invocation of apply or call. This can normally only happen when we do a recursive
 678             // invocation of createApplyOrCallCall (because we're doing apply-of-apply). In this case, create delegate
 679             // linkage by unpacking the vararg invocation and use pairArguments to introduce the necessary spreader.
 680             return createVarArgApplyOrCallCall(isApply, desc, request, args);
 681         }
 682 
 683         final boolean passesThis = paramCount > 2;
 684         final boolean passesArgs = paramCount > 3;
 685         final int realArgCount = passesArgs ? paramCount - 3 : 0;
 686 
 687         final Object appliedFn = args[1];
 688         final boolean appliedFnNeedsWrappedThis = needsWrappedThis(appliedFn);
 689 
 690         //box call back to apply
 691         CallSiteDescriptor appliedDesc = desc;
 692         final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
 693         //enough to change the proto switchPoint here
 694 
 695         final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
 696         final boolean isFailedApplyToCall = isApplyToCall && applyToCallSwitchPoint.hasBeenInvalidated();
 697 
 698         // R(apply|call, ...) => R(...)
 699         MethodType appliedType = descType.dropParameterTypes(0, 1);
 700         if (!passesThis) {
 701             // R() => R(this)
 702             appliedType = appliedType.insertParameterTypes(1, Object.class);
 703         } else if (appliedFnNeedsWrappedThis) {
 704             appliedType = appliedType.changeParameterType(1, Object.class);
 705         }
 706 
 707         /*
 708          * dropArgs is a synthetic method handle that contains any args that we need to
 709          * get rid of that come after the arguments array in the apply case. We adapt
 710          * the callsite to ask for 3 args only and then dropArguments on the method handle
 711          * to make it fit the extraneous args.
 712          */
 713         MethodType dropArgs = MH.type(void.class);
 714         if (isApply && !isFailedApplyToCall) {
 715             final int pc = appliedType.parameterCount();
 716             for (int i = 3; i < pc; i++) {
 717                 dropArgs = dropArgs.appendParameterTypes(appliedType.parameterType(i));
 718             }
 719             if (pc > 3) {
 720                 appliedType = appliedType.dropParameterTypes(3, pc);
 721             }
 722         }
 723 
 724         if (isApply || isFailedApplyToCall) {
 725             if (passesArgs) {
 726                 // R(this, args) => R(this, Object[])
 727                 appliedType = appliedType.changeParameterType(2, Object[].class);
 728                 // drop any extraneous arguments for the apply fail case
 729                 if (isFailedApplyToCall) {
 730                     appliedType = appliedType.dropParameterTypes(3, paramCount - 1);
 731                 }
 732             } else {
 733                 // R(this) => R(this, Object[])
 734                 appliedType = appliedType.insertParameterTypes(2, Object[].class);
 735             }
 736         }
 737 
 738         appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
 739 
 740         // Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
 741         final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
 742         appliedArgs[0] = appliedFn;
 743         appliedArgs[1] = passesThis ? appliedFnNeedsWrappedThis ? ScriptFunctionData.wrapThis(args[2]) : args[2] : ScriptRuntime.UNDEFINED;
 744         if (isApply && !isFailedApplyToCall) {
 745             appliedArgs[2] = passesArgs ? NativeFunction.toApplyArgs(args[3]) : ScriptRuntime.EMPTY_ARRAY;
 746         } else {
 747             if (passesArgs) {
 748                 if (isFailedApplyToCall) {
 749                     final Object[] tmp = new Object[args.length - 3];
 750                     System.arraycopy(args, 3, tmp, 0, tmp.length);
 751                     appliedArgs[2] = NativeFunction.toApplyArgs(tmp);
 752                 } else {
 753                     assert !isApply;
 754                     System.arraycopy(args, 3, appliedArgs, 2, args.length - 3);
 755                 }
 756             } else if (isFailedApplyToCall) {
 757                 appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
 758             }
 759         }
 760 
 761         // Ask the linker machinery for an invocation of the target function
 762         final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
 763 
 764         GuardedInvocation appliedInvocation;
 765         try {
 766             appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
 767         } catch (final RuntimeException | Error e) {
 768             throw e;
 769         } catch (final Exception e) {
 770             throw new RuntimeException(e);
 771         }
 772         assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
 773 
 774         final Class<?> applyFnType = descType.parameterType(0);
 775         MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation
 776 
 777         if (isApply && !isFailedApplyToCall) {
 778             if (passesArgs) {
 779                 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
 780                 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
 781             } else {
 782                 // If the original call site doesn't pass argArray, pass in an empty array
 783                 inv = MH.insertArguments(inv, 2, (Object)ScriptRuntime.EMPTY_ARRAY);
 784             }
 785         }
 786 
 787         if (isApplyToCall) {
 788             if (isFailedApplyToCall) {
 789                 //take the real arguments that were passed to a call and force them into the apply instead
 790                 Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
 791                 inv = MH.asCollector(inv, Object[].class, realArgCount);
 792             } else {
 793                 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
 794             }
 795         }
 796 
 797         if (!passesThis) {
 798             // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
 799             inv = bindImplicitThis(appliedFn, inv);
 800         } else if (appliedFnNeedsWrappedThis) {
 801             // target function needs a wrapped this, so make sure we filter for that
 802             inv = MH.filterArguments(inv, 1, WRAP_THIS);
 803         }
 804         inv = MH.dropArguments(inv, 0, applyFnType);
 805 
 806         /*
 807          * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
 808          * is when we need to add arguments to the callsite to catch and ignore the synthetic
 809          * extra args that someone has added to the command line.
 810          */
 811         for (int i = 0; i < dropArgs.parameterCount(); i++) {
 812             inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
 813         }
 814 
 815         MethodHandle guard = appliedInvocation.getGuard();
 816         // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one
 817         if (!passesThis && guard.type().parameterCount() > 1) {
 818             guard = bindImplicitThis(appliedFn, guard);
 819         }
 820         final MethodType guardType = guard.type();
 821 
 822         // We need to account for the dropped (apply|call) function argument.
 823         guard = MH.dropArguments(guard, 0, descType.parameterType(0));
 824         // Take the "isApplyFunction" guard, and bind it to this function.
 825         MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
 826         // Adapt the guard to receive all the arguments that the original guard does.
 827         applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
 828         // Fold the original function guard into our apply guard.
 829         guard = MH.foldArguments(applyFnGuard, guard);
 830 
 831         return appliedInvocation.replaceMethods(inv, guard);
 832     }
 833 
 834     /*
 835      * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity
 836      * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with
 837      * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method.
 838      * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back
 839      * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to
 840      * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity
 841      * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already
 842      * solved by createApplyOrCallCall) non-vararg call site linking.
 843      */
 844     private GuardedInvocation createVarArgApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc,
 845             final LinkRequest request, final Object[] args) {
 846         final MethodType descType = desc.getMethodType();
 847         final int paramCount = descType.parameterCount();
 848         final Object[] varArgs = (Object[])args[paramCount - 1];
 849         // -1 'cause we're not passing the vararg array itself
 850         final int copiedArgCount = args.length - 1;
 851         final int varArgCount = varArgs.length;
 852 
 853         // Spread arguments for the delegate createApplyOrCallCall invocation.
 854         final Object[] spreadArgs = new Object[copiedArgCount + varArgCount];
 855         System.arraycopy(args, 0, spreadArgs, 0, copiedArgCount);
 856         System.arraycopy(varArgs, 0, spreadArgs, copiedArgCount, varArgCount);
 857 
 858         // Spread call site descriptor for the delegate createApplyOrCallCall invocation. We drop vararg array and
 859         // replace it with a list of Object.class.
 860         final MethodType spreadType = descType.dropParameterTypes(paramCount - 1, paramCount).appendParameterTypes(
 861                 Collections.<Class<?>>nCopies(varArgCount, Object.class));
 862         final CallSiteDescriptor spreadDesc = desc.changeMethodType(spreadType);
 863 
 864         // Delegate back to createApplyOrCallCall with the spread (that is, reverted to non-vararg) request/
 865         final LinkRequest spreadRequest = request.replaceArguments(spreadDesc, spreadArgs);
 866         final GuardedInvocation spreadInvocation = createApplyOrCallCall(isApply, spreadDesc, spreadRequest, spreadArgs);
 867 
 868         // Add spreader combinators to returned invocation and guard.
 869         return spreadInvocation.replaceMethods(
 870                 // Use standard ScriptObject.pairArguments on the invocation
 871                 pairArguments(spreadInvocation.getInvocation(), descType),
 872                 // Use our specialized spreadGuardArguments on the guard (see below).
 873                 spreadGuardArguments(spreadInvocation.getGuard(), descType));
 874     }
 875 
 876     private static MethodHandle spreadGuardArguments(final MethodHandle guard, final MethodType descType) {
 877         final MethodType guardType = guard.type();
 878         final int guardParamCount = guardType.parameterCount();
 879         final int descParamCount = descType.parameterCount();
 880         final int spreadCount = guardParamCount - descParamCount + 1;
 881         if (spreadCount <= 0) {
 882             // Guard doesn't dip into the varargs
 883             return guard;
 884         }
 885 
 886         final MethodHandle arrayConvertingGuard;
 887         // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
 888         // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
 889         // with ClassCastException of NativeArray to Object[].
 890         if(guardType.parameterType(guardParamCount - 1).isArray()) {
 891             arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
 892         } else {
 893             arrayConvertingGuard = guard;
 894         }
 895 
 896         return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount);
 897     }
 898 
 899     private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) {
 900          final MethodHandle bound;
 901          if(fn instanceof ScriptFunction && ((ScriptFunction)fn).needsWrappedThis()) {
 902              bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
 903          } else {
 904              bound = mh;
 905          }
 906          return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
 907      }
 908 
 909     /**
 910      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
 911      *
 912      * These don't want a callee parameter, so bind that. Name binding is optional.
 913      */
 914     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
 915         return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
 916     }
 917 
 918     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
 919         if (bindName == null) {
 920             return methodHandle;
 921         }
 922 
 923         // if it is vararg method, we need to extend argument array with
 924         // a new zeroth element that is set to bindName value.
 925         final MethodType methodType = methodHandle.type();
 926         final int parameterCount = methodType.parameterCount();
 927         final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
 928 
 929         if (isVarArg) {
 930             return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
 931         }
 932         return MH.insertArguments(methodHandle, 1, bindName);
 933     }
 934 
 935     /**
 936      * Get the guard that checks if a {@link ScriptFunction} is equal to
 937      * a known ScriptFunction, using reference comparison
 938      *
 939      * @param function The ScriptFunction to check against. This will be bound to the guard method handle
 940      *
 941      * @return method handle for guard
 942      */
 943     private static MethodHandle getFunctionGuard(final ScriptFunction function, final int flags) {
 944         assert function.data != null;
 945         // Built-in functions have a 1-1 correspondence to their ScriptFunctionData, so we can use a cheaper identity
 946         // comparison for them.
 947         if (function.data.isBuiltin()) {
 948             return Guards.getIdentityGuard(function);
 949         }
 950         return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
 951     }
 952 
 953     /**
 954      * Get a guard that checks if a {@link ScriptFunction} is equal to
 955      * a known ScriptFunction using reference comparison, and whether the type of
 956      * the second argument (this-object) is not a JavaScript primitive type.
 957      *
 958      * @param function The ScriptFunction to check against. This will be bound to the guard method handle
 959      *
 960      * @return method handle for guard
 961      */
 962     private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
 963         assert function.data != null;
 964         return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
 965     }
 966 
 967     @SuppressWarnings("unused")
 968     private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
 969         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data;
 970     }
 971 
 972     @SuppressWarnings("unused")
 973     private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
 974         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
 975     }
 976 
 977     //TODO this can probably be removed given that we have builtin switchpoints in the context
 978     @SuppressWarnings("unused")
 979     private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
 980         // NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
 981         return appliedFnCondition && self == expectedSelf;
 982     }
 983 
 984     @SuppressWarnings("unused")
 985     private static Object[] addZerothElement(final Object[] args, final Object value) {
 986         // extends input array with by adding new zeroth element
 987         final Object[] src = args == null? ScriptRuntime.EMPTY_ARRAY : args;
 988         final Object[] result = new Object[src.length + 1];
 989         System.arraycopy(src, 0, result, 1, src.length);
 990         result[0] = value;
 991         return result;
 992     }
 993 
 994     @SuppressWarnings("unused")
 995     private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
 996             throws Throwable {
 997         final Object syncObj = sync == UNDEFINED ? self : sync;
 998         synchronized (syncObj) {
 999             return func.invoke(self, args);
1000         }
1001     }
1002 
1003     private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
1004         return MH.findStatic(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
1005     }
1006 
1007     private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
1008         return MH.findVirtual(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
1009     }
1010 }
1011