changeset 838:636c6e455269

Merge
author lagergren
date Fri, 11 Apr 2014 16:52:56 +0200
parents ddda121eca56 (diff) f47393d4559b (current diff)
children 8423d57c70de
files
diffstat 55 files changed, 1590 insertions(+), 265 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/internal/dynalink/linker/GuardedInvocation.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/internal/dynalink/linker/GuardedInvocation.java	Fri Apr 11 16:52:56 2014 +0200
@@ -110,7 +110,7 @@
     private final MethodHandle invocation;
     private final MethodHandle guard;
     private final Class<? extends Throwable> exception;
-    private final SwitchPoint switchPoint;
+    private final SwitchPoint[] switchPoints;
 
     /**
      * Creates a new guarded invocation. This invocation is unconditional as it has no invalidations.
@@ -118,8 +118,8 @@
      * @param invocation the method handle representing the invocation. Must not be null.
      * @throws NullPointerException if invocation is null.
      */
-    public GuardedInvocation(MethodHandle invocation) {
-        this(invocation, null, null, null);
+    public GuardedInvocation(final MethodHandle invocation) {
+        this(invocation, null, (SwitchPoint)null, null);
     }
 
     /**
@@ -131,8 +131,8 @@
      * an unconditional invocation, although that is unusual.
      * @throws NullPointerException if invocation is null.
      */
-    public GuardedInvocation(MethodHandle invocation, MethodHandle guard) {
-        this(invocation, guard, null, null);
+    public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard) {
+        this(invocation, guard, (SwitchPoint)null, null);
     }
 
     /**
@@ -142,7 +142,7 @@
      * @param switchPoint the optional switch point that can be used to invalidate this linkage.
      * @throws NullPointerException if invocation is null.
      */
-    public GuardedInvocation(MethodHandle invocation, SwitchPoint switchPoint) {
+    public GuardedInvocation(final MethodHandle invocation, final SwitchPoint switchPoint) {
         this(invocation, null, switchPoint, null);
     }
 
@@ -156,7 +156,7 @@
      * @param switchPoint the optional switch point that can be used to invalidate this linkage.
      * @throws NullPointerException if invocation is null.
      */
-    public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint) {
+    public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint) {
         this(invocation, guard, switchPoint, null);
     }
 
@@ -172,11 +172,31 @@
      * invalidates the linkage.
      * @throws NullPointerException if invocation is null.
      */
-    public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint, Class<? extends Throwable> exception) {
+    public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint, final Class<? extends Throwable> exception) {
         invocation.getClass(); // NPE check
         this.invocation = invocation;
         this.guard = guard;
-        this.switchPoint = switchPoint;
+        this.switchPoints = switchPoint == null ? null : new SwitchPoint[] { switchPoint };
+        this.exception = exception;
+    }
+
+    /**
+     * Creates a new guarded invocation
+     *
+     * @param invocation the method handle representing the invocation. Must not be null.
+     * @param guard the method handle representing the guard. Must have the same method type as the invocation, except
+     * it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it
+     * and the switch point are null, this represents an unconditional invocation, which is legal but unusual.
+     * @param switchPoints the optional switch points that can be used to invalidate this linkage.
+     * @param exception the optional exception type that is expected to be thrown by the invocation and that also
+     * invalidates the linkage.
+     * @throws NullPointerException if invocation is null.
+     */
+    public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint[] switchPoints, final Class<? extends Throwable> exception) {
+        invocation.getClass(); // NPE check
+        this.invocation = invocation;
+        this.guard = guard;
+        this.switchPoints = switchPoints;
         this.exception = exception;
     }
 
@@ -203,8 +223,8 @@
      *
      * @return the switch point that can be used to invalidate the invocation handle. Can be null.
      */
-    public SwitchPoint getSwitchPoint() {
-        return switchPoint;
+    public SwitchPoint[] getSwitchPoints() {
+        return switchPoints == null ? null : switchPoints.clone();
     }
 
     /**
@@ -221,7 +241,15 @@
      * @return true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated.
      */
     public boolean hasBeenInvalidated() {
-        return switchPoint != null && switchPoint.hasBeenInvalidated();
+        if (switchPoints == null) {
+            return false;
+        }
+        for (final SwitchPoint sp : switchPoints) {
+            if (sp.hasBeenInvalidated()) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -231,9 +259,9 @@
      * @param type the asserted type
      * @throws WrongMethodTypeException if the invocation and the guard are not of the expected method type.
      */
-    public void assertType(MethodType type) {
+    public void assertType(final MethodType type) {
         assertType(invocation, type);
-        if(guard != null) {
+        if (guard != null) {
             assertType(guard, type.changeReturnType(Boolean.TYPE));
         }
     }
@@ -245,12 +273,34 @@
      * @param newGuard the new guard
      * @return a new guarded invocation with the replaced methods and the same switch point as this invocation.
      */
-    public GuardedInvocation replaceMethods(MethodHandle newInvocation, MethodHandle newGuard) {
-        return new GuardedInvocation(newInvocation, newGuard, switchPoint, exception);
+    public GuardedInvocation replaceMethods(final MethodHandle newInvocation, final MethodHandle newGuard) {
+        return new GuardedInvocation(newInvocation, newGuard, switchPoints, exception);
     }
 
-    private GuardedInvocation replaceMethodsOrThis(MethodHandle newInvocation, MethodHandle newGuard) {
-        if(newInvocation == invocation && newGuard == guard) {
+    /**
+     * Add a switchpoint to this guarded invocation
+     * @param newSwitchPoint new switchpoint, or null for nop
+     * @return new guarded invocation with the extra switchpoint
+     */
+    public GuardedInvocation addSwitchPoint(final SwitchPoint newSwitchPoint) {
+        if (newSwitchPoint == null) {
+            return this;
+        }
+
+        final SwitchPoint[] newSwitchPoints;
+        if (switchPoints != null) {
+            newSwitchPoints = new SwitchPoint[switchPoints.length + 1];
+            System.arraycopy(switchPoints, 0, newSwitchPoints, 0, switchPoints.length);
+            newSwitchPoints[switchPoints.length] = newSwitchPoint;
+        } else {
+            newSwitchPoints = new SwitchPoint[] { newSwitchPoint };
+        }
+
+        return new GuardedInvocation(invocation, guard, newSwitchPoints, exception);
+    }
+
+    private GuardedInvocation replaceMethodsOrThis(final MethodHandle newInvocation, final MethodHandle newGuard) {
+        if (newInvocation == invocation && newGuard == guard) {
             return this;
         }
         return replaceMethods(newInvocation, newGuard);
@@ -263,7 +313,7 @@
      * @param newType the new type of the invocation.
      * @return a guarded invocation with the new type applied to it.
      */
-    public GuardedInvocation asType(MethodType newType) {
+    public GuardedInvocation asType(final MethodType newType) {
         return replaceMethodsOrThis(invocation.asType(newType), guard == null ? null : Guards.asType(guard, newType));
     }
 
@@ -275,7 +325,7 @@
      * @param newType the new type of the invocation.
      * @return a guarded invocation with the new type applied to it.
      */
-    public GuardedInvocation asType(LinkerServices linkerServices, MethodType newType) {
+    public GuardedInvocation asType(final LinkerServices linkerServices, final MethodType newType) {
         return replaceMethodsOrThis(linkerServices.asType(invocation, newType), guard == null ? null :
             Guards.asType(linkerServices, guard, newType));
     }
@@ -289,7 +339,7 @@
      * @param newType the new type of the invocation.
      * @return a guarded invocation with the new type applied to it.
      */
-    public GuardedInvocation asTypeSafeReturn(LinkerServices linkerServices, MethodType newType) {
+    public GuardedInvocation asTypeSafeReturn(final LinkerServices linkerServices, final MethodType newType) {
         return replaceMethodsOrThis(linkerServices.asTypeLosslessReturn(invocation, newType), guard == null ? null :
             Guards.asType(linkerServices, guard, newType));
     }
@@ -301,7 +351,7 @@
      * @param desc a call descriptor whose method type is adapted.
      * @return a guarded invocation with the new type applied to it.
      */
-    public GuardedInvocation asType(CallSiteDescriptor desc) {
+    public GuardedInvocation asType(final CallSiteDescriptor desc) {
         return asType(desc.getMethodType());
     }
 
@@ -311,7 +361,7 @@
      * @param filters the argument filters
      * @return a filtered invocation
      */
-    public GuardedInvocation filterArguments(int pos, MethodHandle... filters) {
+    public GuardedInvocation filterArguments(final int pos, final MethodHandle... filters) {
         return replaceMethods(MethodHandles.filterArguments(invocation, pos, filters), guard == null ? null :
             MethodHandles.filterArguments(guard, pos, filters));
     }
@@ -322,7 +372,7 @@
      * @param valueTypes the types of the values being dropped
      * @return an invocation that drops arguments
      */
-    public GuardedInvocation dropArguments(int pos, List<Class<?>> valueTypes) {
+    public GuardedInvocation dropArguments(final int pos, final List<Class<?>> valueTypes) {
         return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null :
             MethodHandles.dropArguments(guard, pos, valueTypes));
     }
@@ -333,7 +383,7 @@
      * @param valueTypes the types of the values being dropped
      * @return an invocation that drops arguments
      */
-    public GuardedInvocation dropArguments(int pos, Class<?>... valueTypes) {
+    public GuardedInvocation dropArguments(final int pos, final Class<?>... valueTypes) {
         return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null :
             MethodHandles.dropArguments(guard, pos, valueTypes));
     }
@@ -344,7 +394,7 @@
      * @param fallback the fallback method handle in case switchpoint is invalidated or guard returns false.
      * @return a composite method handle.
      */
-    public MethodHandle compose(MethodHandle fallback) {
+    public MethodHandle compose(final MethodHandle fallback) {
         return compose(fallback, fallback, fallback);
     }
 
@@ -355,7 +405,7 @@
      * @param catchFallback the fallback method in case the exception handler triggers
      * @return a composite method handle.
      */
-    public MethodHandle compose(MethodHandle guardFallback, MethodHandle switchpointFallback, MethodHandle catchFallback) {
+    public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) {
         final MethodHandle guarded =
                 guard == null ?
                         invocation :
@@ -375,24 +425,26 @@
                                     0,
                                     exception));
 
-        final MethodHandle spGuarded =
-                switchPoint == null ?
-                        catchGuarded :
-                        switchPoint.guardWithTest(
-                                catchGuarded,
-                                switchpointFallback);
+        if (switchPoints == null) {
+            return catchGuarded;
+        }
+
+        MethodHandle spGuarded = catchGuarded;
+        for (final SwitchPoint sp : switchPoints) {
+            spGuarded = sp.guardWithTest(spGuarded, switchpointFallback);
+        }
 
         return spGuarded;
     }
 
     private static MethodHandle catchException(final MethodHandle target, final Class<? extends Throwable> exType, final MethodHandle handler) {
-        if(USE_FAST_REWRITE) {
+        if (USE_FAST_REWRITE) {
             return CatchExceptionCombinator.catchException(target, exType, handler);
         }
         return MethodHandles.catchException(target, exType, handler);
     }
 
-    private static void assertType(MethodHandle mh, MethodType type) {
+    private static void assertType(final MethodHandle mh, final MethodType type) {
         if(!mh.type().equals(type)) {
             throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type());
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS_VAR;
+import static jdk.nashorn.internal.codegen.CompilerConstants.EXPLODED_ARGUMENT_PREFIX;
+
+import java.lang.invoke.MethodType;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.CallNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+
+/**
+ * An optimization that attempts to turn applies into calls. This pattern
+ * is very common for fake class instance creation, and apply
+ * introduces expensive args collection and boxing
+ *
+ * <pre>
+ * {@code
+ * var Class = {
+ *     create: function() {
+ *         return function() { //vararg
+ *             this.initialize.apply(this, arguments);
+ *         }
+ *     }
+ * };
+ *
+ * Color = Class.create();
+ *
+ * Color.prototype = {
+ *    red: 0, green: 0, blue: 0,
+ *    initialize: function(r,g,b) {
+ *        this.red = r;
+ *        this.green = g;
+ *        this.blue = b;
+ *    }
+ * }
+ *
+ * new Color(17, 47, 11);
+ * }
+ * </pre>
+ */
+
+public class ApplySpecialization {
+
+    private final RecompilableScriptFunctionData data;
+
+    private FunctionNode functionNode;
+
+    private final MethodType actualCallSiteType;
+
+    private static final DebugLogger LOG = new DebugLogger("apply2call");
+
+    private static final String ARGUMENTS = ARGUMENTS_VAR.symbolName();
+
+    private boolean changed;
+
+    private boolean finished;
+
+    private final boolean isRestOf;
+
+    /**
+     * Return the apply to call specialization logger
+     * @return the logger
+     */
+    public static DebugLogger getLogger() {
+        return LOG;
+    }
+
+    /**
+     * Apply specialization optimization. Try to explode arguments and call
+     * applies as calls if they just pass on the "arguments" array and
+     * "arguments" doesn't escape.
+     *
+     * @param data                recompilable script function data, which contains e.g. needs callee information
+     * @param functionNode        functionNode
+     * @param actualCallSiteType  actual call site type that we use (not Object[] varargs)
+     * @param isRestOf            is this a restof method
+     */
+    public ApplySpecialization(final RecompilableScriptFunctionData data, final FunctionNode functionNode, final MethodType actualCallSiteType, final boolean isRestOf) {
+        this.data = data;
+        this.functionNode = functionNode;
+        this.actualCallSiteType = actualCallSiteType;
+        this.isRestOf = isRestOf;
+    }
+
+    /**
+     * Return the function node, possibly after transformation
+     * @return function node
+     */
+    public FunctionNode getFunctionNode() {
+        return functionNode;
+    }
+
+    /**
+     * Arguments may only be used as args to the apply. Everything else is disqualified
+     * @return true if arguments escape
+     */
+    private boolean argumentsEscape() {
+
+        final Deque<Set<Expression>> stack = new ArrayDeque<>();
+        //ensure that arguments is only passed as arg to apply
+        try {
+            functionNode = (FunctionNode)functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                private boolean isCurrentArg(final Expression expr) {
+                    return !stack.isEmpty() && stack.peek().contains(expr);
+                }
+
+                private boolean isArguments(final Expression expr) {
+                    return expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName());
+                }
+
+                @Override
+                public Node leaveIdentNode(final IdentNode identNode) {
+                    if (ARGUMENTS.equals(identNode.getName()) && !isCurrentArg(identNode)) {
+                        throw new UnsupportedOperationException();
+                    }
+                    return identNode;
+                }
+
+                @Override
+                public boolean enterCallNode(final CallNode callNode) {
+                    final Set<Expression> callArgs = new HashSet<>();
+                    if (isApply(callNode)) {
+                        final List<Expression> argList = callNode.getArgs();
+                        if (argList.size() != 2 || !isArguments(argList.get(argList.size() - 1))) {
+                            throw new UnsupportedOperationException();
+                        }
+                        callArgs.addAll(callNode.getArgs());
+                    }
+                    stack.push(callArgs);
+                    return true;
+                }
+
+                @Override
+                public Node leaveCallNode(final CallNode callNode) {
+                    stack.pop();
+                    return callNode;
+                }
+            });
+        } catch (final UnsupportedOperationException e) {
+            LOG.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
+            return true; //bad
+        }
+
+        return false;
+    }
+
+    private boolean finish() {
+        finished = true;
+        return changed;
+    }
+
+    /**
+     * Try to do the apply to call transformation
+     * @return true if successful, false otherwise
+     */
+    public boolean transform() {
+        if (finished) {
+            throw new AssertionError("Can't apply transform twice");
+        }
+
+        changed = false;
+
+        if (!Global.instance().isSpecialNameValid("apply")) {
+            LOG.fine("Apply transform disabled: apply/call overridden");
+            assert !Global.instance().isSpecialNameValid("call") : "call and apply should have the same SwitchPoint";
+            return finish();
+        }
+
+        //eval can do anything to escape arguments so that is not ok
+        if (functionNode.hasEval()) {
+            return finish();
+        }
+
+        if (argumentsEscape()) {
+            return finish();
+        }
+
+        int start = 0;
+
+        if (data.needsCallee()) {
+            start++;
+        }
+
+        start++; //we always uses this
+
+        final List<IdentNode> newParams = new ArrayList<>();
+        for (int i = start; i < actualCallSiteType.parameterCount(); i++) {
+            newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i - start)));
+        }
+
+        // expand arguments
+        // this function has to be guarded with call and apply being builtins
+        functionNode = (FunctionNode)functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public Node leaveCallNode(final CallNode callNode) {
+                //apply needs to be a global symbol or we don't allow it
+
+                if (isApply(callNode)) {
+                    final List<Expression> newArgs = new ArrayList<>();
+                    for (final Expression arg : callNode.getArgs()) {
+                        if (arg instanceof IdentNode && ARGUMENTS.equals(((IdentNode)arg).getName())) {
+                            newArgs.addAll(newParams);
+                        } else {
+                            newArgs.add(arg);
+                        }
+                    }
+
+                    changed = true;
+
+                    final CallNode newCallNode = callNode.setArgs(newArgs).setIsApplyToCall();
+                    LOG.fine("Transformed " + callNode + " from apply to call => " + newCallNode + " in '" + functionNode.getName() + "'");
+                    return newCallNode;
+                }
+
+                return callNode;
+            }
+        });
+
+        if (changed) {
+            functionNode = functionNode.clearFlag(null, FunctionNode.USES_ARGUMENTS).
+                    setFlag(null, FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION).
+                    setParameters(null, newParams);
+        }
+
+        LOG.info("Successfully specialized apply to call in '" + functionNode.getName() + "' id=" + functionNode.getId() + " signature=" + actualCallSiteType + " isRestOf=" + isRestOf);
+        return finish();
+    }
+
+    private static boolean isApply(final Node node) {
+        if (node instanceof AccessNode) {
+            return isApply(((AccessNode)node).getProperty());
+        }
+        return node instanceof IdentNode && "apply".equals(((IdentNode)node).getName());
+    }
+
+    private static boolean isApply(final CallNode callNode) {
+        final Expression f = callNode.getFunction();
+        return f instanceof AccessNode && isApply(f);
+    }
+
+}
--- a/src/jdk/nashorn/internal/codegen/Attr.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/Attr.java	Fri Apr 11 16:52:56 2014 +0200
@@ -1,4 +1,5 @@
 /*
+
  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -588,8 +589,7 @@
         final int optimisticFlag = lc.hasOptimisticAssumptions() ? FunctionNode.IS_OPTIMISTIC : 0;
 
         newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR).setFlag(lc, optimisticFlag);
-
-        popLocals();
+        popLocalsFunction();
 
         if (!env.isOnDemandCompilation() && newFunctionNode.isProgram()) {
             newFunctionNode = newFunctionNode.setBody(lc, newFunctionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE));
@@ -2147,6 +2147,10 @@
         localUses.pop();
     }
 
+    private void popLocalsFunction() {
+        popLocals();
+    }
+
     private boolean isLocalDef(final String name) {
         return localDefs.peek().contains(name);
     }
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Apr 11 16:52:56 2014 +0200
@@ -51,6 +51,7 @@
 import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_APPLY_TO_CALL;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
@@ -809,7 +810,11 @@
     }
 
     private int loadArgs(final List<Expression> args) {
-        return loadArgs(args, null, false, args.size());
+        return loadArgs(args, args.size());
+    }
+
+    private int loadArgs(final List<Expression> args, final int argCount) {
+        return loadArgs(args, null, false, argCount);
     }
 
     private int loadArgs(final List<Expression> args, final String signature, final boolean isVarArg, final int argCount) {
@@ -990,6 +995,11 @@
 
             @Override
             public boolean enterAccessNode(final AccessNode node) {
+                //check if this is an apply to call node. only real applies, that haven't been
+                //shadowed from their way to the global scope counts
+
+                //call nodes have program points.
+
                 new OptimisticOperation() {
                     int argCount;
                     @Override
@@ -999,14 +1009,14 @@
                         // NOTE: not using a nested OptimisticOperation on this dynamicGet, as we expect to get back
                         // a callable object. Nobody in their right mind would optimistically type this call site.
                         assert !node.isOptimistic();
-                        method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true);
+                        final int flags = getCallSiteFlags() | (callNode.isApplyToCall() ? CALLSITE_APPLY_TO_CALL : 0);
+                        method.dynamicGet(node.getType(), node.getProperty().getName(), flags, true);
                         method.swap();
                         argCount = loadArgs(args);
                     }
                     @Override
                     void consumeStack() {
-                        final int flags = getCallSiteFlagsOptimistic(callNode);
-                        dynamicCall(method, callNode, callNodeType, 2 + argCount, flags);
+                        dynamicCall(method, callNode, callNodeType, 2 + argCount, getCallSiteFlagsOptimistic(callNode) | (callNode.isApplyToCall() ? CALLSITE_APPLY_TO_CALL : 0));
                     }
                 }.emit(callNode);
 
@@ -1034,7 +1044,6 @@
                         final int flags = getCallSiteFlagsOptimistic(callNode);
                         //assert callNodeType.equals(callee.getReturnType()) : callNodeType + " != " + callee.getReturnType();
                         dynamicCall(method, callNode, callNodeType, 2 + argsCount, flags);
-                        //assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
                     }
                 }.emit(callNode);
                 method.convert(callNodeType);
@@ -1149,7 +1158,7 @@
 
     private static MethodEmitter dynamicCall(final MethodEmitter method, final Expression expr, final Type desiredType, final int argCount, final int flags) {
         final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags);
-        if(isOptimistic(finalFlags)) {
+        if (isOptimistic(finalFlags)) {
             return method.dynamicCall(getOptimisticCoercedType(desiredType, expr), argCount, finalFlags).convert(desiredType);
         }
         return method.dynamicCall(desiredType, argCount, finalFlags);
@@ -2024,16 +2033,9 @@
 
         //make sure that undefined has not been overridden or scoped as a local var
         //between us and global
-        final CompilationEnvironment  env = compiler.getCompilationEnvironment();
-        RecompilableScriptFunctionData data = env.getScriptFunctionData(lc.getCurrentFunction().getId());
-        final RecompilableScriptFunctionData program = compiler.getCompilationEnvironment().getProgram();
-        assert data != null;
-
-        while (data != program) {
-            if (data.hasInternalSymbol("undefined")) {
-                return false;
-            }
-            data = data.getParent();
+        final CompilationEnvironment env = compiler.getCompilationEnvironment();
+        if (!env.isGlobalSymbol(lc.getCurrentFunction(), "undefined")) {
+            return false;
         }
 
         load(expr);
--- a/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java	Fri Apr 11 16:52:56 2014 +0200
@@ -481,18 +481,15 @@
         if (compiledFunction == null) {
             return null;
         }
-        RecompilableScriptFunctionData program = compiledFunction;
-        while (true) {
-            final RecompilableScriptFunctionData parent = program.getParent();
-            if (parent == null) {
-                return program;
-            }
-            program = parent;
-        }
+        return compiledFunction.getProgram();
     }
 
     RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
         return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId);
     }
 
+    boolean isGlobalSymbol(final FunctionNode functionNode, final String name) {
+        final RecompilableScriptFunctionData data = getScriptFunctionData(functionNode.getId());
+        return data.isGlobalSymbol(functionNode, name);
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Fri Apr 11 16:52:56 2014 +0200
@@ -244,7 +244,7 @@
     public FunctionNode compile(final String className, final FunctionNode functionNode) throws CompilationException {
         try {
             return compileInternal(className, functionNode);
-        } catch(final AssertionError e) {
+        } catch (final AssertionError e) {
             throw new AssertionError("Assertion failure compiling " + functionNode.getSource(), e);
         }
     }
--- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Fri Apr 11 16:52:56 2014 +0200
@@ -111,6 +111,9 @@
     /** the internal arguments object, when necessary (not visible to scripts, can't be reassigned). */
     ARGUMENTS(":arguments", ScriptObject.class),
 
+    /** prefix for apply-to-call exploded arguments */
+    EXPLODED_ARGUMENT_PREFIX(":xarg"),
+
     /** prefix for iterators for for (x in ...) */
     ITERATOR_PREFIX(":i", Iterator.class),
 
--- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Fri Apr 11 16:52:56 2014 +0200
@@ -36,6 +36,7 @@
 
 import java.util.Iterator;
 import java.util.List;
+
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.runtime.Context;
@@ -143,6 +144,9 @@
                 } else {
                     putSlot(method, ArrayIndex.toLongIndex(index), tuple);
                 }
+
+                //this is a nop of tuple.key isn't e.g. "apply" or another special name
+                method.invalidateSpecialName(tuple.key);
             }
         }
     }
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Fri Apr 11 16:52:56 2014 +0200
@@ -78,6 +78,7 @@
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.List;
+
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -94,6 +95,7 @@
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ArgumentSetter;
 import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.DebugLogger;
@@ -168,6 +170,9 @@
     /** Bootstrap for array populators */
     private static final Handle POPULATE_ARRAY_BOOTSTRAP = new Handle(H_INVOKESTATIC, RewriteException.BOOTSTRAP.className(), RewriteException.BOOTSTRAP.name(), RewriteException.BOOTSTRAP.descriptor());
 
+    /** Bootstrap for global name invalidation */
+    private static final Handle INVALIDATE_NAME_BOOTSTRAP = new Handle(H_INVOKESTATIC, Global.BOOTSTRAP.className(), Global.BOOTSTRAP.name(), Global.BOOTSTRAP.descriptor());
+
     /**
      * Constructor - internal use from ClassEmitter only
      * @see ClassEmitter#method
@@ -509,7 +514,6 @@
         stack.markLocalLoad(l0);
         pushType(p1);
         stack.markLocalLoad(l1);
-        debug("after ", p0, p1);
         return this;
     }
 
@@ -1886,6 +1890,15 @@
         return descriptor;
     }
 
+    MethodEmitter invalidateSpecialName(final String name) {
+        //this is a nop if the global hasn't registered this as a special name - we can just ignore it
+        if (Global.instance().isSpecialName(name)) {
+            debug("dynamic_invalidate_name", "name=", name);
+            method.visitInvokeDynamicInsn(name, "()V", INVALIDATE_NAME_BOOTSTRAP);
+        }
+        return this;
+    }
+
     /**
      * Generate a dynamic new
      *
@@ -1923,6 +1936,7 @@
     }
 
     MethodEmitter dynamicArrayPopulatorCall(final int argCount, final int startIndex) {
+        debug("populate_array", "args=", argCount, "startIndex=", startIndex);
         final String signature = getDynamicSignature(Type.OBJECT_ARRAY, argCount);
         method.visitInvokeDynamicInsn("populateArray", signature, POPULATE_ARRAY_BOOTSTRAP, startIndex);
         pushType(Type.OBJECT_ARRAY);
--- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Fri Apr 11 16:52:56 2014 +0200
@@ -26,8 +26,8 @@
 package jdk.nashorn.internal.codegen;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
+import java.util.List;
 
-import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
--- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Fri Apr 11 16:52:56 2014 +0200
@@ -28,9 +28,11 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
+
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.runtime.JSType;
@@ -75,6 +77,9 @@
             final String     key   = tuple.key;
             final Expression value = tuple.value;
 
+            //this is a nop of tuple.key isn't e.g. "apply" or another special name
+            method.invalidateSpecialName(tuple.key);
+
             if (value != null) {
                 final Object constantValue = LiteralNode.objectAsConstant(value);
                 if (constantValue == LiteralNode.POSTSET_MARKER) {
--- a/src/jdk/nashorn/internal/ir/Block.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/ir/Block.java	Fri Apr 11 16:52:56 2014 +0200
@@ -243,6 +243,11 @@
     }
 
     @Override
+    public int getFlags() {
+        return flags;
+    }
+
+    @Override
     public boolean isTerminal() {
         return getFlag(IS_TERMINAL);
     }
--- a/src/jdk/nashorn/internal/ir/CallNode.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/ir/CallNode.java	Fri Apr 11 16:52:56 2014 +0200
@@ -47,10 +47,13 @@
     private final List<Expression> args;
 
     /** Is this a "new" operation */
-    public static final int IS_NEW =     1 << 0;
+    private static final int IS_NEW =     1 << 0;
 
     /** Is the callsite type for this call optimistic rather than based on statically known coercion semantics */
-    public static final int OPTIMISTIC = 1 << 1;
+    private static final int IS_OPTIMISTIC = 1 << 1;
+
+    /** Can this be a Function.call? */
+    private static final int IS_APPLY_TO_CALL = 1 << 2;
 
     private final int flags;
 
@@ -188,7 +191,7 @@
     }
 
     @Override
-    public Optimistic setType(TemporarySymbols ts, Type optimisticType) {
+    public Optimistic setType(final TemporarySymbols ts, final Type optimisticType) {
         if (this.optimisticType == optimisticType) {
             return this;
         }
@@ -214,7 +217,7 @@
                                 setThis((IdentNode)evalArgs.getThis().accept(visitor))));
             // Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice,
             // setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now.
-            if(this != newCallNode) {
+            if (this != newCallNode) {
                 return Node.replaceInLexicalContext(lc, this, newCallNode);
             }
         }
@@ -225,7 +228,12 @@
     @Override
     public void toString(final StringBuilder sb) {
         Node.optimisticType(this, sb);
-        function.toString(sb);
+
+        final StringBuilder fsb = new StringBuilder();
+        function.toString(fsb);
+        if (isApplyToCall()) {
+            sb.append(fsb.toString().replace("apply", "[apply => call]"));
+        }
 
         sb.append('(');
 
@@ -255,8 +263,9 @@
     /**
      * Reset the arguments for the call
      * @param args new arguments list
+     * @return new callnode, or same if unchanged
      */
-    private CallNode setArgs(final List<Expression> args) {
+    public CallNode setArgs(final List<Expression> args) {
         if (this.args == args) {
             return this;
         }
@@ -294,6 +303,23 @@
     }
 
     /**
+     * Is this an apply call that we optimistically should try to turn into
+     * a call instead
+     * @return true if apply to call
+     */
+    public boolean isApplyToCall() {
+        return (flags & IS_APPLY_TO_CALL) != 0;
+    }
+
+    /**
+     * Flag this call node as one that tries to call call instead of apply
+     * @return new call node with changed flags, if not already flagged as apply to call, then the same node
+     */
+    public CallNode setIsApplyToCall() {
+        return setFlags(flags | IS_APPLY_TO_CALL);
+    }
+
+    /**
      * Return the function expression that this call invokes
      * @return the function
      */
@@ -318,7 +344,7 @@
      * @return true if this a new operation
      */
     public boolean isNew() {
-        return (flags & IS_NEW) == IS_NEW;
+        return (flags & IS_NEW) != 0;
     }
 
     /**
@@ -326,7 +352,7 @@
      * @return same node or new one on state change
      */
     public CallNode setIsNew() {
-        return setFlags(IS_NEW);
+        return setFlags(flags | IS_NEW);
     }
 
     private CallNode setFlags(final int flags) {
@@ -366,7 +392,7 @@
 
     @Override
     public boolean isOptimistic() {
-        return (flags & OPTIMISTIC) == OPTIMISTIC;
+        return (flags & IS_OPTIMISTIC) != 0;
     }
 
     @Override
@@ -374,6 +400,6 @@
         if (isOptimistic() == isOptimistic) {
             return this;
         }
-        return new CallNode(this, function, args, isOptimistic ? (flags | OPTIMISTIC) : (flags & ~OPTIMISTIC), optimisticType, evalArgs, programPoint);
+        return new CallNode(this, function, args, isOptimistic ? (flags | IS_OPTIMISTIC) : (flags & ~IS_OPTIMISTIC), optimisticType, evalArgs, programPoint);
     }
 }
--- a/src/jdk/nashorn/internal/ir/Flags.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/ir/Flags.java	Fri Apr 11 16:52:56 2014 +0200
@@ -37,6 +37,12 @@
 public interface Flags<T extends LexicalContextNode> {
 
     /**
+     * Get all flags of a LexicalContextNode
+     * @return flags
+     */
+    public int getFlags();
+
+    /**
      * Check if a flag is set in a lexical context node
      * @param flag flag to check
      * @return flags
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Fri Apr 11 16:52:56 2014 +0200
@@ -192,21 +192,24 @@
     /** Does this function have optimistic expressions? */
     public static final int IS_OPTIMISTIC               = 1 << 12;
 
+    /** Are we vararg, but do we just pass the arguments along to apply or call */
+    public static final int HAS_APPLY_TO_CALL_SPECIALIZATION = 1 << 13;
+
     /** Does this function explicitly use the {@link CompilerConstants#RETURN} symbol? Some functions are known to
      * always use the return symbol, namely a function that is a program (as it must track its last executed expression
      * statement's value) as well as functions that are split (to communicate return values from inner to outer
      * partitions). Other functions normally don't use the return symbol (so we optimize away its slot), except in some
      * very special cases, e.g. when containing a return statement in a finally block. These special cases set this
      * flag. */
-    public static final int USES_RETURN_SYMBOL = 1 << 13;
+    public static final int USES_RETURN_SYMBOL = 1 << 14;
 
     /**
      * Is this function the top-level program?
      */
-    public static final int IS_PROGRAM = 1 << 14;
+    public static final int IS_PROGRAM = 1 << 15;
 
     /** Does this function use the "this" keyword? */
-    public static final int USES_THIS                   = 1 << 15;
+    public static final int USES_THIS                   = 1 << 16;
 
     /** Does this function or any nested functions contain an eval? */
     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
@@ -477,6 +480,11 @@
     }
 
     @Override
+    public int getFlags() {
+        return flags;
+    }
+
+    @Override
     public boolean getFlag(final int flag) {
         return (flags & flag) != 0;
     }
@@ -509,7 +517,7 @@
 
     /**
      * Returns true if the function is optimistic
-     * @return True if this function is optimistic
+     * @return true if this function is optimistic
      */
     public boolean isOptimistic() {
         return getFlag(IS_OPTIMISTIC);
@@ -569,6 +577,15 @@
         return getFlag(USES_THIS);
     }
 
+
+    /**
+     * Return true if function contains an apply to call transform
+     * @return true if this function has transformed apply to call
+     */
+    public boolean hasOptimisticApplyToCall() {
+        return getFlag(HAS_APPLY_TO_CALL_SPECIALIZATION);
+    }
+
     /**
      * Get the identifier for this function, this is its symbol.
      * @return the identifier as an IdentityNode
--- a/src/jdk/nashorn/internal/objects/Global.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/objects/Global.java	Fri Apr 11 16:52:56 2014 +0200
@@ -25,22 +25,30 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
 import java.lang.reflect.Field;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.codegen.ApplySpecialization;
+import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Property;
@@ -75,6 +83,33 @@
     private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
     private final InvokeByName VALUE_OF  = new InvokeByName("valueOf",  ScriptObject.class);
 
+    /**
+     * Optimistic builtin names that require switchpoint invalidation
+     * upon assignment. Overly conservative, but works for now, to avoid
+     * any complicated scope checks and especially heavy weight guards
+     * like
+     *
+     * <pre>
+     * {@code
+     *     public boolean setterGuard(final Object receiver) {
+     *         final Global          global = Global.instance();
+     *         final ScriptObject    sobj   = global.getFunctionPrototype();
+     *         final Object          apply  = sobj.get("apply");
+     *         return apply == receiver;
+     *     }
+     *
+     * }
+     * </pre>
+     *
+     * Naturally, checking for builting classes like NativeFunction is cheaper,
+     * it's when you start adding property checks for said builtins you have
+     * problems with guard speed.
+     */
+    public final Map<String, SwitchPoint> optimisticFunctionMap;
+
+    /** Name invalidator for things like call/apply */
+    public static final Call BOOTSTRAP = staticCall(MethodHandles.lookup(), Global.class, "invalidateNameBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
+
     /** ECMA 15.1.2.2 parseInt (string , radix) */
     @Property(attributes = Attribute.NOT_ENUMERABLE)
     public Object parseInt;
@@ -379,12 +414,15 @@
     // Used to store the last RegExp result to support deprecated RegExp constructor properties
     private RegExpResult lastRegExpResult;
 
-    private static final MethodHandle EVAL              = findOwnMH("eval",              Object.class, Object.class, Object.class);
-    private static final MethodHandle PRINT             = findOwnMH("print",             Object.class, Object.class, Object[].class);
-    private static final MethodHandle PRINTLN           = findOwnMH("println",           Object.class, Object.class, Object[].class);
-    private static final MethodHandle LOAD              = findOwnMH("load",              Object.class, Object.class, Object.class);
-    private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH("loadWithNewGlobal", Object.class, Object.class, Object[].class);
-    private static final MethodHandle EXIT              = findOwnMH("exit",              Object.class, Object.class, Object.class);
+    private static final MethodHandle EVAL              = findOwnMH_S("eval",              Object.class, Object.class, Object.class);
+    private static final MethodHandle PRINT             = findOwnMH_S("print",             Object.class, Object.class, Object[].class);
+    private static final MethodHandle PRINTLN           = findOwnMH_S("println",           Object.class, Object.class, Object[].class);
+    private static final MethodHandle LOAD              = findOwnMH_S("load",              Object.class, Object.class, Object.class);
+    private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class);
+    private static final MethodHandle EXIT              = findOwnMH_S("exit",              Object.class, Object.class, Object.class);
+
+    /** Invalidate a reserved name, such as "apply" or "call" if assigned */
+    public MethodHandle INVALIDATE_RESERVED_NAME = MH.bindTo(findOwnMH_V("invalidateReservedName", void.class, String.class), this);
 
     // initialized by nasgen
     private static PropertyMap $nasgenmap$;
@@ -426,6 +464,7 @@
         super(checkAndGetMap(context));
         this.context = context;
         this.setIsScope();
+        this.optimisticFunctionMap = new HashMap<>();
         GlobalConstants.instance().invalidateAll();
     }
 
@@ -1886,7 +1925,7 @@
     // to play with object references carefully!!
     private void initFunctionAndObject() {
         // First-n-foremost is Function
-        this.builtinFunction = (ScriptFunction)initConstructor("Function");
+        this.builtinFunction      = (ScriptFunction)initConstructor("Function");
 
         // create global anonymous function
         final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction(this);
@@ -1946,7 +1985,15 @@
             }
         }
 
+        //make sure apply and call have the same invalidation switchpoint
+        final SwitchPoint sp = new SwitchPoint();
+        optimisticFunctionMap.put("apply", sp);
+        optimisticFunctionMap.put("call", sp);
+        getFunctionPrototype().getProperty("apply").setChangeCallback(sp);
+        getFunctionPrototype().getProperty("call").setChangeCallback(sp);
+
         properties = getObjectPrototype().getMap().getProperties();
+
         for (final jdk.nashorn.internal.runtime.Property property : properties) {
             final Object key   = property.getKey();
             final Object value = ObjectPrototype.get(key);
@@ -1965,7 +2012,11 @@
         }
     }
 
-    private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
+    private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
+        return MH.findVirtual(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
+    }
+
+    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findStatic(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
     }
 
@@ -1982,4 +2033,59 @@
         return true;
     }
 
+    /**
+     * Check if there is a switchpoint for a reserved name. If there
+     * is, it must be invalidated upon properties with this name
+     * @param name property name
+     * @return switchpoint for invalidating this property, or null if not registered
+     */
+    public SwitchPoint getChangeCallback(final String name) {
+        return optimisticFunctionMap.get(name);
+    }
+
+    /**
+     * Is this a special name, that might be subject to invalidation
+     * on write, such as "apply" or "call"
+     * @param name name to check
+     * @return true if special name
+     */
+    public boolean isSpecialName(final String name) {
+        return getChangeCallback(name) != null;
+    }
+
+    /**
+     * Check if a reserved property name is invalidated
+     * @param name property name
+     * @return true if someone has written to it since Global was instantiated
+     */
+    public boolean isSpecialNameValid(final String name) {
+        final SwitchPoint sp = getChangeCallback(name);
+        return sp != null && !sp.hasBeenInvalidated();
+    }
+
+    /**
+     * Tag a reserved name as invalidated - used when someone writes
+     * to a property with this name - overly conservative, but link time
+     * is too late to apply e.g. apply->call specialization
+     * @param name property name
+     */
+    public void invalidateReservedName(final String name) {
+        final SwitchPoint sp = getChangeCallback(name);
+        if (sp != null) {
+            ApplySpecialization.getLogger().info("Overwrote special name '" + name +"' - invalidating switchpoint");
+            SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+        }
+    }
+
+    /**
+     * Bootstrapper for invalidating a builtin name
+     * @param lookup lookup
+     * @param name   name to invalidate
+     * @param type   methodhandle type
+     * @return callsite for invalidator
+     */
+    public static CallSite invalidateNameBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type) {
+        final MethodHandle target = MH.insertArguments(Global.instance().INVALIDATE_RESERVED_NAME, 0, name);
+        return new ConstantCallSite(target);
+    }
 }
--- a/src/jdk/nashorn/internal/objects/NativeFunction.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/objects/NativeFunction.java	Fri Apr 11 16:52:56 2014 +0200
@@ -97,7 +97,7 @@
     public static Object apply(final Object self, final Object thiz, final Object array) {
         checkCallable(self);
 
-        Object[] args = toApplyArgs(array);
+        final Object[] args = toApplyArgs(array);
 
         if (self instanceof ScriptFunction) {
             return ScriptRuntime.apply((ScriptFunction)self, thiz, args);
@@ -177,7 +177,7 @@
     public static Object call(final Object self, final Object... args) {
         checkCallable(self);
 
-        Object thiz = (args.length == 0) ? UNDEFINED : args[0];
+        final Object thiz = (args.length == 0) ? UNDEFINED : args[0];
         Object[] arguments;
 
         if (args.length > 1) {
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Apr 11 16:52:56 2014 +0200
@@ -578,7 +578,7 @@
     }
 
     @Override
-    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
+    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         return findHook(desc, __new__, false);
     }
 
--- a/src/jdk/nashorn/internal/objects/NativeObject.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/objects/NativeObject.java	Fri Apr 11 16:52:56 2014 +0200
@@ -765,7 +765,7 @@
         } catch(final Throwable t) {
             throw new RuntimeException(t);
         }
-        assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints.
+        assert inv.getSwitchPoints() == null; // Linkers in Dynalink's beans package don't use switchpoints.
         // We discard the guard, as all method handles will be bound to a specific object.
         return inv.getInvocation();
     }
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Fri Apr 11 16:52:56 2014 +0200
@@ -30,6 +30,7 @@
 
 import java.lang.invoke.MethodHandle;
 import java.util.ArrayList;
+
 import jdk.nashorn.internal.runtime.AccessorProperty;
 import jdk.nashorn.internal.runtime.GlobalFunctions;
 import jdk.nashorn.internal.runtime.Property;
@@ -226,7 +227,7 @@
      * @return a function with the specified self and parameters bound.
      */
     @Override
-    protected ScriptFunction makeBoundFunction(Object self, Object[] args) {
+    protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
         return super.makeBoundFunction(self, args);
     }
 
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Fri Apr 11 16:52:56 2014 +0200
@@ -41,12 +41,14 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.SwitchPoint;
 import java.util.logging.Level;
 
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.objects.Global;
 
 /**
  * An AccessorProperty is the most generic property type. An AccessorProperty is
@@ -60,6 +62,8 @@
 
     private static final DebugLogger LOG = ObjectClassGenerator.getLogger();
 
+    private static final MethodHandle INVALIDATE_SP  = findOwnMH("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class, String.class);
+
     /**
      * Properties in different maps for the same structure class will share their field getters and setters. This could
      * be further extended to other method handles that are looked up in the AccessorProperty constructor, but right now
@@ -168,7 +172,6 @@
         this.primitiveSetter = bindTo(property.primitiveSetter, delegate);
         this.objectGetter    = bindTo(property.objectGetter, delegate);
         this.objectSetter    = bindTo(property.objectSetter, delegate);
-
         property.GETTER_CACHE = new MethodHandle[NOOF_TYPES];
         // Properties created this way are bound to a delegate
         setCurrentType(property.getCurrentType());
@@ -601,6 +604,13 @@
         return sobj;
     }
 
+    @SuppressWarnings("unused")
+    private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp, final String key) {
+        LOG.info("Field change callback for " + key + " triggered: " + sp);
+        SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+        return obj;
+    }
+
     private MethodHandle generateSetter(final Class<?> forType, final Class<?> type) {
         MethodHandle mh = createSetter(forType, type, primitiveSetter, objectSetter);
         mh = debug(mh, getCurrentType(), type, "set");
@@ -637,11 +647,40 @@
             mh = generateSetter(forType, type);
         }
 
+        /**
+         * Check if this is a special global name that requires switchpoint invalidation
+         */
+        final SwitchPoint ccb = getChangeCallback();
+        if (ccb != null && ccb != NO_CHANGE_CALLBACK) {
+            mh = MH.filterArguments(mh, 0, MH.insertArguments(INVALIDATE_SP, 1, changeCallback, getKey()));
+        }
+
         assert mh.type().returnType() == void.class;
 
         return mh;
     }
 
+    private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
+
+    /**
+     * Get the change callback for this property
+     * @return switchpoint that is invalidated when property changes
+     */
+    protected SwitchPoint getChangeCallback() {
+        if (changeCallback == null) {
+            try {
+                changeCallback = Global.instance().getChangeCallback(getKey());
+            } catch (final NullPointerException e) {
+                assert !"apply".equals(getKey()) && !"call".equals(getKey());
+                //empty
+            }
+            if (changeCallback == null) {
+                changeCallback = NO_CHANGE_CALLBACK;
+            }
+        }
+        return changeCallback;
+    }
+
     @Override
     public final boolean canChangeType() {
         if (OBJECT_FIELDS_ONLY) {
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Fri Apr 11 16:52:56 2014 +0200
@@ -72,6 +72,7 @@
     private MethodHandle invoker;
     private MethodHandle constructor;
     private OptimismInfo optimismInfo;
+    private int flags; // from FunctionNode
 
     CompiledFunction(final MethodHandle invoker) {
         this.invoker = invoker;
@@ -87,15 +88,24 @@
         this.constructor = constructor;
     }
 
-    CompiledFunction(final MethodHandle invoker, final RecompilableScriptFunctionData functionData, final boolean isOptimistic) {
+    CompiledFunction(final MethodHandle invoker, final RecompilableScriptFunctionData functionData, final int flags) {
         this(invoker);
-        if(isOptimistic) {
+        this.flags = flags;
+        if ((flags & FunctionNode.IS_OPTIMISTIC) != 0) {
             optimismInfo = new OptimismInfo(functionData);
         } else {
             optimismInfo = null;
         }
     }
 
+    int getFlags() {
+        return flags;
+    }
+
+    boolean isVarArg() {
+        return isVarArgsType(invoker.type());
+    }
+
     @Override
     public String toString() {
         return "<callSiteType=" + invoker.type() + " invoker=" + invoker + " ctor=" + constructor + " weight=" + weight() + ">";
@@ -127,13 +137,17 @@
      * @return a direct constructor method handle for this function.
      */
     MethodHandle getConstructor() {
-        if(constructor == null) {
+        if (constructor == null) {
             constructor = createConstructorFromInvoker(createInvokerForPessimisticCaller());
         }
 
         return constructor;
     }
 
+    MethodHandle getInvoker() {
+        return invoker;
+    }
+
     /**
      * Creates a version of the invoker intended for a pessimistic caller (return type is Object, no caller optimistic
      * program point available).
@@ -248,7 +262,7 @@
         return weight;
     }
 
-    private static boolean isVarArgsType(final MethodType type) {
+    static boolean isVarArgsType(final MethodType type) {
         assert type.parameterCount() >= 1 : type;
         return type.parameterType(type.parameterCount() - 1) == Object[].class;
     }
@@ -405,20 +419,20 @@
             return paramTypes[i];
         }
         assert isVarArg;
-        return ((ArrayType)(paramTypes[paramTypes.length - 1])).getElementType();
+        return ((ArrayType)paramTypes[paramTypes.length - 1]).getElementType();
     }
 
-    boolean matchesCallSite(final MethodType callSiteType) {
-        if(!ScriptEnvironment.globalOptimistic()) {
+    boolean matchesCallSite(final MethodType callSiteType, final boolean pickVarArg) {
+        if (!ScriptEnvironment.globalOptimistic()) {
             // Without optimistic recompilation, always choose the first eagerly compiled version.
             return true;
         }
 
-        final MethodType type = type();
+        final MethodType type  = type();
         final int fnParamCount = getParamCount(type);
         final boolean isVarArg = fnParamCount == Integer.MAX_VALUE;
-        if(isVarArg) {
-            return true;
+        if (isVarArg) {
+            return pickVarArg;
         }
 
         final int csParamCount = getParamCount(callSiteType);
@@ -618,7 +632,7 @@
             final Type previousFailedType = invalidatedProgramPoints.put(e.getProgramPoint(), retType);
             if (previousFailedType != null && !previousFailedType.narrowerThan(retType)) {
                 final StackTraceElement[] stack = e.getStackTrace();
-                final String functionId = stack.length == 0 ? data.getName() : (stack[0].getClassName() + "." + stack[0].getMethodName());
+                final String functionId = stack.length == 0 ? data.getName() : stack[0].getClassName() + "." + stack[0].getMethodName();
                 LOG.info("RewriteException for an already invalidated program point ", e.getProgramPoint(), " in ", functionId, ". This is okay for a recursive function invocation, but a bug otherwise.");
                 return null;
             }
--- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java	Fri Apr 11 16:52:56 2014 +0200
@@ -40,11 +40,11 @@
         this.name = name;
     }
 
-    void add(CompiledFunction f) {
+    void add(final CompiledFunction f) {
         functions.add(f);
     }
 
-    void addAll(CompiledFunctions fs) {
+    void addAll(final CompiledFunctions fs) {
         functions.addAll(fs.functions);
     }
 
@@ -61,6 +61,15 @@
         return '\'' + name + "' code=" + functions;
     }
 
+    private CompiledFunction pick(final MethodType callSiteType, final boolean canPickVarArg) {
+        for (final CompiledFunction candidate : functions) {
+            if (candidate.matchesCallSite(callSiteType, false)) {
+                return candidate;
+            }
+        }
+        return null;
+    }
+
     /**
      * Returns the compiled function best matching the requested call site method type
      * @param callSiteType
@@ -73,12 +82,11 @@
         assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
 
         if (recompilable) {
-            for (final CompiledFunction candidate: functions) {
-                if(candidate.matchesCallSite(callSiteType)) {
-                    return candidate;
-                }
+            final CompiledFunction candidate = pick(callSiteType, false);
+            if (candidate != null) {
+                return candidate;
             }
-            return null;
+            return pick(callSiteType, true); //try vararg last
         }
 
         CompiledFunction best = null;
@@ -98,7 +106,7 @@
      * @return true if the functions need a callee, false otherwise.
      */
     boolean needsCallee() {
-        boolean needsCallee = functions.getFirst().needsCallee();
+        final boolean needsCallee = functions.getFirst().needsCallee();
         assert allNeedCallee(needsCallee);
         return needsCallee;
     }
--- a/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Fri Apr 11 16:52:56 2014 +0200
@@ -32,6 +32,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.SwitchPoint;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.logging.Level;
@@ -333,7 +334,7 @@
         final MethodHandle invalidator  = MH.asType(INVALIDATE_SP, INVALIDATE_SP.type().changeParameterType(0, receiverType).changeReturnType(receiverType));
         final MethodHandle mh           = MH.filterArguments(inv.getInvocation(), 0, MH.insertArguments(invalidator, 1, acc));
 
-        assert inv.getSwitchPoint() == null : inv.getSwitchPoint();
+        assert inv.getSwitchPoints() == null : Arrays.asList(inv.getSwitchPoints());
         LOG.info("Linked setter " + quote(name) + " " + acc.getSwitchPoint());
         return new GuardedInvocation(mh, inv.getGuard(), acc.getSwitchPoint(), inv.getException());
     }
--- a/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Fri Apr 11 16:52:56 2014 +0200
@@ -137,12 +137,12 @@
     }
 
     @Override
-    protected GuardedInvocation findNewMethod(CallSiteDescriptor desc) {
+    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         return createClassNotFoundInvocation(desc);
     }
 
     @Override
-    protected GuardedInvocation findCallMethod(CallSiteDescriptor desc, LinkRequest request) {
+    protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         return createClassNotFoundInvocation(desc);
     }
 
--- a/src/jdk/nashorn/internal/runtime/Property.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/Property.java	Fri Apr 11 16:52:56 2014 +0200
@@ -30,7 +30,9 @@
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
 
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.SwitchPoint;
 import java.util.Objects;
+
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 
 /**
@@ -98,6 +100,8 @@
     /** Property field number or spill slot. */
     private final int slot;
 
+    protected SwitchPoint changeCallback;
+
     /**
      * Constructor
      *
@@ -118,9 +122,10 @@
      * @param property source property
      */
     Property(final Property property, final int flags) {
-        this.key   = property.key;
-        this.slot  = property.slot;
-        this.flags = flags;
+        this.key            = property.key;
+        this.slot           = property.slot;
+        this.changeCallback = property.changeCallback;
+        this.flags          = flags;
     }
 
     /**
@@ -168,6 +173,10 @@
         return propFlags;
     }
 
+    public final void setChangeCallback(final SwitchPoint sp) {
+        this.changeCallback = sp;
+    }
+
     /**
      * Property flag utility method for {@link PropertyDescriptor}. Get the property flags
      * conforming to any Property using this PropertyDescriptor
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Apr 11 16:52:56 2014 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.nashorn.internal.codegen.CompilationEnvironment;
 import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases;
+import jdk.nashorn.internal.codegen.ApplySpecialization;
 import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -238,7 +239,7 @@
     public String toStringVerbose() {
         final StringBuilder sb = new StringBuilder();
 
-        sb.append("fid=").append(functionNodeId).append(' ');
+        sb.append("fnId=").append(functionNodeId).append(' ');
 
         if (source != null) {
             sb.append(source.getName())
@@ -250,6 +251,11 @@
         return sb.toString() + super.toString();
     }
 
+    @Override
+    public String getFunctionName() {
+        return functionName;
+    }
+
     private static String functionName(final FunctionNode fn) {
         if (fn.isAnonymous()) {
             return "";
@@ -323,7 +329,7 @@
             functionNodeId - (isProgram ? 0 : 1),
             lineNumber - 1); // source starts at line 0, so even though lineNumber is the correct declaration line, back off one to make it exclusive
 
-        if(isAnonymous) {
+        if (isAnonymous) {
             parser.setFunctionName(functionName);
         }
         final FunctionNode program = parser.parse(scriptName, descPosition, Token.descLength(token), true);
@@ -367,13 +373,19 @@
         final String scriptName = RECOMPILATION_PREFIX + RECOMPILE_ID.incrementAndGet() + "$restOf";
         FunctionNode fn = reparse(scriptName);
 
+        final ApplyToCallTransform tr = new ApplyToCallTransform(fn, fnCallSiteType, true);
+        fn = tr.transform();
+        final int newArity = tr.arity;
+
         final Compiler compiler = new Compiler(
                 new CompilationEnvironment(
                     CompilationPhases.EAGER.makeOptimistic(),
                     isStrict(),
                     this,
                     runtimeScope,
-                    isVariableArity() ? null : new ParamTypeMap(functionNodeId, explicitParams(fnCallSiteType)),
+                    isVariableArity() && !tr.transformed ?
+                            null :
+                            new ParamTypeMap(functionNodeId, explicitParams(fnCallSiteType, newArity)),
                     invalidatedProgramPoints,
                     continuationEntryPoints,
                     true
@@ -381,11 +393,11 @@
                 installer);
 
         fn = compiler.compile(scriptName, fn);
-
         compiler.install(fn);
 
         // look up the rest of method
-        return lookupWithExplicitType(fn, MethodType.methodType(fn.getReturnType().getTypeClass(), RewriteException.class));
+        final MethodHandle mh = lookupWithExplicitType(fn, MethodType.methodType(fn.getReturnType().getTypeClass(), RewriteException.class));
+        return mh;
     }
 
     private FunctionNode compileTypeSpecialization(final MethodType actualCallSiteType, final ScriptObject runtimeScope) {
@@ -399,8 +411,13 @@
         if (LOG.isEnabled()) {
             LOG.info(reason, " of '", functionName, "' signature: ", fnCallSiteType, " ", stringifyInvalidations(invalidatedProgramPoints));
         }
+
         FunctionNode fn = reparse(scriptName);
 
+        final ApplyToCallTransform tr = new ApplyToCallTransform(fn, actualCallSiteType, false);
+        fn = tr.transform();
+        final int newArity = tr.arity;
+
         final CompilationPhases phases = CompilationPhases.EAGER;
         final Compiler compiler = new Compiler(
             new CompilationEnvironment(
@@ -408,11 +425,11 @@
                 isStrict(),
                 this,
                 runtimeScope,
-                fnCallSiteType == null || isVariableArity() ?
+                fnCallSiteType == null || isVariableArity() && !tr.transformed ?
                     null :
                     new ParamTypeMap(
                         functionNodeId,
-                        explicitParams(fnCallSiteType)),
+                        explicitParams(fnCallSiteType, newArity)),
                 invalidatedProgramPoints,
                 true),
             installer);
@@ -424,10 +441,7 @@
         return fn;
     }
 
-    private MethodType explicitParams(final MethodType callSiteType) {
-        assert !isVariableArity(); // Should not be invoked for varargs
-        final int arity = getArity();
-
+    private static MethodType explicitParams(final MethodType callSiteType, final int arity) {
         final MethodType noCalleeThisType = callSiteType.dropParameterTypes(0, 2); // (callee, this) is always in call site type
         final int callSiteParamCount = noCalleeThisType.parameterCount();
 
@@ -436,9 +450,9 @@
         final int minParams = Math.min(callSiteParamCount, arity);
         final Class<?>[] paramTypes = noCalleeThisType.parameterArray();
         boolean changed = false;
-        for(int i = 0; i < minParams; ++i) {
+        for (int i = 0; i < minParams; ++i) {
             final Class<?> paramType = paramTypes[i];
-            if(!(paramType.isPrimitive() || paramType == Object.class)) {
+            if (!(paramType.isPrimitive() || paramType == Object.class)) {
                 paramTypes[i] = Object.class;
                 changed = true;
             }
@@ -446,9 +460,9 @@
         final MethodType generalized = changed ? MethodType.methodType(noCalleeThisType.returnType(), paramTypes) : noCalleeThisType;
 
         // Match arity
-        if(callSiteParamCount < arity) {
+        if (callSiteParamCount < arity) {
             return generalized.appendParameterTypes(Collections.<Class<?>>nCopies(arity - callSiteParamCount, Object.class));
-        } else if(callSiteParamCount > arity) {
+        } else if (callSiteParamCount > arity) {
             return generalized.dropParameterTypes(arity, callSiteParamCount);
         } else {
             return generalized;
@@ -467,7 +481,7 @@
         assert fns.size() == 1 : "got back more than one method in recompilation";
         final FunctionNode f = fns.iterator().next();
         assert f.getId() == functionNodeId;
-        if(!isDeclared && f.isDeclared()) {
+        if (!isDeclared && f.isDeclared()) {
             return f.clearFlag(null, FunctionNode.IS_DECLARED);
         }
         return f;
@@ -499,14 +513,14 @@
         addCode(functionNode);
     }
 
-    private CompiledFunction addCode(final MethodHandle target, final boolean isOptimistic) {
-        final CompiledFunction cfn = new CompiledFunction(target, this, isOptimistic);
+    private CompiledFunction addCode(final MethodHandle target, final int fnFlags) {
+        final CompiledFunction cfn = new CompiledFunction(target, this, fnFlags);
         code.add(cfn);
         return cfn;
     }
 
     private CompiledFunction addCode(final FunctionNode fn) {
-        return addCode(lookup(fn), fn.isOptimistic());
+        return addCode(lookup(fn), fn.getFlags());
     }
 
     /**
@@ -520,7 +534,7 @@
      * @return the compiled function object, with its type matching that of the call site type.
      */
     private CompiledFunction addCode(final FunctionNode fn, final MethodType callSiteType) {
-        if(fn.isVarArg()) {
+        if (fn.isVarArg()) {
             return addCode(fn);
         }
 
@@ -549,15 +563,31 @@
             toType = toType.dropParameterTypes(fromCount, toCount);
         }
 
-        return addCode(lookup(fn).asType(toType), fn.isOptimistic());
+        return addCode(lookup(fn).asType(toType), fn.getFlags());
     }
 
     @Override
     CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
         synchronized (code) {
             final CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope);
-            // TODO: what if callSiteType is vararg?
-            return existingBest != null ? existingBest : addCode(compileTypeSpecialization(callSiteType, runtimeScope), callSiteType);
+            if (existingBest != null) {
+                /*
+                 * If callsite type isn't vararg and our best is vararg, generate a specialization
+                 * we DO have a generic version, which means that we know which ones of the applies
+                 * were actual applies
+                 */
+                if (existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType)) {
+                    //System.err.println("Looking in code for best " + callSiteType + " " + existingBest + " code=" + code);
+                    final FunctionNode fn = compileTypeSpecialization(callSiteType, runtimeScope);
+                    if (fn.hasOptimisticApplyToCall()) { //did the specialization work
+                        final CompiledFunction cf = addCode(fn, callSiteType);
+                        assert !cf.isVarArg();
+                        return cf;
+                    }
+                }
+                return existingBest;
+            }
+            return addCode(compileTypeSpecialization(callSiteType, runtimeScope), callSiteType);
         }
     }
 
@@ -567,7 +597,7 @@
     }
 
     @Override
-    boolean needsCallee() {
+    public boolean needsCallee() {
         return needsCallee;
     }
 
@@ -606,4 +636,73 @@
         }
         return null;
     }
+
+    /**
+     * Get the uppermost parent, the program, for this data
+     * @return program
+     */
+    public RecompilableScriptFunctionData getProgram() {
+        RecompilableScriptFunctionData program = this;
+        while (true) {
+            final RecompilableScriptFunctionData p = program.getParent();
+            if (p == null) {
+                return program;
+            }
+            program = p;
+        }
+    }
+
+    /**
+     * Check whether a certain name is a global symbol, i.e. only exists as defined
+     * in outermost scope and not shadowed by being parameter or assignment in inner
+     * scopes
+     *
+     * @param functionNode function node to check
+     * @param symbolName symbol name
+     * @return true if global symbol
+     */
+    public boolean isGlobalSymbol(final FunctionNode functionNode, final String symbolName) {
+        RecompilableScriptFunctionData data = getScriptFunctionData(functionNode.getId());
+        assert data != null;
+        final RecompilableScriptFunctionData program = getProgram();
+
+        while (data != program) {
+            if (data.hasInternalSymbol(symbolName)) {
+                return false;
+            }
+            data = data.getParent();
+        }
+
+        return true;
+    }
+
+    /**
+     * Helper class for transforming apply calls to calls
+     */
+    private class ApplyToCallTransform {
+        private final MethodType actualCallSiteType;
+        private final boolean isRestOf;
+        private int arity;
+        private FunctionNode functionNode;
+        private boolean transformed;
+
+        ApplyToCallTransform(final FunctionNode functionNode, final MethodType actualCallSiteType, final boolean isRestOf) {
+            this.functionNode = functionNode;
+            this.actualCallSiteType = actualCallSiteType;
+            this.arity = getArity();
+            this.isRestOf = isRestOf;
+        }
+
+        FunctionNode transform() {
+            if (isVariableArity()) {
+                final ApplySpecialization spec = new ApplySpecialization(RecompilableScriptFunctionData.this, functionNode, actualCallSiteType, isRestOf);
+                if (spec.transform()) {
+                    functionNode = spec.getFunctionNode();
+                    arity = functionNode.getParameters().size();
+                    transformed = true;
+                }
+            }
+            return functionNode;
+        }
+    }
 }
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri Apr 11 16:52:56 2014 +0200
@@ -294,9 +294,6 @@
             if (kv.hasValue("objects")) {
                 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
             }
-            if (kv.hasValue("scope")) {
-                callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_TRACE_SCOPE;
-            }
         }
         this._callsite_flags = callSiteFlags;
 
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Apr 11 16:52:56 2014 +0200
@@ -34,11 +34,14 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.support.Guards;
+import jdk.nashorn.internal.codegen.ApplySpecialization;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.objects.NativeFunction;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -324,17 +327,6 @@
    public abstract ScriptFunction makeSynchronizedFunction(Object sync);
 
     /**
-     * Return the most appropriate invocation for the specified call site type. If specializations are possible, it will
-     * strive to return an efficient specialization.
-     * @param callSiteType the call site type; can be as specific as needed.
-     * @return a guarded invocation with invoke method handle and potentially a switch point guarding optimistic
-     * assumptions.
-     */
-    private GuardedInvocation getBestInvoker(final MethodType callSiteType, final int callerProgramPoint) {
-        return data.getBestInvoker(callSiteType, callerProgramPoint, scope);
-    }
-
-    /**
      * Return the invoke handle bound to a given ScriptObject self reference.
      * If callee parameter is required result is rebound to this.
      *
@@ -468,12 +460,13 @@
     }
 
     @Override
-    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
+    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final MethodType type = desc.getMethodType();
         assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
-        final GuardedInvocation bestCtorInv = data.getBestConstructor(type, scope);
+        final CompiledFunction cf = data.getBestConstructor(type, scope);
+        final GuardedInvocation bestCtorInv = new GuardedInvocation(cf.getConstructor(), cf.getOptimisticAssumptionsSwitchPoint());
         //TODO - ClassCastException
-        return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this), bestCtorInv.getSwitchPoint());
+        return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
     }
 
     @SuppressWarnings("unused")
@@ -512,6 +505,7 @@
         final String  name       = getName();
         final boolean isUnstable = request.isCallSiteUnstable();
         final boolean scopeCall  = NashornCallSiteDescriptor.isScope(desc);
+
         final boolean isCall     = !scopeCall && data.isBuiltin() && "call".equals(name);
         final boolean isApply    = !scopeCall && data.isBuiltin() && "apply".equals(name);
 
@@ -519,7 +513,7 @@
             //megamorphic - replace call with apply
             final MethodHandle handle;
             //ensure that the callsite is vararg so apply can consume it
-            if(type.parameterCount() == 3 && type.parameterType(2) == Object[].class) {
+            if (type.parameterCount() == 3 && type.parameterType(2) == Object[].class) {
                 // Vararg call site
                 handle = ScriptRuntime.APPLY.methodHandle();
             } else {
@@ -532,7 +526,7 @@
             return new GuardedInvocation(
                     handle,
                     null,
-                    null,
+                    (SwitchPoint)null,
                     ClassCastException.class);
         }
 
@@ -548,7 +542,12 @@
         } //else just fall through and link as ordinary function or unstable apply
 
         final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
-        final GuardedInvocation bestInvoker = getBestInvoker(type, programPoint);
+        final CompiledFunction cf = data.getBestInvoker(type, programPoint, scope);
+        final GuardedInvocation bestInvoker =
+                new GuardedInvocation(
+                        cf.createInvoker(type.returnType(), programPoint),
+                        cf.getOptimisticAssumptionsSwitchPoint());
+
         final MethodHandle callHandle = bestInvoker.getInvocation();
 
         if (data.needsCallee()) {
@@ -587,65 +586,90 @@
 
         boundHandle = pairArguments(boundHandle, type);
 
-        return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard, bestInvoker.getSwitchPoint());
+        return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this, cf.getFlags()) : guard, bestInvoker.getSwitchPoints(), null);
     }
 
     private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
         final MethodType descType = desc.getMethodType();
         final int paramCount = descType.parameterCount();
+
         final boolean passesThis = paramCount > 2;
         final boolean passesArgs = paramCount > 3;
+        final int realArgCount = passesArgs ? paramCount - 3 : 0;
 
         final Object appliedFn = args[1];
         final boolean appliedFnNeedsWrappedThis = needsWrappedThis(appliedFn);
 
+        //box call back to apply
+        CallSiteDescriptor appliedDesc = desc;
+        final SwitchPoint applyToCallSwitchPoint = Global.instance().getChangeCallback("apply");
+        //enough to change the proto switchPoint here
+
+        final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
+        final boolean isFailedApplyToCall = isApplyToCall && applyToCallSwitchPoint.hasBeenInvalidated();
+
         // R(apply|call, ...) => R(...)
         MethodType appliedType = descType.dropParameterTypes(0, 1);
-        if(!passesThis) {
+        if (!passesThis) {
             // R() => R(this)
             appliedType = appliedType.insertParameterTypes(1, Object.class);
-        } else if(appliedFnNeedsWrappedThis) {
+        } else if (appliedFnNeedsWrappedThis) {
             appliedType = appliedType.changeParameterType(1, Object.class);
         }
-        if(isApply) {
-            if(passesArgs) {
+
+        if (isApply || isFailedApplyToCall) {
+            if (passesArgs) {
                 // R(this, args) => R(this, Object[])
                 appliedType = appliedType.changeParameterType(2, Object[].class);
+                // drop any extraneous arguments for the apply fail case
+                if (isFailedApplyToCall) {
+                    appliedType = appliedType.dropParameterTypes(3, paramCount - 1);
+                }
             } else {
                 // R(this) => R(this, Object[])
                 appliedType = appliedType.insertParameterTypes(2, Object[].class);
             }
         }
-        final CallSiteDescriptor appliedDesc = desc.changeMethodType(appliedType);
+
+        appliedDesc = appliedDesc.changeMethodType(appliedType);
 
         // Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
         final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
         appliedArgs[0] = appliedFn;
         appliedArgs[1] = passesThis ? appliedFnNeedsWrappedThis ? ScriptFunctionData.wrapThis(args[2]) : args[2] : ScriptRuntime.UNDEFINED;
-        if(isApply) {
+        if (isApply && !isFailedApplyToCall) {
             appliedArgs[2] = passesArgs ? NativeFunction.toApplyArgs(args[3]) : ScriptRuntime.EMPTY_ARRAY;
         } else {
-            if(passesArgs) {
-                System.arraycopy(args, 3, appliedArgs, 2, args.length - 3);
+            if (passesArgs) {
+                if (isFailedApplyToCall) {
+                    final Object[] tmp = new Object[args.length - 3];
+                    System.arraycopy(args, 3, tmp, 0, tmp.length);
+                    appliedArgs[2] = NativeFunction.toApplyArgs(tmp);
+                } else {
+                    System.arraycopy(args, 3, appliedArgs, 2, args.length - 3);
+                }
+            } else if (isFailedApplyToCall) {
+                appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
             }
         }
 
         // Ask the linker machinery for an invocation of the target function
         final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
-        final GuardedInvocation appliedInvocation;
+        GuardedInvocation appliedInvocation;
         try {
             appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
-        } catch(final RuntimeException | Error e) {
+        } catch (final RuntimeException | Error e) {
             throw e;
-        } catch(final Exception e) {
+        } catch (final Exception e) {
             throw new RuntimeException(e);
         }
         assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
 
         final Class<?> applyFnType = descType.parameterType(0);
         MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation
-        if(isApply) {
-            if(passesArgs) {
+
+        if (isApply && !isFailedApplyToCall) {
+            if (passesArgs) {
                 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
                 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
             } else {
@@ -653,17 +677,29 @@
                 inv = MH.insertArguments(inv, 2, (Object)ScriptRuntime.EMPTY_ARRAY);
             }
         }
-        if(!passesThis) {
+
+        if (isApplyToCall) {
+            if (isFailedApplyToCall) {
+                //take the real arguments that were passed to a call and force them into the apply instead
+                ApplySpecialization.getLogger().info("Collection arguments to revert call to apply in " + appliedFn);
+                inv = MH.asCollector(inv, Object[].class, realArgCount);
+            } else {
+                appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
+            }
+        }
+
+        if (!passesThis) {
             // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
             inv = bindImplicitThis(appliedFn, inv);
-        } else if(appliedFnNeedsWrappedThis) {
+        } else if (appliedFnNeedsWrappedThis) {
             // target function needs a wrapped this, so make sure we filter for that
             inv = MH.filterArguments(inv, 1, WRAP_THIS);
         }
         inv = MH.dropArguments(inv, 0, applyFnType);
+
         MethodHandle guard = appliedInvocation.getGuard();
         // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one
-        if(!passesThis && guard.type().parameterCount() > 1) {
+        if (!passesThis && guard.type().parameterCount() > 1) {
             guard = bindImplicitThis(appliedFn, guard);
         }
         final MethodType guardType = guard.type();
@@ -725,11 +761,14 @@
      *
      * @return method handle for guard
      */
-    private static MethodHandle getFunctionGuard(final ScriptFunction function) {
+    private static MethodHandle getFunctionGuard(final ScriptFunction function, final int flags) {
         assert function.data != null;
         // Built-in functions have a 1-1 correspondence to their ScriptFunctionData, so we can use a cheaper identity
         // comparison for them.
-        return function.data.isBuiltin() ? Guards.getIdentityGuard(function) : MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
+        if (function.data.isBuiltin()) {
+            return Guards.getIdentityGuard(function);
+        }
+        return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Fri Apr 11 16:52:56 2014 +0200
@@ -37,7 +37,7 @@
 import java.util.Collections;
 import java.util.Map;
 import java.util.WeakHashMap;
-import jdk.internal.dynalink.linker.GuardedInvocation;
+
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
 
 /**
@@ -144,6 +144,15 @@
         return (flags & IS_STRICT) != 0;
     }
 
+    /**
+     * Return the complete internal function name for this
+     * data, not anonymous or similar. May be identical
+     * @return internal function name
+     */
+    protected String getFunctionName() {
+        return getName();
+    }
+
     boolean isBuiltin() {
         return (flags & IS_BUILTIN) != 0;
     }
@@ -210,19 +219,19 @@
      * @return guarded invocation with method handle to best invoker and potentially a switch point guarding optimistic
      * assumptions.
      */
-     final GuardedInvocation getBestInvoker(final MethodType callSiteType, final int callerProgramPoint, final ScriptObject runtimeScope) {
+     final CompiledFunction getBestInvoker(final MethodType callSiteType, final int callerProgramPoint, final ScriptObject runtimeScope) {
         final CompiledFunction cf = getBest(callSiteType, runtimeScope);
         assert cf != null;
-        return new GuardedInvocation(cf.createInvoker(callSiteType.returnType(), callerProgramPoint), cf.getOptimisticAssumptionsSwitchPoint());
+        return cf;
     }
 
-    final GuardedInvocation getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope) {
+    final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope) {
         if (!isConstructor()) {
             throw typeError("not.a.constructor", toSource());
         }
         // Constructor call sites don't have a "this", but getBest is meant to operate on "callee, this, ..." style
         final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope);
-        return new GuardedInvocation(cf.getConstructor(), cf.getOptimisticAssumptionsSwitchPoint());
+        return cf;
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Apr 11 16:52:56 2014 +0200
@@ -1766,7 +1766,7 @@
         case "call":
             return findCallMethod(desc, request);
         case "new":
-            return findNewMethod(desc);
+            return findNewMethod(desc, request);
         case "callMethod":
             return findCallMethodMethod(desc, request);
         default:
@@ -1778,10 +1778,11 @@
      * Find the appropriate New method for an invoke dynamic call.
      *
      * @param desc The invoke dynamic call site descriptor.
+     * @param request The link request
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
+    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         return notAFunction();
     }
 
@@ -1866,6 +1867,17 @@
         return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
     }
 
+    //this will only return true if apply is still builtin
+    private static SwitchPoint checkReservedName(final CallSiteDescriptor desc, final LinkRequest request) {
+        final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        if ("apply".equals(name) && isApplyToCall && Global.instance().isSpecialNameValid(name)) {
+            assert Global.instance().getChangeCallback("apply") == Global.instance().getChangeCallback("call");
+            return Global.instance().getChangeCallback("apply");
+        }
+        return null;
+    }
+
     /**
      * Find the appropriate GET method for an invoke dynamic call.
      *
@@ -1877,7 +1889,15 @@
      */
     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
         final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
-        final String  name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        final String name;
+        final SwitchPoint reservedNameSwitchPoint;
+
+        reservedNameSwitchPoint = checkReservedName(desc, request);
+        if (reservedNameSwitchPoint != null) {
+            name = "call"; //turn apply into call, it is the builtin apply and has been modified to explode args
+        } else {
+            name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        }
 
         if (request.isCallSiteUnstable() || hasWithScope()) {
             return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator), isScope() && NashornCallSiteDescriptor.isScope(desc));
@@ -1893,7 +1913,7 @@
                         explicitInstanceOfCheck ?
                                 getScriptObjectGuard(desc.getMethodType(), explicitInstanceOfCheck) :
                                 null,
-                        null,
+                        (SwitchPoint)null,
                         explicitInstanceOfCheck ?
                                 null : ClassCastException.class);
             }
@@ -1910,9 +1930,9 @@
             }
         }
 
-        final GuardedInvocation inv = GlobalConstants.instance().findGetMethod(find, this, desc, request, operator);
-        if (inv != null) {
-            return inv;
+        final GuardedInvocation cinv = GlobalConstants.instance().findGetMethod(find, this, desc, request, operator);
+        if (cinv != null) {
+            return cinv;
         }
 
         final Class<?> returnType = desc.getMethodType().returnType();
@@ -1928,25 +1948,26 @@
         final ScriptObject owner = find.getOwner();
         final Class<ClassCastException> exception = explicitInstanceOfCheck ? null : ClassCastException.class;
 
+        final SwitchPoint protoSwitchPoint;
+
         if (mh == null) {
             mh = Lookup.emptyGetter(returnType);
-        } else if (find.isSelf()) {
-            return new GuardedInvocation(mh, guard, null, exception);
-         } else {
+            protoSwitchPoint = getProtoSwitchPoint(name, owner);
+        } else if (!find.isSelf()) {
             assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
             if (!property.hasGetterFunction(owner)) {
                 // Add a filter that replaces the self object with the prototype owning the property.
                 mh = addProtoFilter(mh, find.getProtoChainLength());
             }
+            protoSwitchPoint = getProtoSwitchPoint(name, owner);
+        } else {
+            protoSwitchPoint = null;
         }
 
         assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
 
-        return new GuardedInvocation(
-                mh,
-                guard,
-                getProtoSwitchPoint(name, owner),
-                exception);
+        final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
+        return inv.addSwitchPoint(reservedNameSwitchPoint);
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod, final boolean isScope) {
@@ -1994,7 +2015,7 @@
         }
 
         final MethodHandle mh = findGetIndexMethodHandle(returnClass, name, keyClass, desc);
-        return new GuardedInvocation(mh, getScriptObjectGuard(callType, explicitInstanceOfCheck), null, explicitInstanceOfCheck ? null : ClassCastException.class);
+        return new GuardedInvocation(mh, getScriptObjectGuard(callType, explicitInstanceOfCheck), (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
     private static MethodHandle getScriptObjectGuard(final MethodType type, final boolean explicitInstanceOfCheck) {
@@ -2091,7 +2112,7 @@
                 return new GuardedInvocation(
                         SETPROTOCHECK,
                         getScriptObjectGuard(desc.getMethodType(), explicitInstanceOfCheck),
-                        null,
+                        (SwitchPoint)null,
                         explicitInstanceOfCheck ? null : ClassCastException.class);
             } else if (!isExtensible()) {
                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
@@ -2179,7 +2200,7 @@
         MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, boolean.class);
         methodHandle = MH.insertArguments(methodHandle, 3, isStrict);
 
-        return new GuardedInvocation(methodHandle, getScriptObjectGuard(callType, explicitInstanceOfCheck), null, explicitInstanceOfCheck ? null : ClassCastException.class);
+        return new GuardedInvocation(methodHandle, getScriptObjectGuard(callType, explicitInstanceOfCheck), (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
     /**
@@ -2215,7 +2236,7 @@
                         0,
                         Object.class),
                 NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
-                null,
+                (SwitchPoint)null,
                 explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
--- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Fri Apr 11 16:52:56 2014 +0200
@@ -30,6 +30,8 @@
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
 
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.SwitchPoint;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -111,7 +113,7 @@
             // getGuard returns a map guard that casts its argument to ScriptObject, and if that fails, we need to
             // relink on ClassCastException.
             return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc, explicitInstanceOfCheck),
-                    null, explicitInstanceOfCheck ? null : ClassCastException.class);
+                    (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/SpillProperty.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java	Fri Apr 11 16:52:56 2014 +0200
@@ -64,13 +64,13 @@
             this.ensureSpillSize = MH.asType(MH.insertArguments(ScriptObject.ENSURE_SPILL_SIZE, 1, slot), MH.type(Object.class, Object.class));
         }
 
-        private static void ensure(int slot) {
+        private static void ensure(final int slot) {
             int len = ACCESSOR_CACHE.length;
             if (slot >= len) {
                 do {
                     len *= 2;
                 } while (slot >= len);
-                Accessors newCache[] = new Accessors[len];
+                final Accessors newCache[] = new Accessors[len];
                 System.arraycopy(ACCESSOR_CACHE, 0, newCache, 0, ACCESSOR_CACHE.length);
                 ACCESSOR_CACHE = newCache;
             }
@@ -157,7 +157,6 @@
      * @param flags  the property flags
      * @param slot   spill slot
      */
-    @SuppressWarnings("unused")
     public SpillProperty(final String key, final int flags, final int slot) {
         super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot));
         assert !OBJECT_FIELDS_ONLY || getCurrentType() == Object.class;
--- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Fri Apr 11 16:52:56 2014 +0200
@@ -229,7 +229,7 @@
                 if (getElement != null) {
                     getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz)));
                     final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
-                    return new GuardedInvocation(getElement, guard, null, ClassCastException.class);
+                    return new GuardedInvocation(getElement, guard, (SwitchPoint)null, ClassCastException.class);
                 }
             }
         }
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Fri Apr 11 16:52:56 2014 +0200
@@ -94,7 +94,7 @@
         factory.setSyncOnRelink(true);
         factory.setPrelinkFilter(new GuardedInvocationFilter() {
             @Override
-            public GuardedInvocation filter(GuardedInvocation inv, LinkRequest request, LinkerServices linkerServices) {
+            public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
                 return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType());
             }
@@ -341,7 +341,7 @@
      * @param boundThis the bound "this" value.
      * @return a bound dynamic method.
      */
-    public static Object bindDynamicMethod(Object dynamicMethod, Object boundThis) {
+    public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
         return new BoundDynamicMethod(dynamicMethod, boundThis);
     }
 
@@ -362,7 +362,7 @@
      * @param clazz the class being tested
      * @param isStatic is access checked for static members (or instance members)
      */
-    public static void checkReflectionAccess(Class<?> clazz, boolean isStatic) {
+    public static void checkReflectionAccess(final Class<?> clazz, final boolean isStatic) {
         ReflectionCheckLinker.checkReflectionAccess(clazz, isStatic);
     }
 
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Fri Apr 11 16:52:56 2014 +0200
@@ -30,6 +30,7 @@
 import java.lang.invoke.MethodType;
 import java.util.HashMap;
 import java.util.Map;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.GuardedTypeConversion;
@@ -71,7 +72,7 @@
 
         final GuardedInvocation inv;
         if (self instanceof JSObject) {
-            inv = lookup(desc);
+            inv = lookup(desc, request);
         } else {
             throw new AssertionError(); // Should never reach here.
         }
@@ -95,9 +96,10 @@
     }
 
 
-    private static GuardedInvocation lookup(final CallSiteDescriptor desc) {
+    private static GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
         final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
         final int c = desc.getNameTokenCount();
+
         switch (operator) {
             case "getProp":
             case "getElem":
@@ -116,7 +118,8 @@
     }
 
     private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc) {
-        final MethodHandle getter = MH.insertArguments(JSOBJECT_GETMEMBER, 1, desc.getNameToken(2));
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        final MethodHandle getter = MH.insertArguments(JSOBJECT_GETMEMBER, 1, name);
         return new GuardedInvocation(getter, IS_JSOBJECT_GUARD);
     }
 
@@ -135,8 +138,11 @@
 
     private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
         // TODO: if call site is already a vararg, don't do asCollector
-        final MethodHandle func = MH.asCollector(JSOBJECT_CALL, Object[].class, desc.getMethodType().parameterCount() - 2);
-        return new GuardedInvocation(func, IS_JSOBJECT_GUARD);
+        MethodHandle mh = JSOBJECT_CALL;
+        if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
+            mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, JSOBJECT_CALL);
+        }
+        return new GuardedInvocation(MH.asCollector(mh, Object[].class, desc.getMethodType().parameterCount() - 2), IS_JSOBJECT_GUARD);
     }
 
     private static GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
@@ -199,6 +205,21 @@
         return JSType.isRepresentableAsInt(value) ? (int)value : -1;
     }
 
+    @SuppressWarnings("unused")
+    private static Object callToApply(final MethodHandle mh, final JSObject obj, final Object thiz, final Object... args) {
+        assert args.length >= 2;
+        final Object   receiver  = args[0];
+        final Object[] arguments = new Object[args.length - 1];
+        System.arraycopy(args, 1, arguments, 0, arguments.length);
+        try {
+            return mh.invokeExact(obj, thiz, new Object[] { receiver, arguments });
+        } catch (final RuntimeException | Error e) {
+            throw e;
+        } catch (final Throwable e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
 
     // method handles of the current class
@@ -207,10 +228,11 @@
     private static final MethodHandle JSOBJECTLINKER_PUT = findOwnMH_S("put", Void.TYPE, Object.class, Object.class, Object.class);
 
     // method handles of JSObject class
-    private static final MethodHandle JSOBJECT_GETMEMBER  = findJSObjectMH_V("getMember", Object.class, String.class);
-    private static final MethodHandle JSOBJECT_SETMEMBER  = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class);
-    private static final MethodHandle JSOBJECT_CALL       = findJSObjectMH_V("call", Object.class, Object.class, Object[].class);
-    private static final MethodHandle JSOBJECT_NEW        = findJSObjectMH_V("newObject", Object.class, Object[].class);
+    private static final MethodHandle JSOBJECT_GETMEMBER     = findJSObjectMH_V("getMember", Object.class, String.class);
+    private static final MethodHandle JSOBJECT_SETMEMBER     = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class);
+    private static final MethodHandle JSOBJECT_CALL          = findJSObjectMH_V("call", Object.class, Object.class, Object[].class);
+    private static final MethodHandle JSOBJECT_CALL_TO_APPLY = findOwnMH_S("callToApply", Object.class, MethodHandle.class, JSObject.class, Object.class, Object[].class);
+    private static final MethodHandle JSOBJECT_NEW           = findJSObjectMH_V("newObject", Object.class, Object[].class);
 
     private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>();
     static {
--- a/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Fri Apr 11 16:52:56 2014 +0200
@@ -297,7 +297,6 @@
         }
 
         static class ProfileDumper implements Runnable {
-            @SuppressWarnings("resource")
             @Override
             public void run() {
                 PrintWriter out    = null;
@@ -442,7 +441,7 @@
                     final Object arg = args[i];
                     out.print(", ");
 
-                    if (getNashornDescriptor().isTraceScope() || !(arg instanceof ScriptObject && ((ScriptObject)arg).isScope())) {
+                    if (!(arg instanceof ScriptObject && ((ScriptObject)arg).isScope())) {
                         printObject(out, arg);
                     } else {
                         out.print("SCOPE");
@@ -470,7 +469,7 @@
          *
          * @throws Throwable if invocation fails or throws exception/error
          */
-        @SuppressWarnings({"unused", "resource"})
+        @SuppressWarnings("unused")
         public Object traceObject(final MethodHandle mh, final Object... args) throws Throwable {
             final PrintWriter out = Context.getCurrentErr();
             tracePrint(out, "ENTER ", args, null);
@@ -488,7 +487,7 @@
          *
          * @throws Throwable if invocation fails or throws exception/error
          */
-        @SuppressWarnings({"unused", "resource"})
+        @SuppressWarnings("unused")
         public void traceVoid(final MethodHandle mh, final Object... args) throws Throwable {
             final PrintWriter out = Context.getCurrentErr();
             tracePrint(out, "ENTER ", args, null);
--- a/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Fri Apr 11 16:52:56 2014 +0200
@@ -44,37 +44,37 @@
 public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
     /** Flags that the call site references a scope variable (it's an identifier reference or a var declaration, not a
      * property access expression. */
-    public static final int CALLSITE_SCOPE      = 1 << 0;
+    public static final int CALLSITE_SCOPE         = 1 << 0;
     /** Flags that the call site is in code that uses ECMAScript strict mode. */
-    public static final int CALLSITE_STRICT     = 1 << 1;
+    public static final int CALLSITE_STRICT        = 1 << 1;
     /** Flags that a property getter or setter call site references a scope variable that is located at a known distance
      * in the scope chain. Such getters and setters can often be linked more optimally using these assumptions. */
-    public static final int CALLSITE_FAST_SCOPE = 1 << 2;
+    public static final int CALLSITE_FAST_SCOPE    = 1 << 2;
     /** Flags that a callsite type is optimistic, i.e. we might get back a wider return value than encoded in the
      * descriptor, and in that case we have to throw an UnwarrantedOptimismException */
-    public static final int CALLSITE_OPTIMISTIC = 1 << 3;
+    public static final int CALLSITE_OPTIMISTIC    = 1 << 3;
+    /** Is this really an apply that we try to call as a call? */
+    public static final int CALLSITE_APPLY_TO_CALL = 1 << 4;
 
     /** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
      * code where call sites have this flag set. */
-    public static final int CALLSITE_PROFILE        = 1 << 4;
+    public static final int CALLSITE_PROFILE        = 1 << 5;
     /** Flags that the call site is traced; Contexts that have {@code "trace.callsites"} property set emit code where
      * call sites have this flag set. */
-    public static final int CALLSITE_TRACE          = 1 << 5;
+    public static final int CALLSITE_TRACE          = 1 << 6;
     /** Flags that the call site linkage miss (and thus, relinking) is traced; Contexts that have the keyword
      * {@code "miss"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
-    public static final int CALLSITE_TRACE_MISSES   = 1 << 6;
+    public static final int CALLSITE_TRACE_MISSES   = 1 << 7;
     /** Flags that entry/exit to/from the method linked at call site are traced; Contexts that have the keyword
      * {@code "enterexit"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
-    public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 7;
+    public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 8;
     /** Flags that values passed as arguments to and returned from the method linked at call site are traced; Contexts
      * that have the keyword {@code "values"} in their {@code "trace.callsites"} property emit code where call sites
      * have this flag set. */
-    public static final int CALLSITE_TRACE_VALUES   = 1 << 8;
-    /** Ordinarily, when {@link #CALLSITE_TRACE_VALUES} is set, scope objects are not printed in the trace but instead
-     * the word {@code "SCOPE"} is printed instead With this flag, scope objects are also printed. Contexts that have
-     * the keyword {@code "scope"} in their {@code "trace.callsites"} property emit code where call sites have this flag
-     * set. */
-    public static final int CALLSITE_TRACE_SCOPE      = 1 << 9;
+    public static final int CALLSITE_TRACE_VALUES   = 1 << 9;
+
+    //we could have more tracing flags here, for example CALLSITE_TRACE_SCOPE, but bits are a bit precious
+    //right now given the program points
 
     /**
      * Number of bits the program point is shifted to the left in the flags (lowest bit containing a program point).
@@ -125,6 +125,9 @@
                 sb.append("scope ");
             }
         }
+        if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
+            sb.append("apply2call ");
+        }
         if ((flags & CALLSITE_STRICT) != 0) {
             sb.append("strict ");
         }
@@ -308,6 +311,16 @@
     }
 
     /**
+     * Returns true if this is an apply call that we try to call as
+     * a "call"
+     * @param desc descriptor
+     * @return true if apply to call
+     */
+    public static boolean isApplyToCall(final CallSiteDescriptor desc) {
+        return isFlag(desc, CALLSITE_APPLY_TO_CALL);
+    }
+
+    /**
      * Is this an optimistic call site
      * @param desc descriptor
      * @return true if optimistic
@@ -346,10 +359,6 @@
         return isFlag(CALLSITE_TRACE_VALUES);
     }
 
-    boolean isTraceScope() {
-        return isFlag(CALLSITE_TRACE_SCOPE);
-    }
-
     boolean isOptimistic() {
         return isFlag(CALLSITE_OPTIMISTIC);
     }
@@ -358,4 +367,5 @@
     public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
         return get(getLookup(), operator, operand, newMethodType, flags);
     }
+
 }
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Fri Apr 11 16:52:56 2014 +0200
@@ -63,7 +63,7 @@
 final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
     private static final ClassValue<MethodHandle> ARRAY_CONVERTERS = new ClassValue<MethodHandle>() {
         @Override
-        protected MethodHandle computeValue(Class<?> type) {
+        protected MethodHandle computeValue(final Class<?> type) {
             return createArrayConverter(type);
         }
     };
@@ -212,7 +212,7 @@
         return MH.asType(converter, converter.type().changeReturnType(type));
     }
 
-    private static GuardedInvocation getMirrorConverter(Class<?> sourceType, Class<?> targetType) {
+    private static GuardedInvocation getMirrorConverter(final Class<?> sourceType, final Class<?> targetType) {
         // Could've also used (targetType.isAssignableFrom(ScriptObjectMirror.class) && targetType != Object.class) but
         // it's probably better to explicitly spell out the supported target types
         if (targetType == Map.class || targetType == Bindings.class || targetType == JSObject.class || targetType == ScriptObjectMirror.class) {
@@ -274,7 +274,7 @@
         return Comparison.INDETERMINATE;
     }
 
-    private static boolean isList(Class<?> clazz) {
+    private static boolean isList(final Class<?> clazz) {
         return clazz == List.class || clazz == Deque.class;
     }
 
--- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Fri Apr 11 16:52:56 2014 +0200
@@ -126,7 +126,7 @@
                 assert receiverType.isAssignableFrom(wrapType.returnType());
                 method = MH.filterArguments(method, 0, MH.asType(wrapFilter, wrapType.changeReturnType(receiverType)));
             }
-            return new GuardedInvocation(method, guard, link.getSwitchPoint());
+            return new GuardedInvocation(method, guard, link.getSwitchPoints(), null);
         }
         return null;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/examples/apply_to_call_benchmark.js	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,37 @@
+var Class = {
+  create: function() {
+    return function() { //vararg
+        this.initialize.apply(this, arguments);
+    }
+  }
+};
+
+Color = Class.create();
+Color.prototype = {
+    red: 0, green: 0, blue: 0,
+    initialize: function(r,g,b) {
+	this.red = r;
+	this.green = g;
+	this.blue = b;
+    }
+}
+
+function bench(x) {
+    var d = new Date;
+    var colors = new Array(16);
+    for (var i=0;i<1e8;i++) {
+	colors[i&0xf] = (new Color(1,2,3));
+    }
+    print(new Date - d);
+    return colors;
+}
+bench(17);
+
+print("Swapping out call");
+Function.prototype.call = function() {
+    throw "This should not happen, apply should be called instead";
+};
+
+bench(17);
+
+print("All done!");
--- a/test/script/basic/JDK-8016618.js	Fri Apr 11 16:40:06 2014 +0200
+++ b/test/script/basic/JDK-8016618.js	Fri Apr 11 16:52:56 2014 +0200
@@ -61,11 +61,23 @@
 
 function f() {
     // mirror function called with local arguments
+    //    global.func.apply(obj, arguments);
     global.func.apply(obj, arguments);
 }
 
 f(23, "hello");
 
+f(24, "hello2");
+
+var oldCall = Function.prototype.call;
+Function.prototype.call = function() {
+    throw "this should never happen! go back to apply!";
+};
+
+f(25, "hello3");
+
+Function.prototype.call = oldCall;
+
 var fObject = global.eval("Object");
 
 // instanceof on mirrors
--- a/test/script/basic/JDK-8016618.js.EXPECTED	Fri Apr 11 16:40:06 2014 +0200
+++ b/test/script/basic/JDK-8016618.js.EXPECTED	Fri Apr 11 16:52:56 2014 +0200
@@ -1,6 +1,10 @@
 x = 33
 func.x = 23
 func.x = hello
+func.x = 24
+func.x = hello2
+func.x = 25
+func.x = hello3
 global instanceof fObject? true
 x is wriable ? true
 x value = 33
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call1.js	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * apply_to_call1.js - do one apply to call specialization, then override, apply and make sure it reverts (i.e. stops 
+ * calling call)
+ *
+ * @test
+ * @run
+ */
+
+print("start"); 
+
+var x = {
+    a : 0,
+    b : 0,
+    c : 0,
+    initialize : function(x,y,z) {
+	this.a = x;
+	this.b = y;
+	this.c = z;
+    }
+};
+
+function test() {
+    x.initialize.apply(x, arguments);
+}
+
+test(4711,23,17);
+print(x.a);
+print(x.b);
+print(x.c);
+
+print("Overwriting apply now");
+
+x.initialize = { 
+    apply : function() {
+	for (var i=0;i<arguments.length;i++) {	    
+	    print("I am not who you think " + arguments[i]);
+	}
+	x.a = arguments[1][0];
+    }
+};
+
+test(4712);
+print(x.a);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call1.js.EXPECTED	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,8 @@
+start
+4711
+23
+17
+Overwriting apply now
+I am not who you think [object Object]
+I am not who you think [object Arguments]
+4712
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call2.js	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * apply_to_call2.js - do one apply to call specialization, then override call and make sure it reverts (i.e. stops 
+ * calling call)
+ *
+ * @test
+ * @run
+ */
+
+print("start"); 
+
+var x = {
+    a : 0,
+    b : 0,
+    c : 0,
+    initialize : function(x,y,z) {
+	this.a = x;
+	this.b = y;
+	this.c = z;
+    }
+};
+
+function test() {
+    x.initialize.apply(x, arguments);
+}
+
+test(4711,23,17);
+print(x.a);
+print(x.b);
+print(x.c);
+
+print("Overwriting call now");
+
+Function.prototype.call = function() {
+    throw "this should never be thrown - test should revert to builtin apply";
+};
+
+test(1,2,3);
+print(x.a);
+print(x.b);
+print(x.c);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call2.js.EXPECTED	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,8 @@
+start
+4711
+23
+17
+Overwriting call now
+1
+2
+3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call3.js	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * apply_to_call3.js - do one apply to call specialization, then override, apply and make sure it reverts (i.e. stops 
+ * calling call). Then apply should break and throw exception
+ *
+ * @test
+ * @run
+ */
+
+print("start"); 
+
+var x = {
+    a : 0,
+    b : 0,
+    c : 0,
+    initialize : function(x,y,z) {
+	this.a = x;
+	this.b = y;
+	this.c = z;
+    }
+};
+
+function test() {
+    x.initialize.apply(x, arguments);
+}
+
+test(4711,23,17);
+print(x.a);
+print(x.b);
+print(x.c);
+
+print("Overwriting apply now");
+
+Function.prototype.apply = function() {
+    throw "This should be thrown, as the test call transform is no longer valid";
+};
+
+try {
+    test(1,2,3);
+} catch (e) {
+    print(e);
+}
+print(x.a);
+print(x.b);
+print(x.c);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call3.js.EXPECTED	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,9 @@
+start
+4711
+23
+17
+Overwriting apply now
+This should be thrown, as the test call transform is no longer valid
+4711
+23
+17
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call4.js	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * apply_to_call4.js - various escaping args patterns that prevent the optimization from being applied
+ * calling call)
+ *
+ * @test
+ * @run
+ */
+
+print("start"); 
+
+var x = {
+    a : 0,
+    b : 0,
+    c : 0,
+    initialize : function(x,y,z) {
+	this.a = x;
+	this.b = y;
+	this.c = z;
+    }
+};
+
+function f(x) {
+    print("this is a black hole - arguments escape");
+}
+
+function test() {
+    f(arguments);
+    x.initialize.apply(x, arguments);
+}
+
+test(4711,23,17);
+print(x.a);
+print(x.b);
+print(x.c);
+
+function test2() {
+    arguments[0] = 17;
+    x.initialize.apply(x, arguments);
+}
+
+test2(1,2,3);
+print(x.a);
+print(x.b);
+print(x.c);
+
+function test3() {
+    var escape = arguments[0];
+    f(escape);
+    x.initialize.apply(x, arguments);
+}
+
+test3("alpha", "beta", "gamma");
+print(x.a);
+print(x.b);
+print(x.c);
+
+function test4() {
+    var escape = arguments.length;
+    f(escape);
+    x.initialize.apply(x, arguments);
+}
+
+test4(1.2, 2.3, 3.4);
+print(x.a);
+print(x.b);
+print(x.c);
+
+function test5() {
+    x.initialize.apply(x, arguments, 17);
+}
+
+print("test 5 done");
+test5(11, 22);
+print("a="+typeof(x.a));
+print(x.b);
+print(x.c);
+
+print("Now it's time for transforms");
+
+function test6() {
+    x.initialize.apply(x, arguments);
+}
+
+test6(19, 20, 21);
+print(x.a);
+print(x.b);
+print(x.c);
+
+function test7() {
+    x.initialize.apply(x, arguments);
+}
+
+test7(1, 2.2, 17, 18);
+print(x.a);
+print(x.b);
+print(x.c);
+
+print("Should have transformed");
+
+function test8() {
+    var apply = f;
+    x.initialize.apply(x, arguments);
+}
+
+test8(7,8,9);
+print(x.a);
+print(x.b);
+print(x.c);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call4.js.EXPECTED	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,31 @@
+start
+this is a black hole - arguments escape
+4711
+23
+17
+17
+2
+3
+this is a black hole - arguments escape
+alpha
+beta
+gamma
+this is a black hole - arguments escape
+1.2
+2.3
+3.4
+test 5 done
+a=object
+17
+undefined
+Now it's time for transforms
+19
+20
+21
+1
+2.2
+17
+Should have transformed
+7
+8
+9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call_bench.js	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * sanity check that apply to call specialization is faster than apply.
+ *
+ * @test
+  * @run
+ */
+
+var Class = {
+    create: function() {
+	return function() { //vararg
+	    this.initialize.apply(this, arguments);
+	}
+    }
+};
+
+Color = Class.create();
+Color.prototype = {
+    red: 0, green: 0, blue: 0,
+    initialize: function(r,g,b) {
+	this.red = r;
+	this.green = g;
+	this.blue = b;
+    }
+};
+
+var time1 = 0;
+var time2 = 0;
+
+function set_time1(t) {
+    time1 = t;
+}
+
+function set_time2(t) {
+    time2 = t;
+}
+
+function bench(x, set_time) {
+    var d = new Date;
+    var colors = new Array(16);
+    for (var i=0;i<1e8;i++) {
+	colors[i & 0xf] = new Color(1,2,3);
+    }
+    var t = new Date - d;
+    set_time(t);
+    return colors;
+}
+
+//warmup
+print("Running warmup");
+bench(17, set_time1);
+
+print("Running sharp run");
+bench(17, set_time1);
+
+print("Swapping out call");
+Function.prototype.call = function() {
+    throw "This should not happen, apply should be called instead";
+};
+
+print("Rerunning invalidated");
+bench(17, set_time2);
+
+print("All done!");
+
+if (time1 > time2) {
+    print("ERROR: time1 > time2 (" + time1 + " > " + time2 + ")");
+} else {
+    print("Times OK");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call_bench.js.EXPECTED	Fri Apr 11 16:52:56 2014 +0200
@@ -0,0 +1,6 @@
+Running warmup
+Running sharp run
+Swapping out call
+Rerunning invalidated
+All done!
+Times OK
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java	Fri Apr 11 16:52:56 2014 +0200
@@ -42,7 +42,7 @@
  */
 public class ScriptEngineSecurityTest {
 
-    private void log(String msg) {
+    private void log(final String msg) {
         org.testng.Reporter.log(msg, true);
     }
 
@@ -185,8 +185,8 @@
         // put an empty script object into array
         e.eval("holder[0] = {}");
         // holder[0] is an object of some subclass of ScriptObject
-        Class ScriptObjectClass = holder[0].getClass().getSuperclass();
-        Class PropertyAccessClass = ScriptObjectClass.getInterfaces()[0];
+        final Class<?> ScriptObjectClass = holder[0].getClass().getSuperclass();
+        final Class<?> PropertyAccessClass = ScriptObjectClass.getInterfaces()[0];
         // implementation methods for PropertyAccess class
         e.eval("function set() {}; function get() {}; function getInt(){} " +
                "function getDouble(){}; function getLong() {}; " +
@@ -206,11 +206,11 @@
 
     // @bug 8032948: Nashorn linkages awry
     public static class FakeProxy extends Proxy {
-        public FakeProxy(InvocationHandler ih) {
+        public FakeProxy(final InvocationHandler ih) {
             super(ih);
         }
 
-        public static Class<?> makeProxyClass(ClassLoader cl, Class<?>... ifaces) {
+        public static Class<?> makeProxyClass(final ClassLoader cl, final Class<?>... ifaces) {
             return Proxy.getProxyClass(cl, ifaces);
         }
     }
@@ -229,11 +229,11 @@
         e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
         e.put("intfs", new Class[] { Runnable.class });
 
-        String getClass = "Java.type(name + '$FakeProxy').getProxyClass(cl, intfs);";
+        final String getClass = "Java.type(name + '$FakeProxy').getProxyClass(cl, intfs);";
 
         // Should not be able to call static methods of Proxy via fake subclass
         try {
-            Class c = (Class)e.eval(getClass);
+            final Class<?> c = (Class<?>)e.eval(getClass);
             fail("should have thrown SecurityException");
         } catch (final Exception exp) {
             if (! (exp instanceof SecurityException)) {
@@ -256,11 +256,11 @@
         e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
         e.put("intfs", new Class[] { Runnable.class });
 
-        String getClass = "Java.type(name + '$FakeProxy').makeProxyClass(cl, intfs);";
+        final String getClass = "Java.type(name + '$FakeProxy').makeProxyClass(cl, intfs);";
 
         // Should not be able to call static methods of Proxy via fake subclass
         try {
-            Class c = (Class)e.eval(getClass);
+            final Class<?> c = (Class<?>)e.eval(getClass);
             fail("should have thrown SecurityException");
         } catch (final Exception exp) {
             if (! (exp instanceof SecurityException)) {
@@ -278,7 +278,7 @@
             new Class[] { Runnable.class },
             new InvocationHandler() {
                 @Override
-                public Object invoke(Object p, Method m, Object[] a) {
+                public Object invoke(final Object p, final Method m, final Object[] a) {
                     return null;
                 }
             });
--- a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java	Fri Apr 11 16:40:06 2014 +0200
+++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java	Fri Apr 11 16:52:56 2014 +0200
@@ -34,7 +34,6 @@
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptContext;
 import javax.script.ScriptException;
-import javax.script.SimpleBindings;
 import javax.script.SimpleScriptContext;
 import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
 import org.testng.annotations.Test;
@@ -55,7 +54,7 @@
         private final boolean[] reached = new boolean[1];
 
         @Override
-        protected Class findClass(final String name) throws ClassNotFoundException {
+        protected Class<?> findClass(final String name) throws ClassNotFoundException {
             // flag that it reached here
             reached[0] = true;
             return super.findClass(name);
@@ -72,7 +71,7 @@
     @Test
     public void factoryClassLoaderTest() {
         final ScriptEngineManager sm = new ScriptEngineManager();
-        for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+        for (final ScriptEngineFactory fac : sm.getEngineFactories()) {
             if (fac instanceof NashornScriptEngineFactory) {
                 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
                 final MyClassLoader loader = new MyClassLoader();
@@ -96,7 +95,7 @@
     @Test
     public void factoryClassLoaderAndOptionsTest() {
         final ScriptEngineManager sm = new ScriptEngineManager();
-        for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+        for (final ScriptEngineFactory fac : sm.getEngineFactories()) {
             if (fac instanceof NashornScriptEngineFactory) {
                 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
                 final String[] options = new String[] { "-strict" };
@@ -130,7 +129,7 @@
     @Test
     public void factoryOptionsTest() {
         final ScriptEngineManager sm = new ScriptEngineManager();
-        for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+        for (final ScriptEngineFactory fac : sm.getEngineFactories()) {
             if (fac instanceof NashornScriptEngineFactory) {
                 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
                 // specify --no-syntax-extensions flag
@@ -156,7 +155,7 @@
      */
     public void noLoaderPerCompilerTest() {
         final ScriptEngineManager sm = new ScriptEngineManager();
-        for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+        for (final ScriptEngineFactory fac : sm.getEngineFactories()) {
             if (fac instanceof NashornScriptEngineFactory) {
                 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
                 final String[] options = new String[] { "--loader-per-compile=false" };
@@ -181,7 +180,7 @@
      */
     public void noLoaderPerCompilerWithSameNameTest() {
         final ScriptEngineManager sm = new ScriptEngineManager();
-        for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+        for (final ScriptEngineFactory fac : sm.getEngineFactories()) {
             if (fac instanceof NashornScriptEngineFactory) {
                 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
                 final String[] options = new String[] { "--loader-per-compile=false" };