changeset 991:724bb760e386

Merge
author jcoomes
date Tue, 07 Oct 2014 10:57:55 -0700
parents 6a8ecdeae4a9 (current diff) 9b24fc6da691 (diff)
children bcc569328dfa
files src/jdk/nashorn/internal/objects/annotations/SpecializedConstructor.java
diffstat 100 files changed, 3099 insertions(+), 869 deletions(-) [+]
line wrap: on
line diff
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Tue Oct 07 10:57:55 2014 -0700
@@ -292,7 +292,6 @@
             mi.push(memInfo.getArity());
             mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
         }
-
     }
 
     static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Tue Oct 07 10:57:55 2014 -0700
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC;
-
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
 import jdk.nashorn.internal.objects.annotations.Where;
@@ -75,10 +74,6 @@
          * This is a specialized version of a function
          */
         SPECIALIZED_FUNCTION,
-        /**
-         * This is a specialized version of a constructor
-         */
-        SPECIALIZED_CONSTRUCTOR
     }
 
     // keep in sync with jdk.nashorn.internal.objects.annotations.Attribute
@@ -107,6 +102,12 @@
 
     private Where where;
 
+    private Type linkLogicClass;
+
+    private boolean isSpecializedConstructor;
+
+    private boolean isOptimistic;
+
     /**
      * @return the kind
      */
@@ -136,6 +137,57 @@
     }
 
     /**
+     * Tag something as specialized constructor or not
+     * @param isSpecializedConstructor boolean, true if specialized constructor
+     */
+    public void setIsSpecializedConstructor(final boolean isSpecializedConstructor) {
+        this.isSpecializedConstructor = isSpecializedConstructor;
+    }
+
+    /**
+     * Check if something is a specialized constructor
+     * @return true if specialized constructor
+     */
+    public boolean isSpecializedConstructor() {
+        return isSpecializedConstructor;
+    }
+
+    /**
+     * Check if this is an optimistic builtin function
+     * @return true if optimistic builtin
+     */
+    public boolean isOptimistic() {
+        return isOptimistic;
+    }
+
+    /**
+     * Tag something as optimitic builtin or not
+     * @param isOptimistic boolean, true if builtin constructor
+     */
+    public void setIsOptimistic(final boolean isOptimistic) {
+        this.isOptimistic = isOptimistic;
+    }
+
+    /**
+     * Get the SpecializedFunction guard for specializations, i.e. optimistic
+     * builtins
+     * @return specialization, null if none
+     */
+    public Type getLinkLogicClass() {
+        return linkLogicClass;
+    }
+
+    /**
+     * Set thre SpecializedFunction link logic class for specializations, i.e. optimistic
+     * builtins
+     * @param linkLogicClass link logic class
+     */
+
+    public void setLinkLogicClass(final Type linkLogicClass) {
+        this.linkLogicClass = linkLogicClass;
+    }
+
+    /**
      * @return the attributes
      */
     public int getAttributes() {
@@ -304,19 +356,6 @@
                 }
             }
             break;
-            case SPECIALIZED_CONSTRUCTOR: {
-                final Type returnType = Type.getReturnType(javaDesc);
-                if (!isJSObjectType(returnType)) {
-                    error("return value of a @SpecializedConstructor method should be a valid JS type, found " + returnType);
-                }
-                final Type[] argTypes = Type.getArgumentTypes(javaDesc);
-                for (int i = 0; i < argTypes.length; i++) {
-                    if (!isValidJSType(argTypes[i])) {
-                        error(i + "'th argument of a @SpecializedConstructor method is not valid JS type, found " + argTypes[i]);
-                    }
-                }
-            }
-            break;
             case FUNCTION: {
                 final Type returnType = Type.getReturnType(javaDesc);
                 if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) {
@@ -351,7 +390,7 @@
             break;
             case SPECIALIZED_FUNCTION: {
                 final Type returnType = Type.getReturnType(javaDesc);
-                if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) {
+                if (!(isValidJSType(returnType) || (isSpecializedConstructor() && Type.VOID_TYPE == returnType))) {
                     error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType);
                 }
                 final Type[] argTypes = Type.getArgumentTypes(javaDesc);
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java	Tue Oct 07 10:57:55 2014 -0700
@@ -56,6 +56,7 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
 import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
 import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
@@ -76,9 +77,11 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
 import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
-
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT2;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT3;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SPECIALIZATION;
 import java.util.List;
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -95,6 +98,8 @@
     private final Type returnType;
     private final Type[] argumentTypes;
 
+    static final Type EMPTY_LINK_LOGIC_TYPE = Type.getType("Ljdk/nashorn/internal/objects/annotations/SpecializedFunction$LinkLogic$Empty;");
+
     MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
         super(ASM4, mv);
         this.access        = access;
@@ -380,6 +385,11 @@
         super.visitFieldInsn(GETFIELD, owner, field, desc);
     }
 
+    private static boolean linkLogicIsEmpty(final Type type) {
+        assert EMPTY_LINK_LOGIC_TYPE != null; //type is ok for null if we are a @SpecializedFunction without any attribs
+        return EMPTY_LINK_LOGIC_TYPE.equals(type);
+    }
+
     void memberInfoArray(final String className, final List<MemberInfo> mis) {
         if (mis.isEmpty()) {
             pushNull();
@@ -388,12 +398,22 @@
 
         int pos = 0;
         push(mis.size());
-        newObjectArray(METHODHANDLE_TYPE);
+        newObjectArray(SPECIALIZATION_TYPE);
         for (final MemberInfo mi : mis) {
             dup();
             push(pos++);
+            visitTypeInsn(NEW, SPECIALIZATION_TYPE);
+            dup();
             visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc()));
-            arrayStore(TYPE_METHODHANDLE);
+            final Type    linkLogicClass = mi.getLinkLogicClass();
+            final boolean linkLogic      = !linkLogicIsEmpty(linkLogicClass);
+            final String  ctor           = linkLogic ? SPECIALIZATION_INIT3 : SPECIALIZATION_INIT2;
+            if (linkLogic) {
+                visitLdcInsn(linkLogicClass);
+            }
+            visitInsn(mi.isOptimistic() ? ICONST_1 : ICONST_0);
+            visitMethodInsn(INVOKESPECIAL, SPECIALIZATION_TYPE, INIT, ctor, false);
+            arrayStore(TYPE_SPECIALIZATION);
         }
     }
 
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java	Tue Oct 07 10:57:55 2014 -0700
@@ -37,7 +37,6 @@
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Setter;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
@@ -57,7 +56,7 @@
     static final String PROPERTY_ANNO_DESC      = Type.getDescriptor(Property.class);
     static final String WHERE_ENUM_DESC         = Type.getDescriptor(Where.class);
     static final String SPECIALIZED_FUNCTION    = Type.getDescriptor(SpecializedFunction.class);
-    static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class);
+    static final String LINK_LOGIC_DESC         = "Ljdk/nashorn/internal/objects/annotations/SpecializedFunction$LinkLogic;";
 
     static final Map<String, Kind> annotations = new HashMap<>();
 
@@ -69,7 +68,6 @@
         annotations.put(SETTER_ANNO_DESC, Kind.SETTER);
         annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY);
         annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION);
-        annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR);
     }
 
     // name of the script class
@@ -119,11 +117,12 @@
     List<MemberInfo> getSpecializedConstructors() {
         final List<MemberInfo> res = new LinkedList<>();
         for (final MemberInfo memInfo : members) {
-            if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) {
+            if (memInfo.isSpecializedConstructor()) {
+                assert memInfo.getKind() == Kind.SPECIALIZED_FUNCTION;
                 res.add(memInfo);
             }
         }
-        return res;
+        return Collections.unmodifiableList(res);
     }
 
     int getPrototypeMemberCount() {
@@ -175,7 +174,7 @@
                 res.add(memInfo);
             }
         }
-        return res;
+        return Collections.unmodifiableList(res);
     }
 
     MemberInfo findSetter(final MemberInfo getter) {
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Tue Oct 07 10:57:55 2014 -0700
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC;
 import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC;
-
 import java.io.BufferedInputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -41,6 +40,7 @@
 import jdk.internal.org.objectweb.asm.FieldVisitor;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
 
@@ -194,6 +194,7 @@
 
                     final MemberInfo memInfo = new MemberInfo();
 
+                    //annokind == e.g. GETTER or SPECIALIZED_FUNCTION
                     memInfo.setKind(annoKind);
                     memInfo.setJavaName(methodName);
                     memInfo.setJavaDesc(methodDesc);
@@ -208,12 +209,18 @@
                         private Integer attributes;
                         private Integer arity;
                         private Where   where;
+                        private boolean isSpecializedConstructor;
+                        private boolean isOptimistic;
+                        private Type    linkLogicClass = MethodGenerator.EMPTY_LINK_LOGIC_TYPE;
 
                         @Override
                         public void visit(final String annotationName, final Object annotationValue) {
                             switch (annotationName) {
                             case "name":
                                 this.name = (String)annotationValue;
+                                if (name.isEmpty()) {
+                                    name = null;
+                                }
                                 break;
                             case "attributes":
                                 this.attributes = (Integer)annotationValue;
@@ -221,6 +228,17 @@
                             case "arity":
                                 this.arity = (Integer)annotationValue;
                                 break;
+                            case "isConstructor":
+                                assert annoKind == Kind.SPECIALIZED_FUNCTION;
+                                this.isSpecializedConstructor = (Boolean)annotationValue;
+                                break;
+                            case "isOptimistic":
+                                assert annoKind == Kind.SPECIALIZED_FUNCTION;
+                                this.isOptimistic = (Boolean)annotationValue;
+                                break;
+                            case "linkLogic":
+                                this.linkLogicClass = (Type)annotationValue;
+                                break;
                             default:
                                 break;
                             }
@@ -230,12 +248,19 @@
 
                         @Override
                         public void visitEnum(final String enumName, final String desc, final String enumValue) {
-                            if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
-                                this.where = Where.valueOf(enumValue);
+                            switch (enumName) {
+                            case "where":
+                                if (WHERE_ENUM_DESC.equals(desc)) {
+                                    this.where = Where.valueOf(enumValue);
+                                }
+                                break;
+                            default:
+                                break;
                             }
                             super.visitEnum(enumName, desc, enumValue);
                         }
 
+                        @SuppressWarnings("fallthrough")
                         @Override
                         public void visitEnd() {
                             super.visitEnd();
@@ -256,7 +281,6 @@
                                     case SETTER:
                                         where = Where.INSTANCE;
                                         break;
-                                    case SPECIALIZED_CONSTRUCTOR:
                                     case CONSTRUCTOR:
                                         where = Where.CONSTRUCTOR;
                                         break;
@@ -264,12 +288,18 @@
                                         where = Where.PROTOTYPE;
                                         break;
                                     case SPECIALIZED_FUNCTION:
-                                        //TODO is this correct
+                                        if (isSpecializedConstructor) {
+                                            where = Where.CONSTRUCTOR;
+                                        }
+                                        //fallthru
                                     default:
                                         break;
                                 }
                             }
                             memInfo.setWhere(where);
+                            memInfo.setLinkLogicClass(linkLogicClass);
+                            memInfo.setIsSpecializedConstructor(isSpecializedConstructor);
+                            memInfo.setIsOptimistic(isOptimistic);
                         }
                     };
                 }
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java	Tue Oct 07 10:57:55 2014 -0700
@@ -38,7 +38,6 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
-
 import java.io.BufferedInputStream;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Tue Oct 07 10:57:55 2014 -0700
@@ -37,6 +37,7 @@
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.Specialization;
 
 /**
  * String constants used for code generation/instrumentation.
@@ -44,20 +45,26 @@
 @SuppressWarnings("javadoc")
 public interface StringConstants {
     // standard jdk types, methods
-    static final Type TYPE_METHODHANDLE       = Type.getType(MethodHandle.class);
-    static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
-    static final Type TYPE_OBJECT             = Type.getType(Object.class);
-    static final Type TYPE_STRING             = Type.getType(String.class);
-    static final Type TYPE_COLLECTION         = Type.getType(Collection.class);
-    static final Type TYPE_COLLECTIONS        = Type.getType(Collections.class);
-    static final Type TYPE_ARRAYLIST          = Type.getType(ArrayList.class);
-    static final Type TYPE_LIST               = Type.getType(List.class);
+    static final Type TYPE_METHODHANDLE         = Type.getType(MethodHandle.class);
+    static final Type TYPE_METHODHANDLE_ARRAY   = Type.getType(MethodHandle[].class);
+    static final Type TYPE_SPECIALIZATION       = Type.getType(Specialization.class);
+    static final Type TYPE_SPECIALIZATION_ARRAY = Type.getType(Specialization[].class);
+    static final Type TYPE_OBJECT               = Type.getType(Object.class);
+    static final Type TYPE_STRING               = Type.getType(String.class);
+    static final Type TYPE_CLASS                = Type.getType(Class.class);
+    static final Type TYPE_COLLECTION           = Type.getType(Collection.class);
+    static final Type TYPE_COLLECTIONS          = Type.getType(Collections.class);
+    static final Type TYPE_ARRAYLIST            = Type.getType(ArrayList.class);
+    static final Type TYPE_LIST                 = Type.getType(List.class);
 
     static final String CLINIT = "<clinit>";
     static final String INIT = "<init>";
     static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
 
     static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
+    static final String SPECIALIZATION_TYPE = TYPE_SPECIALIZATION.getInternalName();
+    static final String SPECIALIZATION_INIT2 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, Type.getType(boolean.class));
+    static final String SPECIALIZATION_INIT3 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, TYPE_CLASS, Type.getType(boolean.class));
     static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
     static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
     static final String STRING_TYPE = TYPE_STRING.getInternalName();
@@ -122,11 +129,11 @@
     static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC =
         Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE);
     static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC =
-        Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
+        Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
     static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 =
-        Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
+        Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
     static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 =
-        Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
+        Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_SPECIALIZATION_ARRAY);
 
     // ScriptObject
     static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName();
--- a/samples/BufferArray.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/samples/BufferArray.java	Tue Oct 07 10:57:55 2014 -0700
@@ -29,8 +29,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import java.nio.DoubleBuffer;
 import jdk.nashorn.api.scripting.AbstractJSObject;
-import java.nio.DoubleBuffer;
 
 /**
  * Simple class demonstrating pluggable script object
@@ -52,41 +52,49 @@
     // underlying nio buffer
     private final DoubleBuffer buf;
 
-    public BufferArray(int size) {
+    /**
+     * Constructor
+     * @param size initial size
+     */
+    public BufferArray(final int size) {
         buf = DoubleBuffer.allocate(size);
     }
 
-    public BufferArray(DoubleBuffer buf) {
+    /**
+     * Constructur
+     * @param buf {@link DoubleBuffer} to link to
+     */
+    public BufferArray(final DoubleBuffer buf) {
         this.buf = buf;
     }
 
     // called to check if indexed property exists
     @Override
-    public boolean hasSlot(int index) {
+    public boolean hasSlot(final int index) {
         return index > 0 && index < buf.capacity();
     }
 
     // get the value from that index
     @Override
-    public Object getSlot(int index) {
+    public Object getSlot(final int index) {
        return buf.get(index);
     }
 
     // set the value at that index
     @Override
-    public void setSlot(int index, Object value) {
+    public void setSlot(final int index, final Object value) {
        buf.put(index, ((Number)value).doubleValue());
     }
 
     // do you have a property of that given name?
     @Override
-    public boolean hasMember(String name) {
+    public boolean hasMember(final String name) {
        return "length".equals(name) || "buf".equals(name);
     }
 
     // get the value of that named property
     @Override
-    public Object getMember(String name) {
+    public Object getMember(final String name) {
        switch (name) {
           case "length":
               return buf.capacity();
@@ -94,7 +102,7 @@
               // return a 'function' value for this property
               return new AbstractJSObject() {
                   @Override
-                  public Object call(Object thiz, Object... args) {
+                  public Object call(final Object thiz, final Object... args) {
                       return BufferArray.this.buf;
                   }
 
@@ -104,6 +112,8 @@
                       return true;
                   }
               };
+          default:
+              break;
        }
        return null;
     }
--- a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Tue Oct 07 10:57:55 2014 -0700
@@ -27,7 +27,6 @@
 
 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;
@@ -35,7 +34,6 @@
 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;
@@ -131,11 +129,12 @@
         @SuppressWarnings("serial")
         final UnsupportedOperationException uoe = new UnsupportedOperationException() {
             @Override
-            public Throwable fillInStackTrace() {
+            public synchronized Throwable fillInStackTrace() {
                 return null;
             }
         };
 
+        final Set<Expression> argumentsFound = new HashSet<>();
         final Deque<Set<Expression>> stack = new ArrayDeque<>();
         //ensure that arguments is only passed as arg to apply
         try {
@@ -145,7 +144,11 @@
                 }
 
                 private boolean isArguments(final Expression expr) {
-                    return expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName());
+                    if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) {
+                        argumentsFound.add(expr);
+                        return true;
+                    }
+                    return false;
                 }
 
                 private boolean isParam(final String name) {
@@ -159,7 +162,7 @@
 
                 @Override
                 public Node leaveIdentNode(final IdentNode identNode) {
-                    if (isParam(identNode.getName()) || ARGUMENTS.equals(identNode.getName()) && !isCurrentArg(identNode)) {
+                    if (isParam(identNode.getName()) || isArguments(identNode) && !isCurrentArg(identNode)) {
                         throw uoe; //avoid filling in stack trace
                     }
                     return identNode;
@@ -186,7 +189,9 @@
                 }
             });
         } catch (final UnsupportedOperationException e) {
-            log.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
+            if (!argumentsFound.isEmpty()) {
+                log.fine("'arguments' is used but escapes, or is reassigned in '" + functionNode.getName() + "'. Aborting");
+            }
             return true; //bad
         }
 
@@ -267,9 +272,9 @@
             return false;
         }
 
-        if (!Global.instance().isSpecialNameValid("apply")) {
+        if (!Global.isBuiltinFunctionPrototypeApply()) {
             log.fine("Apply transform disabled: apply/call overridden");
-            assert !Global.instance().isSpecialNameValid("call") : "call and apply should have the same SwitchPoint";
+            assert !Global.isBuiltinFunctionPrototypeCall() : "call and apply should have the same SwitchPoint";
             return false;
         }
 
--- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -51,15 +51,14 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
-
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
-
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
@@ -160,8 +159,12 @@
         this.methodNames    = new HashSet<>();
     }
 
+    /**
+     * Return the method names encountered
+     * @return method names
+     */
     public Set<String> getMethodNames() {
-        return methodNames;
+        return Collections.unmodifiableSet(methodNames);
     }
 
     /**
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Oct 07 10:57:55 2014 -0700
@@ -104,6 +104,7 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessor;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
+import jdk.nashorn.internal.ir.JumpStatement;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LexicalContextNode;
@@ -1204,17 +1205,21 @@
 
     @Override
     public boolean enterBreakNode(final BreakNode breakNode) {
+        return enterJumpStatement(breakNode);
+    }
+
+    private boolean enterJumpStatement(final JumpStatement jump) {
         if(!method.isReachable()) {
             return false;
         }
-        enterStatement(breakNode);
-
-        method.beforeJoinPoint(breakNode);
-        final BreakableNode breakFrom = lc.getBreakable(breakNode.getLabelName());
-        popScopesUntil(breakFrom);
-        final Label breakLabel = breakFrom.getBreakLabel();
-        breakLabel.markAsBreakTarget();
-        method.splitAwareGoto(lc, breakLabel, breakFrom);
+        enterStatement(jump);
+
+        method.beforeJoinPoint(jump);
+        final BreakableNode target = jump.getTarget(lc);
+        popScopesUntil(target);
+        final Label targetLabel = jump.getTargetLabel(target);
+        targetLabel.markAsBreakTarget();
+        method.splitAwareGoto(lc, targetLabel, target);
 
         return false;
     }
@@ -1517,19 +1522,7 @@
 
     @Override
     public boolean enterContinueNode(final ContinueNode continueNode) {
-        if(!method.isReachable()) {
-            return false;
-        }
-        enterStatement(continueNode);
-        method.beforeJoinPoint(continueNode);
-
-        final LoopNode continueTo = lc.getContinueTo(continueNode.getLabelName());
-        popScopesUntil(continueTo);
-        final Label continueLabel = continueTo.getContinueLabel();
-        continueLabel.markAsBreakTarget();
-        method.splitAwareGoto(lc, continueLabel, continueTo);
-
-        return false;
+        return enterJumpStatement(continueNode);
     }
 
     @Override
@@ -2807,6 +2800,7 @@
         final boolean hasReturn = method.hasReturn();
         final SplitMethodEmitter splitMethod = ((SplitMethodEmitter)method);
         final List<Label> targets = splitMethod.getExternalTargets();
+        final boolean hasControlFlow = hasReturn || !targets.isEmpty();
         final List<BreakableNode> targetNodes  = splitMethod.getExternalTargetNodes();
         final Type returnType = lc.getCurrentFunction().getReturnType();
 
@@ -2814,6 +2808,9 @@
             // Wrap up this method.
 
             if(method.isReachable()) {
+                if (hasControlFlow) {
+                    method.setSplitState(-1);
+                }
                 method.loadCompilerConstant(RETURN, returnType);
                 method._return(returnType);
             }
@@ -2831,17 +2828,16 @@
             throw e;
         }
 
+        //no external jump targets or return in switch node
+        if (!hasControlFlow) {
+            return splitNode;
+        }
+
         // Handle return from split method if there was one.
         final MethodEmitter caller = method;
         final int     targetCount = targets.size();
 
-        //no external jump targets or return in switch node
-        if (!hasReturn && targets.isEmpty()) {
-            return splitNode;
-        }
-
-        caller.loadCompilerConstant(SCOPE);
-        caller.checkcast(Scope.class);
+        caller.loadScope();
         caller.invoke(Scope.GET_SPLIT_STATE);
 
         final Label breakLabel = new Label("no_split_state");
@@ -2873,19 +2869,16 @@
                     caller.loadCompilerConstant(RETURN, returnType);
                     caller._return(returnType);
                 } else {
-                    // Clear split state.
-                    caller.loadCompilerConstant(SCOPE);
-                    caller.checkcast(Scope.class);
-                    caller.load(-1);
-                    caller.invoke(Scope.SET_SPLIT_STATE);
                     final BreakableNode targetNode = targetNodes.get(i - 1);
                     final Label label = targets.get(i - 1);
-                    final JoinPredecessor jumpOrigin = splitNode.getJumpOrigin(label);
-                    if(jumpOrigin != null) {
-                        method.beforeJoinPoint(jumpOrigin);
+                    if (!lc.isExternalTarget(splitNode, targetNode)) {
+                        final JoinPredecessor jumpOrigin = splitNode.getJumpOrigin(label);
+                        if(jumpOrigin != null) {
+                            method.beforeJoinPoint(jumpOrigin);
+                        }
+                        popScopesUntil(targetNode);
                     }
-                    popScopesUntil(targetNode);
-                    caller.splitAwareGoto(lc, targets.get(i - 1), targetNode);
+                    caller.splitAwareGoto(lc, label, targetNode);
                 }
             }
             caller.label(breakLabel);
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue Oct 07 10:57:55 2014 -0700
@@ -38,7 +38,6 @@
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SYMBOLS_ASSIGNED;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.EnumSet;
@@ -48,7 +47,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-
 import jdk.nashorn.internal.AssertsEnabled;
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
 import jdk.nashorn.internal.ir.FunctionNode;
@@ -627,7 +625,7 @@
 
     /**
      * Start a compilation phase
-     * @param compiler
+     * @param compiler the compiler to use
      * @param functionNode function to compile
      * @return function node
      */
--- a/src/jdk/nashorn/internal/codegen/CompileUnit.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java	Tue Oct 07 10:57:55 2014 -0700
@@ -60,6 +60,10 @@
         emittedUnitCount++;
     }
 
+    /**
+     * Get the amount of emitted compile units so far in the system
+     * @return emitted compile unit count
+     */
     public static int getEmittedUnitCount() {
         return emittedUnitCount;
     }
@@ -72,6 +76,10 @@
         return isUsed;
     }
 
+    /**
+     * Check if a compile unit has code, not counting inits and clinits
+     * @return true of if there is "real code" in the compile unit
+     */
     public boolean hasCode() {
         return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
     }
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Oct 07 10:57:55 2014 -0700
@@ -32,7 +32,6 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
-
 import java.io.File;
 import java.lang.invoke.MethodType;
 import java.util.Arrays;
@@ -154,6 +153,13 @@
     private RecompilableScriptFunctionData compiledFunction;
 
     /**
+     * Most compile unit names are longer than the default StringBuilder buffer,
+     * worth startup performance when massive class generation is going on to increase
+     * this
+     */
+    private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
+
+    /**
      * Compilation phases that a compilation goes through
      */
     public static class CompilationPhases implements Iterable<CompilationPhase> {
@@ -452,12 +458,14 @@
 
     @Override
     public DebugLogger initLogger(final Context ctxt) {
+        final boolean optimisticTypes = ctxt.getEnv()._optimistic_types;
         return ctxt.getLogger(this.getClass(), new Consumer<DebugLogger>() {
             @Override
             public void accept(final DebugLogger newLogger) {
                 if (!Compiler.this.getScriptEnvironment()._lazy_compilation) {
                     newLogger.warning("WARNING: Running with lazy compilation switched off. This is not a default setting.");
                 }
+                newLogger.warning("Optimistic types are ", optimisticTypes ? "ENABLED." : "DISABLED.");
             }
         });
     }
@@ -535,9 +543,10 @@
      * @throws CompilationException if error occurs during compilation
      */
     public FunctionNode compile(final FunctionNode functionNode, final CompilationPhases phases) throws CompilationException {
-
-        log.finest("Starting compile job for ", DebugLogger.quote(functionNode.getName()), " phases=", quote(phases.getDesc()));
-        log.indent();
+        if (log.isEnabled()) {
+            log.info("Starting compile job for ", DebugLogger.quote(functionNode.getName()), " phases=", quote(phases.getDesc()));
+            log.indent();
+        }
 
         final String name = DebugLogger.quote(functionNode.getName());
 
@@ -554,7 +563,7 @@
         long time = 0L;
 
         for (final CompilationPhase phase : phases) {
-            log.fine(phase, " starting for ", quote(name));
+            log.fine(phase, " starting for ", name);
 
             try {
                 newFunctionNode = phase.apply(this, phases, newFunctionNode);
@@ -582,8 +591,11 @@
         log.unindent();
 
         if (info) {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("Compile job for ").append(newFunctionNode.getSource()).append(':').append(quote(newFunctionNode.getName())).append(" finished");
+            final StringBuilder sb = new StringBuilder("Finished compile job for ");
+            sb.append(newFunctionNode.getSource()).
+                append(':').
+                append(quote(newFunctionNode.getName()));
+
             if (time > 0L && timeLogger != null) {
                 assert env.isTimingEnabled();
                 sb.append(" in ").append(time).append(" ms");
@@ -631,7 +643,8 @@
     }
 
     String nextCompileUnitName() {
-        final StringBuilder sb = new StringBuilder(firstCompileUnitName);
+        final StringBuilder sb = new StringBuilder(COMPILE_UNIT_NAME_BUFFER_SIZE);
+        sb.append(firstCompileUnitName);
         final int cuid = nextCompileUnitId.getAndIncrement();
         if (cuid > 0) {
             sb.append("$cu").append(cuid);
--- a/src/jdk/nashorn/internal/codegen/Label.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/Label.java	Tue Oct 07 10:57:55 2014 -0700
@@ -590,8 +590,13 @@
         return label.getOffset() > other.label.getOffset();
     }
 
+    private String str;
+
     @Override
     public String toString() {
-        return name + '_' + id;
+        if (str == null) {
+            str = name + '_' + id;
+        }
+        return str;
     }
 }
--- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Tue Oct 07 10:57:55 2014 -0700
@@ -464,21 +464,20 @@
 
     @Override
     public boolean enterBreakNode(final BreakNode breakNode) {
-        if(!reachable) {
-            return false;
-        }
-
-        final BreakableNode target = lc.getBreakable(breakNode.getLabelName());
-        return splitAwareJumpToLabel(breakNode, target, target.getBreakLabel());
+        return enterJumpStatement(breakNode);
     }
 
     @Override
     public boolean enterContinueNode(final ContinueNode continueNode) {
+        return enterJumpStatement(continueNode);
+    }
+
+    private boolean enterJumpStatement(final JumpStatement jump) {
         if(!reachable) {
             return false;
         }
-        final LoopNode target = lc.getContinueTo(continueNode.getLabelName());
-        return splitAwareJumpToLabel(continueNode, target, target.getContinueLabel());
+        final BreakableNode target = jump.getTarget(lc);
+        return splitAwareJumpToLabel(jump, target, jump.getTargetLabel(target));
     }
 
     private boolean splitAwareJumpToLabel(final JumpStatement jumpStatement, final BreakableNode target, final Label targetLabel) {
--- a/src/jdk/nashorn/internal/codegen/Lower.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/Lower.java	Tue Oct 07 10:57:55 2014 -0700
@@ -52,6 +52,7 @@
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
+import jdk.nashorn.internal.ir.JumpStatement;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
@@ -382,12 +383,16 @@
 
             @Override
             public Node leaveBreakNode(final BreakNode breakNode) {
-                return copy(breakNode, (Node)Lower.this.lc.getBreakable(breakNode.getLabelName()));
+                return leaveJumpStatement(breakNode);
             }
 
             @Override
             public Node leaveContinueNode(final ContinueNode continueNode) {
-                return copy(continueNode, Lower.this.lc.getContinueTo(continueNode.getLabelName()));
+                return leaveJumpStatement(continueNode);
+            }
+
+            private Node leaveJumpStatement(final JumpStatement jump) {
+                return copy(jump, (Node)jump.getTarget(Lower.this.lc));
             }
 
             @Override
@@ -627,7 +632,7 @@
             @Override
             public Node leaveContinueNode(final ContinueNode node) {
                 // all inner loops have been popped.
-                if (lex.contains(lex.getContinueTo(node.getLabelName()))) {
+                if (lex.contains(node.getTarget(lex))) {
                     escapes.add(node);
                 }
                 return node;
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -71,7 +71,6 @@
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
-
 import java.io.PrintStream;
 import java.lang.reflect.Array;
 import java.util.Collection;
@@ -105,7 +104,9 @@
 import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.RewriteException;
+import jdk.nashorn.internal.runtime.Scope;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -180,9 +181,6 @@
     /** 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
@@ -1050,6 +1048,14 @@
         return load(getCompilerConstantSymbol(cc), type != null ? type : getCompilerConstantType(cc));
     }
 
+    MethodEmitter loadScope() {
+        return loadCompilerConstant(SCOPE).checkcast(Scope.class);
+    }
+
+    MethodEmitter setSplitState(final int state) {
+        return loadScope().load(state).invoke(Scope.SET_SPLIT_STATE);
+    }
+
     void storeCompilerConstant(final CompilerConstants cc) {
         storeCompilerConstant(cc, null);
     }
@@ -2131,10 +2137,15 @@
     }
 
     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);
+        switch (name) {
+        case "apply":
+        case "call":
+            debug("invalidate_name", "name=", name);
+            load("Function");
+            invoke(ScriptRuntime.INVALIDATE_RESERVED_BUILTIN_NAME);
+            break;
+        default:
+            break;
         }
         return this;
     }
@@ -2575,12 +2586,55 @@
      *
      * @param args debug information to print
      */
+    @SuppressWarnings("unused")
     private void debug(final Object... args) {
         if (debug) {
             debug(30, args);
         }
     }
 
+    private void debug(final String arg) {
+        if (debug) {
+            debug(30, arg);
+        }
+    }
+
+    private void debug(final Object arg0, final Object arg1) {
+        if (debug) {
+            debug(30, new Object[] { arg0, arg1 });
+        }
+    }
+
+    private void debug(final Object arg0, final Object arg1, final Object arg2) {
+        if (debug) {
+            debug(30, new Object[] { arg0, arg1, arg2 });
+        }
+    }
+
+    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3) {
+        if (debug) {
+            debug(30, new Object[] { arg0, arg1, arg2, arg3 });
+        }
+    }
+
+    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4) {
+        if (debug) {
+            debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4 });
+        }
+    }
+
+    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5) {
+        if (debug) {
+            debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5 });
+        }
+    }
+
+    private void debug(final Object arg0, final Object arg1, final Object arg2, final Object arg3, final Object arg4, final Object arg5, final Object arg6) {
+        if (debug) {
+            debug(30, new Object[] { arg0, arg1, arg2, arg3, arg4, arg5, arg6 });
+        }
+    }
+
     /**
      * Debug function that outputs generated bytecode and stack contents
      * for a label - indentation is currently the only thing that differs
--- a/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Tue Oct 07 10:57:55 2014 -0700
@@ -429,7 +429,6 @@
     }
 
     private static void doCleanup() throws IOException {
-        final long start = System.nanoTime();
         final Path[] files = getAllRegularFilesInLastModifiedOrder();
         final int nFiles = files.length;
         final int filesToDelete = Math.max(0, nFiles - MAX_FILES);
@@ -444,8 +443,7 @@
                 // does not increase filesDeleted
             }
             files[i] = null; // gc eligible
-        };
-        final long duration = System.nanoTime() - start;
+        }
     }
 
     private static Path[] getAllRegularFilesInLastModifiedOrder() throws IOException {
@@ -456,7 +454,7 @@
                 @Override
                 public boolean test(final Path path) {
                     return !Files.isDirectory(path);
-                };
+                }
             })
             .map(new Function<Path, PathAndTime>() {
                 @Override
@@ -497,7 +495,7 @@
         private static long getTime(final Path path) {
             try {
                 return Files.getLastModifiedTime(path).toMillis();
-            } catch (IOException e) {
+            } catch (final IOException e) {
                 // All files for which we can't retrieve the last modified date will be considered oldest.
                 return -1L;
             }
--- a/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,8 +25,6 @@
 
 package jdk.nashorn.internal.codegen;
 
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-
 import java.util.ArrayList;
 import java.util.List;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -34,7 +32,6 @@
 import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.SplitNode;
-import jdk.nashorn.internal.runtime.Scope;
 
 /**
  * Emitter used for splitting methods. Needs to keep track of if there are jump targets
@@ -65,15 +62,13 @@
         assert splitNode != null;
         final int index = findExternalTarget(lc, label, targetNode);
         if (index >= 0) {
-            loadCompilerConstant(SCOPE);
-            checkcast(Scope.class);
-            load(index + 1);
-            invoke(Scope.SET_SPLIT_STATE);
-            loadUndefined(Type.OBJECT);
-            _return(functionNode.getReturnType());
-            return;
+            setSplitState(index + 1); // 0 is ordinary return
+            final Type retType = functionNode.getReturnType();
+            loadUndefined(retType);
+            _return(retType);
+        } else {
+            super.splitAwareGoto(lc, label, targetNode);
         }
-        super.splitAwareGoto(lc, label, targetNode);
     }
 
     private int findExternalTarget(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
@@ -94,11 +89,7 @@
     @Override
     MethodEmitter registerReturn() {
         setHasReturn();
-        loadCompilerConstant(SCOPE);
-        checkcast(Scope.class);
-        load(0);
-        invoke(Scope.SET_SPLIT_STATE);
-        return this;
+        return setSplitState(0);
     }
 
     final List<Label> getExternalTargets() {
--- a/src/jdk/nashorn/internal/codegen/types/Type.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java	Tue Oct 07 10:57:55 2014 -0700
@@ -47,7 +47,6 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
 import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
-
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
@@ -55,8 +54,10 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.Collections;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import jdk.internal.org.objectweb.asm.Handle;
@@ -104,6 +105,16 @@
     /** The class for this type */
     private final Class<?> clazz;
 
+    /**
+     * Cache for internal types - this is a query that requires complex stringbuilding inside
+     * ASM and it saves startup time to cache the type mappings
+     */
+    private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE =
+            Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>());
+
+    /** Internal ASM type for this Type - computed once at construction */
+    private final jdk.internal.org.objectweb.asm.Type internalType;
+
     /** Weights are used to decide which types are "wider" than other types */
     protected static final int MIN_WEIGHT = -1;
 
@@ -122,12 +133,13 @@
      * @param slots       how many bytecode slots the type takes up
      */
     Type(final String name, final Class<?> clazz, final int weight, final int slots) {
-        this.name       = name;
-        this.clazz      = clazz;
-        this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
-        this.weight     = weight;
+        this.name         = name;
+        this.clazz        = clazz;
+        this.descriptor   = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
+        this.weight       = weight;
         assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
-        this.slots      = slots;
+        this.slots        = slots;
+        this.internalType = getInternalType(clazz);
     }
 
     /**
@@ -299,7 +311,7 @@
      *
      * @param typeMap the type map
      * @param output data output
-     * @throws IOException
+     * @throws IOException if write cannot be completed
      */
     public static void writeTypeMap(final Map<Integer, Type> typeMap, final DataOutput output) throws IOException {
         if (typeMap == null) {
@@ -329,7 +341,7 @@
      *
      * @param input data input
      * @return type map
-     * @throws IOException
+     * @throws IOException if read cannot be completed
      */
     public static Map<Integer, Type> readTypeMap(final DataInput input) throws IOException {
         final int size = input.readInt();
@@ -357,11 +369,22 @@
     }
 
     private jdk.internal.org.objectweb.asm.Type getInternalType() {
-        return jdk.internal.org.objectweb.asm.Type.getType(getTypeClass());
+        return internalType;
+    }
+
+    private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) {
+        final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> cache = INTERNAL_TYPE_CACHE;
+        jdk.internal.org.objectweb.asm.Type itype = cache.get(type);
+        if (itype != null) {
+            return itype;
+        }
+        itype = jdk.internal.org.objectweb.asm.Type.getType(type);
+        cache.put(type, itype);
+        return itype;
     }
 
     private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) {
-        return jdk.internal.org.objectweb.asm.Type.getType(type);
+        return lookupInternalType(type);
     }
 
     static void invokestatic(final MethodVisitor method, final Call call) {
--- a/src/jdk/nashorn/internal/ir/BreakNode.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
@@ -68,4 +69,14 @@
     String getStatementName() {
         return "break";
     }
+
+    @Override
+    public BreakableNode getTarget(final LexicalContext lc) {
+        return lc.getBreakable(getLabelName());
+    }
+
+    @Override
+    public Label getTargetLabel(final BreakableNode target) {
+        return target.getBreakLabel();
+    }
 }
--- a/src/jdk/nashorn/internal/ir/ContinueNode.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
@@ -67,5 +68,16 @@
     String getStatementName() {
         return "continue";
     }
+
+
+    @Override
+    public BreakableNode getTarget(final LexicalContext lc) {
+        return lc.getContinueTo(getLabelName());
+    }
+
+    @Override
+    public Label getTargetLabel(final BreakableNode target) {
+        return ((LoopNode)target).getContinueLabel();
+    }
 }
 
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue Oct 07 10:57:55 2014 -0700
@@ -238,17 +238,21 @@
      * Note that even IS_STRICT is one such flag but that requires special handling.
      */
 
-    // parser, lower debugging this function
+    /** parser, print parse tree */
     public static final int IS_PRINT_PARSE       = 1 << 18;
+    /** parser, print lower parse tree */
     public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
+    /** parser, print AST */
     public static final int IS_PRINT_AST         = 1 << 20;
+    /** parser, print lower AST */
     public static final int IS_PRINT_LOWER_AST   = 1 << 21;
+    /** parser, print symbols */
     public static final int IS_PRINT_SYMBOLS     = 1 << 22;
 
+    // callsite tracing, profiling within this function
     /** profile callsites in this function? */
     public static final int IS_PROFILE         = 1 << 23;
 
-    // callsite tracing, profiling within this function
     /** trace callsite enterexit in this function? */
     public static final int IS_TRACE_ENTEREXIT = 1 << 24;
 
@@ -337,7 +341,7 @@
     private FunctionNode(
         final FunctionNode functionNode,
         final long lastToken,
-        Object endParserState,
+        final Object endParserState,
         final int flags,
         final String name,
         final Type returnType,
--- a/src/jdk/nashorn/internal/ir/JumpStatement.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/JumpStatement.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,6 +25,8 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.codegen.Label;
+
 /**
  * Common base class for jump statements (e.g. {@code break} and {@code continue}).
  */
@@ -82,6 +84,24 @@
 
     abstract String getStatementName();
 
+    /**
+     * Finds the target for this jump statement in a lexical context.
+     * @param lc the lexical context
+     * @return the target, or null if not found
+     */
+    public abstract BreakableNode getTarget(final LexicalContext lc);
+
+    /**
+     * Returns the label corresponding to this kind of jump statement (either a break or continue label) in the target.
+     * @param target the target. Note that it need not be the target of this jump statement, as the method can retrieve
+     * a label on any passed target as long as the target has a label of the requisite kind. Of course, it is advisable
+     * to invoke the method on a jump statement that targets the breakable.
+     * @return the label of the target corresponding to the kind of jump statement.
+     * @throws ClassCastException if invoked on the kind of breakable node that this jump statement is not prepared to
+     * handle.
+     */
+    public abstract Label getTargetLabel(final BreakableNode target);
+
     @Override
     public JumpStatement setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) {
         if(this.conversion == conversion) {
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue Oct 07 10:57:55 2014 -0700
@@ -237,6 +237,10 @@
         return value;
     }
 
+    private static Expression[] valueToArray(final List<Expression> value) {
+        return value.toArray(new Expression[value.size()]);
+    }
+
     /**
      * Create a new null literal
      *
@@ -981,10 +985,9 @@
      * @return the new literal node
      */
     public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final List<Expression> value) {
-        return new ArrayLiteralNode(token, finish, value.toArray(new Expression[value.size()]));
+        return new ArrayLiteralNode(token, finish, valueToArray(value));
     }
 
-
     /**
      * Create a new array literal based on a parent node (source, token, finish)
      *
@@ -994,7 +997,7 @@
      * @return the new literal node
      */
     public static LiteralNode<?> newInstance(final Node parent, final List<Expression> value) {
-        return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Expression[value.size()]));
+        return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), valueToArray(value));
     }
 
     /**
--- a/src/jdk/nashorn/internal/ir/Symbol.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/Symbol.java	Tue Oct 07 10:57:55 2014 -0700
@@ -448,14 +448,25 @@
         return (flags & IS_FUNCTION_SELF) != 0;
     }
 
+    /**
+     * Is this a block scoped symbol
+     * @return true if block scoped
+     */
     public boolean isBlockScoped() {
         return isLet() || isConst();
     }
 
+    /**
+     * Has this symbol been declared
+     * @return true if declared
+     */
     public boolean hasBeenDeclared() {
         return (flags & HAS_BEEN_DECLARED) != 0;
     }
 
+    /**
+     * Mark this symbol as declared
+     */
     public void setHasBeenDeclared() {
         if (!hasBeenDeclared()) {
             flags |= HAS_BEEN_DECLARED;
--- a/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Tue Oct 07 10:57:55 2014 -0700
@@ -116,6 +116,10 @@
 
     private static final String VOID_TAG = "[VOID]";
 
+    private static void err(final String str) {
+        Context.getContext().getErr().println(str);
+    }
+
     /**
      * Tracer that is applied before a value is returned from the traced function. It will output the return
      * value and its class
@@ -124,13 +128,16 @@
      * @return return value unmodified
      */
     static Object traceReturn(final DebugLogger logger, final Object value) {
-        if (logger.isEnabled()) {
-            final String str = "    return" +
-                    (VOID_TAG.equals(value) ?
-                        ";" :
-                        " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
+        final String str = "    return" +
+                (VOID_TAG.equals(value) ?
+                    ";" :
+                    " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
+        if (logger == null) {
+            err(str);
+        } else if (logger.isEnabled()) {
             logger.log(TRACE_LEVEL, str);
         }
+
         return value;
     }
 
@@ -169,8 +176,11 @@
             }
         }
 
-        assert logger != null;
-        logger.log(TRACE_LEVEL, sb);
+        if (logger == null) {
+            err(sb.toString());
+        } else {
+            logger.log(TRACE_LEVEL, sb);
+        }
         stacktrace(logger);
     }
 
@@ -181,7 +191,12 @@
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         final PrintStream ps = new PrintStream(baos);
         new Throwable().printStackTrace(ps);
-        logger.log(TRACE_LEVEL, baos.toString());
+        final String st = baos.toString();
+        if (logger == null) {
+            err(st);
+        } else {
+            logger.log(TRACE_LEVEL, st);
+        }
     }
 
     private static String argString(final Object arg) {
@@ -201,7 +216,7 @@
         if (arg instanceof ScriptObject) {
             return arg.toString() +
                 " (map=" + Debug.id(((ScriptObject)arg).getMap()) +
-                ")";
+                ')';
         }
 
         return arg.toString();
@@ -209,6 +224,18 @@
 
     /**
      * Add a debug printout to a method handle, tracing parameters and return values
+     * Output will be unconditional to stderr
+     *
+     * @param mh  method handle to trace
+     * @param tag start of trace message
+     * @return traced method handle
+     */
+    public static MethodHandle addDebugPrintout(final MethodHandle mh, final Object tag) {
+        return addDebugPrintout(null, Level.OFF, mh, 0, true, tag);
+    }
+
+    /**
+     * Add a debug printout to a method handle, tracing parameters and return values
      *
      * @param logger a specific logger to which to write the output
      * @param level level over which to print
@@ -222,6 +249,20 @@
 
     /**
      * Add a debug printout to a method handle, tracing parameters and return values
+     * Output will be unconditional to stderr
+     *
+     * @param mh  method handle to trace
+     * @param paramStart first param to print/trace
+     * @param printReturnValue should we print/trace return value if available?
+     * @param tag start of trace message
+     * @return  traced method handle
+     */
+    public static MethodHandle addDebugPrintout(final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) {
+        return addDebugPrintout(null, Level.OFF, mh, paramStart, printReturnValue, tag);
+    }
+
+     /**
+     * Add a debug printout to a method handle, tracing parameters and return values
      *
      * @param logger a specific logger to which to write the output
      * @param level level over which to print
@@ -240,7 +281,6 @@
             return mh;
         }
 
-        assert logger != null;
         assert TRACE != null;
 
         MethodHandle trace = MethodHandles.insertArguments(TRACE, 0, logger, tag, paramStart);
@@ -428,6 +468,12 @@
         }
 
         @Override
+        public MethodHandle identity(final Class<?> type) {
+            final MethodHandle mh = MethodHandles.identity(type);
+            return debug(mh, "identity", type);
+        }
+
+        @Override
         public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
             final MethodHandle mh = handle.asCollector(arrayType, arrayLength);
             return debug(mh, "asCollector", handle, arrayType, arrayLength);
--- a/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Tue Oct 07 10:57:55 2014 -0700
@@ -173,6 +173,15 @@
     public MethodHandle constant(Class<?> type, Object value);
 
     /**
+     * Wrapper for {@link java.lang.invoke.MethodHandles#identity(Class)}
+     *
+     * @param type  type of value
+     *
+     * @return method handle that returns identity argument
+     */
+    public MethodHandle identity(Class<?> type);
+
+    /**
      * Wrapper for {@link java.lang.invoke.MethodHandle#asType(MethodType)}
      *
      * @param handle  method handle for type conversion
--- a/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Tue Oct 07 10:57:55 2014 -0700
@@ -31,6 +31,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
--- a/src/jdk/nashorn/internal/objects/Global.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/Global.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,23 +25,19 @@
 
 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.referenceError;
 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.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
@@ -52,8 +48,6 @@
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.nashorn.api.scripting.ClassFilter;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
-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;
@@ -72,6 +66,7 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.ScriptingFunctions;
+import jdk.nashorn.internal.runtime.Specialization;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -107,10 +102,6 @@
      * 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);
 
     /** Nashorn extension: arguments array */
     @Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
@@ -428,9 +419,6 @@
     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$;
 
@@ -482,7 +470,6 @@
         super(checkAndGetMap(context));
         this.context = context;
         this.setIsScope();
-        this.optimisticFunctionMap = new HashMap<>();
         //we can only share one instance of Global constants between globals, or we consume way too much
         //memory - this is good enough for most programs
         while (gcsInstance.get() == null) {
@@ -574,6 +561,7 @@
      *
      * @param engine ScriptEngine to initialize
      */
+    @SuppressWarnings("hiding")
     public void initBuiltinObjects(final ScriptEngine engine) {
         if (this.builtinObject != null) {
             // already initialized, just return
@@ -918,10 +906,12 @@
         }
 
         switch (nameStr) {
-            case "context":
-                return sctxt;
-            case "engine":
-                return global.engine;
+        case "context":
+            return sctxt;
+        case "engine":
+            return global.engine;
+        default:
+            break;
         }
 
         if (self == UNDEFINED) {
@@ -1244,6 +1234,40 @@
         return instance.function == instance.getBuiltinFunction();
     }
 
+    /**
+     * Get the switchpoint used to check property changes for Function.prototype.apply
+     * @return the switchpoint guarding apply (same as guarding call, and everything else in function)
+     */
+    public static SwitchPoint getBuiltinFunctionApplySwitchPoint() {
+        return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint();
+    }
+
+    private static boolean isBuiltinFunctionProperty(final String name) {
+        final Global instance = Global.instance();
+        final ScriptFunction builtinFunction = instance.getBuiltinFunction();
+        if (builtinFunction == null) {
+            return false; //conservative for compile-only mode
+        }
+        final boolean isBuiltinFunction = instance.function == builtinFunction;
+        return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin();
+    }
+
+    /**
+     * Check if the Function.prototype.apply has not been replaced
+     * @return true if Function.prototype.apply has been replaced
+     */
+    public static boolean isBuiltinFunctionPrototypeApply() {
+        return isBuiltinFunctionProperty("apply");
+    }
+
+    /**
+     * Check if the Function.prototype.apply has not been replaced
+     * @return true if Function.prototype.call has been replaced
+     */
+    public static boolean isBuiltinFunctionPrototypeCall() {
+        return isBuiltinFunctionProperty("call");
+    }
+
     private ScriptFunction getBuiltinJSAdapter() {
         return builtinJSAdapter;
     }
@@ -1688,6 +1712,13 @@
         splitState = state;
     }
 
+    private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
+        final T func = initConstructor(name, clazz);
+        tagBuiltinProperties(name, func);
+        return func;
+    }
+
+    @SuppressWarnings("hiding")
     private void init(final ScriptEngine engine) {
         assert Context.getGlobal() == this : "this global is not set as current";
 
@@ -1702,8 +1733,19 @@
         // initialize global function properties
         this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
 
-        this.parseInt           = ScriptFunctionImpl.makeFunction("parseInt",   GlobalFunctions.PARSEINT,
-                new MethodHandle[] { GlobalFunctions.PARSEINT_OI, GlobalFunctions.PARSEINT_O });
+        this.parseInt = ScriptFunctionImpl.makeFunction("parseInt",   GlobalFunctions.PARSEINT,
+                    new Specialization[] {
+                    new Specialization(GlobalFunctions.PARSEINT_Z),
+                    new Specialization(GlobalFunctions.PARSEINT_I),
+                    new Specialization(GlobalFunctions.PARSEINT_J),
+                    new Specialization(GlobalFunctions.PARSEINT_OI),
+                    new Specialization(GlobalFunctions.PARSEINT_O) });
+        this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
+        this.isNaN = ScriptFunctionImpl.makeFunction("isNaN",   GlobalFunctions.IS_NAN,
+                   new Specialization[] {
+                        new Specialization(GlobalFunctions.IS_NAN_I),
+                        new Specialization(GlobalFunctions.IS_NAN_J),
+                        new Specialization(GlobalFunctions.IS_NAN_D) });
         this.parseFloat         = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
         this.isNaN              = ScriptFunctionImpl.makeFunction("isNaN",      GlobalFunctions.IS_NAN);
         this.isFinite           = ScriptFunctionImpl.makeFunction("isFinite",   GlobalFunctions.IS_FINITE);
@@ -1720,15 +1762,15 @@
         this.quit               = ScriptFunctionImpl.makeFunction("quit",       EXIT);
 
         // built-in constructors
-        this.builtinArray     = initConstructor("Array", ScriptFunction.class);
-        this.builtinBoolean   = initConstructor("Boolean", ScriptFunction.class);
-        this.builtinDate      = initConstructor("Date", ScriptFunction.class);
-        this.builtinJSON      = initConstructor("JSON", ScriptObject.class);
-        this.builtinJSAdapter = initConstructor("JSAdapter", ScriptFunction.class);
-        this.builtinMath      = initConstructor("Math", ScriptObject.class);
-        this.builtinNumber    = initConstructor("Number", ScriptFunction.class);
-        this.builtinRegExp    = initConstructor("RegExp", ScriptFunction.class);
-        this.builtinString    = initConstructor("String", ScriptFunction.class);
+        this.builtinArray     = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
+        this.builtinBoolean   = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class);
+        this.builtinDate      = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
+        this.builtinJSON      = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
+        this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class);
+        this.builtinMath      = initConstructorAndSwitchPoint("Math", ScriptObject.class);
+        this.builtinNumber    = initConstructorAndSwitchPoint("Number", ScriptFunction.class);
+        this.builtinRegExp    = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
+        this.builtinString    = initConstructorAndSwitchPoint("String", ScriptFunction.class);
 
         // initialize String.prototype.length to 0
         // add String.prototype.length
@@ -1830,6 +1872,8 @@
         // Error.prototype.message = "";
         errorProto.set(NativeError.MESSAGE, "", 0);
 
+        tagBuiltinProperties("Error", builtinError);
+
         this.builtinEvalError = initErrorSubtype("EvalError", errorProto);
         this.builtinRangeError = initErrorSubtype("RangeError", errorProto);
         this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto);
@@ -1844,6 +1888,7 @@
         prototype.set(NativeError.NAME, name, 0);
         prototype.set(NativeError.MESSAGE, "", 0);
         prototype.setInitialProto(errorProto);
+        tagBuiltinProperties(name, cons);
         return cons;
     }
 
@@ -1910,17 +1955,18 @@
     }
 
     private void initTypedArray() {
-        this.builtinArrayBuffer       = initConstructor("ArrayBuffer", ScriptFunction.class);
-        this.builtinDataView          = initConstructor("DataView", ScriptFunction.class);
-        this.builtinInt8Array         = initConstructor("Int8Array", ScriptFunction.class);
-        this.builtinUint8Array        = initConstructor("Uint8Array", ScriptFunction.class);
-        this.builtinUint8ClampedArray = initConstructor("Uint8ClampedArray", ScriptFunction.class);
-        this.builtinInt16Array        = initConstructor("Int16Array", ScriptFunction.class);
-        this.builtinUint16Array       = initConstructor("Uint16Array", ScriptFunction.class);
-        this.builtinInt32Array        = initConstructor("Int32Array", ScriptFunction.class);
-        this.builtinUint32Array       = initConstructor("Uint32Array", ScriptFunction.class);
-        this.builtinFloat32Array      = initConstructor("Float32Array", ScriptFunction.class);
-        this.builtinFloat64Array      = initConstructor("Float64Array", ScriptFunction.class);
+        this.builtinArrayBuffer       = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
+        this.builtinDataView          = initConstructorAndSwitchPoint("DataView", ScriptFunction.class);
+        this.builtinInt8Array         = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class);
+        this.builtinUint8Array        = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class);
+        this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class);
+        this.builtinInt16Array        = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class);
+        this.builtinUint16Array       = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class);
+        this.builtinInt32Array        = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class);
+        this.builtinUint32Array       = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class);
+        this.builtinFloat32Array      = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class);
+        this.builtinFloat64Array      = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class);
+
     }
 
     private void copyBuiltins() {
@@ -1993,10 +2039,6 @@
         return UNDEFINED;
     }
 
-    /**
-     * These classes are generated by nasgen tool and so we have to use
-     * reflection to load and create new instance of these classes.
-     */
     private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
         try {
             // Assuming class name pattern for built-in JS constructors.
@@ -2021,12 +2063,52 @@
             }
 
             res.setIsBuiltin();
+
             return res;
         } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
             throw new RuntimeException(e);
         }
     }
 
+    private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
+        final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
+
+        list.addAll(Arrays.asList(func.getMap().getProperties()));
+
+        if (func instanceof ScriptFunction) {
+            final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func);
+            if (proto != null) {
+                list.addAll(Arrays.asList(proto.getMap().getProperties()));
+            }
+        }
+
+        final jdk.nashorn.internal.runtime.Property prop = getProperty(name);
+        if (prop != null) {
+            list.add(prop);
+        }
+
+        return list;
+    }
+
+    /**
+     * Given a builtin object, traverse its properties recursively and associate them with a name that
+     * will be a key to their invalidation switchpoint.
+     * @param name name for key
+     * @param func builtin script object
+     */
+    private void tagBuiltinProperties(final String name, final ScriptObject func) {
+        SwitchPoint sp = context.getBuiltinSwitchPoint(name);
+        if (sp == null) {
+            sp = context.newBuiltinSwitchPoint(name);
+        }
+
+        //get all builtin properties in this builtin object and register switchpoints keyed on the propery name,
+        //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc
+        for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) {
+            prop.setBuiltinSwitchPoint(sp);
+        }
+    }
+
     // Function and Object constructors are inter-dependent. Also,
     // Function.prototype
     // functions are not properly initialized. We fix the references here.
@@ -2035,7 +2117,8 @@
     // to play with object references carefully!!
     private void initFunctionAndObject() {
         // First-n-foremost is Function
-        this.builtinFunction      = initConstructor("Function", ScriptFunction.class);
+
+        this.builtinFunction = initConstructor("Function", ScriptFunction.class);
 
         // create global anonymous function
         final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction();
@@ -2101,13 +2184,6 @@
             }
         }
 
-        //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) {
@@ -2125,10 +2201,10 @@
                 }
             }
         }
-    }
 
-    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));
+        tagBuiltinProperties("Object", builtinObject);
+        tagBuiltinProperties("Function", builtinFunction);
+        tagBuiltinProperties("Function", anon);
     }
 
     private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
@@ -2147,62 +2223,4 @@
     protected boolean isGlobal() {
         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-&gt;call specialization
-     * @param name property name
-     */
-    public void invalidateReservedName(final String name) {
-        final SwitchPoint sp = getChangeCallback(name);
-        if (sp != null) {
-            getContext().getLogger(ApplySpecialization.class).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/NativeArray.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java	Tue Oct 07 10:57:55 2014 -0700
@@ -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
@@ -33,8 +33,8 @@
 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
-
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.SwitchPoint;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -52,12 +52,13 @@
 import jdk.nashorn.internal.objects.annotations.Getter;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.objects.annotations.Setter;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.OptimisticBuiltins;
 import jdk.nashorn.internal.runtime.PropertyDescriptor;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptFunction;
@@ -67,17 +68,20 @@
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
+import jdk.nashorn.internal.runtime.arrays.ContinuousArrayData;
+import jdk.nashorn.internal.runtime.arrays.IntElements;
+import jdk.nashorn.internal.runtime.arrays.IntOrLongElements;
 import jdk.nashorn.internal.runtime.arrays.IteratorAction;
+import jdk.nashorn.internal.runtime.arrays.NumericElements;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 
 /**
  * Runtime representation of a JavaScript array. NativeArray only holds numeric
  * keyed values. All other values are stored in spill.
  */
 @ScriptClass("Array")
-public final class NativeArray extends ScriptObject {
+public final class NativeArray extends ScriptObject implements OptimisticBuiltins {
     private static final Object JOIN                     = new Object();
     private static final Object EVERY_CALLBACK_INVOKER   = new Object();
     private static final Object SOME_CALLBACK_INVOKER    = new Object();
@@ -88,6 +92,16 @@
     private static final Object CALL_CMP                 = new Object();
     private static final Object TO_LOCALE_STRING         = new Object();
 
+    private SwitchPoint   lengthMadeNotWritableSwitchPoint;
+    private PushLinkLogic pushLinkLogic;
+    private PopLinkLogic  popLinkLogic;
+
+    /**
+     * Index for the modification SwitchPoint that triggers when length
+     * becomes not writable
+     */
+    private static final int LENGTH_NOT_WRITABLE_SWITCHPOINT = 0;
+
     /*
      * Constructors.
      */
@@ -420,6 +434,28 @@
         return getArray().asObjectArray();
     }
 
+    @Override
+    public void setIsLengthNotWritable() {
+        super.setIsLengthNotWritable();
+        /*
+         * Switchpoints are created lazily. If we link any push or pop site,
+         * we need to create the "length made not writable" switchpoint, if it
+         * doesn't exist.
+         *
+         * If the switchpoint already exists, we will find it here, and invalidate
+         * it, invalidating all previous callsites that use it.
+         *
+         * If the switchpoint doesn't exist, no push/pop has been linked so far,
+         * because that would create it too. We invalidate it immediately and the
+         * check link logic for all future callsites will fail immediately at link
+         * time
+         */
+        if (lengthMadeNotWritableSwitchPoint == null) {
+            lengthMadeNotWritableSwitchPoint = new SwitchPoint();
+        }
+        SwitchPoint.invalidateAll(new SwitchPoint[] { lengthMadeNotWritableSwitchPoint });
+    }
+
     /**
      * ECMA 15.4.3.2 Array.isArray ( arg )
      *
@@ -638,7 +674,7 @@
      * @param self   self reference
      * @return the new NativeArray
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeArray construct(final boolean newObj, final Object self) {
         return new NativeArray(0);
     }
@@ -653,7 +689,7 @@
      * @param element first element
      * @return the new NativeArray
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static Object construct(final boolean newObj, final Object self, final boolean element) {
         return new NativeArray(new Object[] { element });
     }
@@ -668,7 +704,7 @@
      * @param length array length
      * @return the new NativeArray
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeArray construct(final boolean newObj, final Object self, final int length) {
         if (length >= 0) {
             return new NativeArray(length);
@@ -687,7 +723,7 @@
      * @param length array length
      * @return the new NativeArray
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeArray construct(final boolean newObj, final Object self, final long length) {
         if (length >= 0L && length <= JSType.MAX_UINT) {
             return new NativeArray(length);
@@ -706,7 +742,7 @@
      * @param length array length
      * @return the new NativeArray
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeArray construct(final boolean newObj, final Object self, final double length) {
         final long uint32length = JSType.toUint32(length);
 
@@ -721,7 +757,7 @@
      * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
      *
      * @param self self reference
-     * @param args arguments to concat
+     * @param args arguments
      * @return resulting NativeArray
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
@@ -793,6 +829,68 @@
     }
 
     /**
+     * Specialization of pop for ContinuousArrayData
+     *   The link guard checks that the array is continuous AND not empty.
+     *   The runtime guard checks that the guard is continuous (CCE otherwise)
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @return element popped
+     * @throws ClassCastException if array is empty, facilitating Undefined return value
+     */
+    @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+    public static int popInt(final Object self) {
+        //must be non empty IntArrayData
+        return getContinuousNonEmptyArrayDataCCE(self, IntElements.class).fastPopInt();
+    }
+
+    /**
+     * Specialization of pop for ContinuousArrayData
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @return element popped
+     * @throws ClassCastException if array is empty, facilitating Undefined return value
+     */
+    @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+    public static long popLong(final Object self) {
+        //must be non empty Int or LongArrayData
+        return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong();
+    }
+
+    /**
+     * Specialization of pop for ContinuousArrayData
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @return element popped
+     * @throws ClassCastException if array is empty, facilitating Undefined return value
+     */
+    @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+    public static double popDouble(final Object self) {
+        //must be non empty int long or double array data
+        return getContinuousNonEmptyArrayDataCCE(self, NumericElements.class).fastPopDouble();
+    }
+
+    /**
+     * Specialization of pop for ContinuousArrayData
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @return element popped
+     * @throws ClassCastException if array is empty, facilitating Undefined return value
+     */
+    @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+    public static Object popObject(final Object self) {
+        //can be any data, because the numeric ones will throw cce and force relink
+        return getContinuousArrayDataCCE(self, null).fastPopObject();
+    }
+
+    /**
      * ECMA 15.4.4.6 Array.prototype.pop ()
      *
      * @param self self reference
@@ -829,6 +927,62 @@
     /**
      * ECMA 15.4.4.7 Array.prototype.push (args...)
      *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @param arg a primitive to push
+     * @return array length after push
+     */
+    @SpecializedFunction(linkLogic=PushLinkLogic.class)
+    public static long push(final Object self, final int arg) {
+        return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg);
+    }
+
+    /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...)
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @param arg a primitive to push
+     * @return array length after push
+     */
+    @SpecializedFunction(linkLogic=PushLinkLogic.class)
+    public static long push(final Object self, final long arg) {
+        return getContinuousArrayDataCCE(self, Long.class).fastPush(arg);
+    }
+
+    /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...)
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @param arg a primitive to push
+     * @return array length after push
+     */
+    @SpecializedFunction(linkLogic=PushLinkLogic.class)
+    public static long push(final Object self, final double arg) {
+        return getContinuousArrayDataCCE(self, Double.class).fastPush(arg);
+    }
+
+    /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...)
+     *
+     * Primitive specialization, {@link LinkLogic}
+     *
+     * @param self self reference
+     * @param arg a primitive to push
+     * @return array length after push
+     */
+    @SpecializedFunction(name="push", linkLogic=PushLinkLogic.class)
+    public static long pushObject(final Object self, final Object arg) {
+        return getContinuousArrayDataCCE(self, Object.class).fastPush(arg);
+    }
+
+    /**
+     * ECMA 15.4.4.7 Array.prototype.push (args...)
+     *
      * @param self self reference
      * @param args arguments to push
      * @return array length after pushes
@@ -857,61 +1011,6 @@
     }
 
     /**
-     * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single int argument
-     *
-     * @param self self reference
-     * @param arg argument to push
-     * @return array after pushes
-     */
-/*    @SpecializedFunction
-    public static long push(final Object self, final int arg) {
-        try {
-            final ScriptObject sobj = (ScriptObject)self;
-            final ArrayData arrayData = sobj.getArray();
-            final long length = arrayData.length();
-
-            if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
-                sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
-                return length + 1;
-            }
-
-            long len = JSType.toUint32(sobj.getLength());
-            sobj.set(len++, arg, true);
-            sobj.set("length", len, true);
-            return len;
-        } catch (final ClassCastException | NullPointerException e) {
-            throw typeError("not.an.object", ScriptRuntime.safeToString(self));
-        }
-    }
-*/
-    /**
-     * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single number argument
-     *
-     * @param self self reference
-     * @param arg argument to push
-     * @return array after pushes
-     */
- /*   @SpecializedFunction
-    public static long push(final Object self, final double arg) {
-        try {
-            final ScriptObject sobj = (ScriptObject)self;        final ArrayData arrayData = sobj.getArray();
-            final long length = arrayData.length();
-
-            if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
-                sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
-                return length + 1;
-            }
-
-            long len = JSType.toUint32(sobj.getLength());
-            sobj.set(len++, arg, true);
-            sobj.set("length", len, true);
-            return len;
-        } catch (final ClassCastException | NullPointerException e) {
-            throw typeError("not.an.object", ScriptRuntime.safeToString(self));
-        }
-    }
-*/
-    /**
      * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument
      *
      * @param self self reference
@@ -925,7 +1024,7 @@
             final ArrayData arrayData = sobj.getArray();
             final long length = arrayData.length();
             if (bulkable(sobj) && length < JSType.MAX_UINT) {
-                sobj.setArray(arrayData.push(true, arg)); //ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+                sobj.setArray(arrayData.push(true, arg));
                 return length + 1;
             }
 
@@ -1584,6 +1683,192 @@
 
     @Override
     public String toString() {
-        return "NativeArray@" + Debug.id(this) + '@' + getArray().getClass().getSimpleName();
+        return "NativeArray@" + Debug.id(this) + " [" + getArray().getClass().getSimpleName() + ']';
+    }
+
+    @Override
+    public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
+        if (clazz == PushLinkLogic.class) {
+            return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
+        } else if (clazz == PopLinkLogic.class) {
+            return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
+        }
+        return null;
+    }
+
+    @Override
+    public boolean hasPerInstanceAssumptions() {
+        return true; //length switchpoint
+    }
+
+    /**
+     * This is an abstract super class that contains common functionality for all
+     * specialized optimistic builtins in NativeArray. For example, it handles the
+     * modification switchpoint which is touched when length is written.
+     */
+    private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic {
+        private final NativeArray array;
+
+        protected ArrayLinkLogic(final NativeArray array) {
+            this.array = array;
+        }
+
+        private SwitchPoint getSwitchPoint() {
+            return array.lengthMadeNotWritableSwitchPoint;
+        }
+
+        private SwitchPoint newSwitchPoint() {
+            assert array.lengthMadeNotWritableSwitchPoint == null;
+            final SwitchPoint sp = new SwitchPoint();
+            array.lengthMadeNotWritableSwitchPoint = sp;
+            return sp;
+        }
+
+        protected static ContinuousArrayData getContinuousArrayData(final Object self) {
+            try {
+                //cast to NativeArray, to avoid cases like x = {0:0, 1:1}, x.length = 2, where we can't use the array push/pop
+                return (ContinuousArrayData)((NativeArray)self).getArray();
+            } catch (final Exception e) {
+                return null;
+            }
+        }
+
+        /**
+         * Push and pop callsites can throw ClassCastException as a mechanism to have them
+         * relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
+         * for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
+         */
+        @Override
+        public Class<? extends Throwable> getRelinkException() {
+            return ClassCastException.class;
+        }
+
+        @Override
+        public boolean hasModificationSwitchPoints() {
+            return getSwitchPoint() != null;
+        }
+
+        @Override
+        public boolean hasModificationSwitchPoint(final int index) {
+            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+            return hasModificationSwitchPoints();
+        }
+
+        @Override
+        public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
+            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+            SwitchPoint sp = getSwitchPoint();
+            if (sp == null) {
+                sp = newSwitchPoint();
+            }
+            return sp;
+        }
+
+        @Override
+        public SwitchPoint[] getOrCreateModificationSwitchPoints() {
+            return new SwitchPoint[] { getOrCreateModificationSwitchPoint(LENGTH_NOT_WRITABLE_SWITCHPOINT) };
+        }
+
+        @Override
+        public void invalidateModificationSwitchPoint(final int index) {
+            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+            invalidateModificationSwitchPoints();
+        }
+
+        @Override
+        public void invalidateModificationSwitchPoints() {
+            final SwitchPoint sp = getSwitchPoint();
+            assert sp != null : "trying to invalidate non-existant modified SwitchPoint";
+            if (!sp.hasBeenInvalidated()) {
+                SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+            }
+        }
+
+        @Override
+        public boolean hasInvalidatedModificationSwitchPoint(final int index) {
+            assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+            return hasInvalidatedModificationSwitchPoints();
+        }
+
+        @Override
+        public boolean hasInvalidatedModificationSwitchPoints() {
+            final SwitchPoint sp = getSwitchPoint();
+            return sp != null && !sp.hasBeenInvalidated();
+        }
+    }
+
+    /**
+     * This is linker logic for optimistic pushes
+     */
+    private static final class PushLinkLogic extends ArrayLinkLogic {
+        private PushLinkLogic(final NativeArray array) {
+            super(array);
+        }
+
+        @Override
+        public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+            return getContinuousArrayData(self) != null;
+        }
+    }
+
+    /**
+     * This is linker logic for optimistic pops
+     */
+    private static final class PopLinkLogic extends ArrayLinkLogic {
+        private PopLinkLogic(final NativeArray array) {
+            super(array);
+        }
+
+        /**
+         * We need to check if we are dealing with a continuous non empty array data here,
+         * as pop with a primitive return value returns undefined for arrays with length 0
+         */
+        @Override
+        public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+            final ContinuousArrayData data = getContinuousNonEmptyArrayData(self);
+            if (data != null) {
+                final Class<?> elementType = data.getElementType();
+                final Class<?> returnType  = desc.getMethodType().returnType();
+                final boolean  typeFits    = JSType.getAccessorTypeIndex(returnType) >= JSType.getAccessorTypeIndex(elementType);
+                return typeFits;
+            }
+            return false;
+        }
+
+        private static ContinuousArrayData getContinuousNonEmptyArrayData(final Object self) {
+            final ContinuousArrayData data = getContinuousArrayData(self);
+            if (data != null) {
+                return data.length() == 0 ? null : data;
+            }
+            return null;
+        }
+    }
+
+    //runtime calls for push and pops. they could be used as guards, but they also perform the runtime logic,
+    //so rather than synthesizing them into a guard method handle that would also perform the push on the
+    //retrieved receiver, we use this as runtime logic
+
+    //TODO - fold these into the Link logics, but I'll do that as a later step, as I want to do a checkin
+    //where everything works first
+
+    private static final <T> ContinuousArrayData getContinuousNonEmptyArrayDataCCE(final Object self, final Class<T> clazz) {
+        try {
+            @SuppressWarnings("unchecked")
+            final ContinuousArrayData data = (ContinuousArrayData)(T)((NativeArray)self).getArray();
+            if (data.length() != 0L) {
+                return data; //if length is 0 we cannot pop and have to relink, because then we'd have to return an undefined, which is a wider type than e.g. int
+           }
+        } catch (final NullPointerException e) {
+            //fallthru
+        }
+        throw new ClassCastException();
+    }
+
+    private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) {
+        try {
+           return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType"
+        } catch (final NullPointerException e) {
+            throw new ClassCastException();
+        }
     }
 }
--- a/src/jdk/nashorn/internal/objects/NativeDataView.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDataView.java	Tue Oct 07 10:57:55 2014 -0700
@@ -27,7 +27,6 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import jdk.nashorn.internal.objects.annotations.Attribute;
@@ -35,7 +34,6 @@
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
@@ -156,7 +154,7 @@
      * @param offset offset in bytes from the start of the ArrayBuffer
      * @return newly constructed DataView object
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) {
         if (!(arrBuf instanceof NativeArrayBuffer)) {
             throw typeError("not.an.arraybuffer.in.dataview");
@@ -174,7 +172,7 @@
      * @param length is the number of bytes from the offset that this DataView will reference
      * @return newly constructed DataView object
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) {
         if (!(arrBuf instanceof NativeArrayBuffer)) {
             throw typeError("not.an.arraybuffer.in.dataview");
--- a/src/jdk/nashorn/internal/objects/NativeDate.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java	Tue Oct 07 10:57:55 2014 -0700
@@ -30,7 +30,6 @@
 import static java.lang.Double.isNaN;
 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
 import java.util.Locale;
 import java.util.TimeZone;
 import java.util.concurrent.Callable;
@@ -38,7 +37,7 @@
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.parser.DateParser;
 import jdk.nashorn.internal.runtime.ConsString;
@@ -155,7 +154,7 @@
      * @param self  self references
      * @return Date representing now
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static Object construct(final boolean isNew, final Object self) {
         final NativeDate result = new NativeDate();
         return isNew ? result : toStringImpl(result, FORMAT_DATE_TIME);
--- a/src/jdk/nashorn/internal/objects/NativeDebug.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.io.PrintWriter;
 import java.util.LinkedList;
 import java.util.Objects;
@@ -262,8 +261,8 @@
 
     /**
      * Set the event queue capacity
-     * @param self
-     * @param newCapacity
+     * @param self an event queue
+     * @param newCapacity new capacity
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static void setEventQueueCapacity(final Object self, final Object newCapacity) {
--- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -85,6 +84,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return double.class;
+        }
+
+        @Override
         protected MethodHandle getGetElem() {
             return GET_ELEM;
         }
--- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -94,6 +93,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return double.class;
+        }
+
         private double getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -95,6 +94,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -113,6 +112,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -93,6 +92,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -48,7 +48,6 @@
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
 import jdk.nashorn.internal.scripts.JO;
 
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java	Tue Oct 07 10:57:55 2014 -0700
@@ -33,13 +33,14 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.Callable;
+
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Getter;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.runtime.BitVector;
 import jdk.nashorn.internal.runtime.JSType;
@@ -143,7 +144,7 @@
      * @param self  self reference
      * @return new NativeRegExp
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeRegExp constructor(final boolean isNew, final Object self) {
         return new NativeRegExp("", "");
     }
@@ -158,7 +159,7 @@
      * @param pattern pattern
      * @return new NativeRegExp
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern) {
         return newRegExp(pattern, UNDEFINED);
     }
@@ -174,7 +175,7 @@
      * @param flags  flags
      * @return new NativeRegExp
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) {
         return newRegExp(pattern, flags);
     }
--- a/src/jdk/nashorn/internal/objects/NativeString.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeString.java	Tue Oct 07 10:57:55 2014 -0700
@@ -29,7 +29,6 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -49,11 +48,12 @@
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.Getter;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.OptimisticBuiltins;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -67,7 +67,7 @@
  * ECMA 15.5 String Objects.
  */
 @ScriptClass("String")
-public final class NativeString extends ScriptObject {
+public final class NativeString extends ScriptObject implements OptimisticBuiltins {
 
     private final CharSequence value;
 
@@ -568,6 +568,14 @@
         return pos < 0 || pos >= str.length() ? "" : String.valueOf(str.charAt(pos));
     }
 
+    private static int getValidChar(final Object self, final int pos) {
+        try {
+            return ((CharSequence)self).charAt(pos);
+        } catch (final IndexOutOfBoundsException e) {
+            throw new ClassCastException();
+        }
+    }
+
     /**
      * ECMA 15.5.4.5 String.prototype.charCodeAt (pos)
      * @param self self reference
@@ -576,7 +584,9 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static double charCodeAt(final Object self, final Object pos) {
-        return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos));
+        final String str = checkObjectToString(self);
+        final int    idx = JSType.toInteger(pos);
+        return idx < 0 || idx >= str.length() ? Double.NaN : str.charAt(idx);
     }
 
     /**
@@ -585,9 +595,20 @@
      * @param pos  position in string
      * @return number representing charcode at position
      */
-    @SpecializedFunction
-    public static double charCodeAt(final Object self, final double pos) {
-        return charCodeAt(self, (int) pos);
+    @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
+    public static int charCodeAt(final Object self, final double pos) {
+        return charCodeAt(self, (int)pos); //toInt pos is ok
+    }
+
+    /**
+     * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for long position
+     * @param self self reference
+     * @param pos  position in string
+     * @return number representing charcode at position
+     */
+    @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
+    public static int charCodeAt(final Object self, final long pos) {
+        return charCodeAt(self, (int)pos);
     }
 
     /**
@@ -596,13 +617,10 @@
      * @param pos  position in string
      * @return number representing charcode at position
      */
-    @SpecializedFunction
-    public static double charCodeAt(final Object self, final int pos) {
-        return charCodeAtImpl(checkObjectToString(self), pos);
-    }
 
-    private static double charCodeAtImpl(final String str, final int pos) {
-        return pos < 0 || pos >= str.length() ? Double.NaN : str.charAt(pos);
+    @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
+    public static int charCodeAt(final Object self, final int pos) {
+        return getValidChar(self, pos);
     }
 
     /**
@@ -1097,7 +1115,6 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static String trim(final Object self) {
-
         final String str = checkObjectToString(self);
         int start = 0;
         int end   = str.length() - 1;
@@ -1181,7 +1198,7 @@
      *
      * @return new NativeString ("")
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static Object constructor(final boolean newObj, final Object self) {
         return newObj ? newObj("") : "";
     }
@@ -1197,7 +1214,7 @@
      *
      * @return new NativeString (arg)
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static Object constructor(final boolean newObj, final Object self, final Object arg) {
         final CharSequence str = JSType.toCharSequence(arg);
         return newObj ? newObj(str) : str.toString();
@@ -1214,8 +1231,42 @@
      *
      * @return new NativeString containing the string representation of the arg
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static Object constructor(final boolean newObj, final Object self, final int arg) {
+        final String str = Integer.toString(arg);
+        return newObj ? newObj(str) : str;
+    }
+
+    /**
+     * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
+     *
+     * Constructor
+     *
+     * @param newObj is this constructor invoked with the new operator
+     * @param self   self reference
+     * @param arg    the arg
+     *
+     * @return new NativeString containing the string representation of the arg
+     */
+    @SpecializedFunction(isConstructor=true)
+    public static Object constructor(final boolean newObj, final Object self, final long arg) {
+        final String str = Long.toString(arg);
+        return newObj ? newObj(str) : str;
+    }
+
+    /**
+     * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
+     *
+     * Constructor
+     *
+     * @param newObj is this constructor invoked with the new operator
+     * @param self   self reference
+     * @param arg    the arg
+     *
+     * @return new NativeString containing the string representation of the arg
+     */
+    @SpecializedFunction(isConstructor=true)
+    public static Object constructor(final boolean newObj, final Object self, final double arg) {
         final String str = JSType.toString(arg);
         return newObj ? newObj(str) : str;
     }
@@ -1231,9 +1282,9 @@
      *
      * @return new NativeString containing the string representation of the arg
      */
-    @SpecializedConstructor
+    @SpecializedFunction(isConstructor=true)
     public static Object constructor(final boolean newObj, final Object self, final boolean arg) {
-        final String str = JSType.toString(arg);
+        final String str = Boolean.toString(arg);
         return newObj ? newObj(str) : str;
     }
 
@@ -1281,7 +1332,7 @@
         } else if (self != null && self == Global.instance().getStringPrototype()) {
             return "";
         } else {
-            throw typeError( "not.a.string", ScriptRuntime.safeToString(self));
+            throw typeError("not.a.string", ScriptRuntime.safeToString(self));
         }
     }
 
@@ -1310,4 +1361,50 @@
         return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type);
     }
 
+    @Override
+    public LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
+        if (clazz == CharCodeAtLinkLogic.class) {
+            return CharCodeAtLinkLogic.INSTANCE;
+        }
+        return null;
+    }
+
+    @Override
+    public boolean hasPerInstanceAssumptions() {
+        return false;
+    }
+
+    /**
+     * This is linker logic charCodeAt - when we specialize further methods in NativeString
+     * It may be expanded. It's link check makes sure that we are dealing with a char
+     * sequence and that we are in range
+     */
+    private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic {
+
+        private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic();
+
+        @Override
+        public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+            try {
+                //check that it's a char sequence or throw cce
+                final CharSequence cs = (CharSequence)self;
+                //check that the index, representable as an int, is inside the array
+                final int intIndex = JSType.toInteger(request.getArguments()[1]);
+                return intIndex >= 0 && intIndex < cs.length(); //can link
+            } catch (final ClassCastException | IndexOutOfBoundsException e) {
+                //fallthru
+            }
+            return false;
+        }
+
+        /**
+         * charCodeAt callsites can throw ClassCastException as a mechanism to have them
+         * relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
+         * for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
+         */
+        @Override
+        public Class<? extends Throwable> getRelinkException() {
+            return ClassCastException.class;
+        }
+    }
 }
--- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -119,6 +118,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -128,6 +127,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return (int)getLong(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.objects;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -119,6 +118,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Tue Oct 07 10:57:55 2014 -0700
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -98,6 +97,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index) & 0xff;
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Tue Oct 07 10:57:55 2014 -0700
@@ -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;
@@ -38,6 +39,7 @@
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.Specialization;
 
 /**
  * Concrete implementation of ScriptFunction. This sets correct map for the
@@ -58,7 +60,7 @@
     // Marker object for lazily initialized prototype object
     private static final Object LAZY_PROTOTYPE = new Object();
 
-    private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
+    private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs, final Global global) {
         super(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
         init(global);
     }
@@ -71,11 +73,11 @@
      * @param invokeHandle handle for invocation
      * @param specs specialized versions of this method, if available, null otherwise
      */
-    ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) {
+    ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
         this(name, invokeHandle, specs, Global.instance());
     }
 
-    private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
+    private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs, final Global global) {
         super(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
         init(global);
     }
@@ -89,11 +91,11 @@
      * @param map initial property map
      * @param specs specialized versions of this method, if available, null otherwise
      */
-    ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) {
+    ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
         this(name, invokeHandle, map, specs, Global.instance());
     }
 
-    private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) {
+    private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags, final Global global) {
         super(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags);
         init(global);
     }
@@ -107,7 +109,7 @@
      * @param specs specialized versions of this method, if available, null otherwise
      * @param flags {@link ScriptFunctionData} flags
      */
-    ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags) {
+    ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags) {
         this(name, methodHandle, scope, specs, flags, Global.instance());
     }
 
@@ -184,7 +186,7 @@
         return new AnonymousFunction();
     }
 
-    private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final int flags) {
+    private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
         final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, flags);
         func.setPrototype(UNDEFINED);
         // Non-constructor built-in functions do not have "prototype" property
@@ -201,7 +203,7 @@
      * @param specs  specialized versions of function if available, null otherwise
      * @return new ScriptFunction
      */
-    static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) {
+    static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
         return makeFunction(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
     }
 
--- a/src/jdk/nashorn/internal/objects/annotations/SpecializedConstructor.java	Wed Oct 01 07:47:24 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * 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.  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.objects.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * The SpecializedConstructor annotation is used to flag more type specific constructors than the standard one in
- * Native objects. For example {@link jdk.nashorn.internal.objects.NativeArray#construct} takes an arbitrary number of
- * Object elements as an array. Call this constructor, including the varargs collector that allocates the array
- * upon each invocation, is much more expensive than calling a specialized constructor that takes one arguments
- * of, e.g. int type from the call site, such as
- * {@link jdk.nashorn.internal.objects.NativeArray#construct(boolean, Object, int)}.
- * {@link jdk.nashorn.internal.runtime.ScriptFunction} will try to look up the most specific function when
- * linking the callsite.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface SpecializedConstructor {
-    //empty
-}
--- a/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Tue Oct 07 10:57:55 2014 -0700
@@ -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
@@ -29,18 +29,315 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.SwitchPoint;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.runtime.ScriptFunction;
 
 /**
- * The SpecializedFunction annotation is used to flag more type specific functions than the standard one in
- * Native objects. For example {@link jdk.nashorn.internal.objects.NativeMath#max} takes an arbitrary number of
- * Object elements as an array. Call this function, including the varargs collector that allocates the array
- * upon each invocation, is much more expensive than calling a specialized function that takes two arguments
- * of, e.g. int type from the call site, such as {@link jdk.nashorn.internal.objects.NativeMath#max(Object, int, int)}.
- * {@link jdk.nashorn.internal.runtime.ScriptFunction} will try to look up the most specific function when
- * linking the callsite.
+ * The SpecializedFunction annotation is used to flag more type specific
+ * functions than the standard one in the native objects
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface SpecializedFunction {
-    //empty
+
+    /**
+     * Functionality for testing if we are allowed to link a specialized
+     * function the first time we encounter it. Then the guard will handle the
+     * rest of the invocations
+     *
+     * This is the same for all callsites in Nashorn, the first time callsite is
+     * linked, we have to manually check that the linkage is OK. Even if we add
+     * a guard and it fails upon the first try, this is not good enough.
+     * (Symmetrical to how it works everywhere else in the Nashorn runtime).
+     *
+     * Here we abstract out a few of the most common link guard checks.
+     */
+    public static abstract class LinkLogic {
+        /**
+         * Empty link logic instance - this is the default
+         * "no special linking or runtime guard behavior"
+         */
+        public static final LinkLogic EMPTY_INSTANCE = new Empty();
+
+        private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0];
+
+        private SwitchPoint[] modificationSwitchPoints; //cache
+
+        /** Empty link logic class - allow all linking, no guards */
+        private static final class Empty extends LinkLogic {
+            @Override
+            public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+                return true;
+            }
+
+            @Override
+            public boolean isEmpty() {
+                return true;
+            }
+        }
+
+        /**
+         * Get the class representing the empty link logic
+         * @return class representing empty link logic
+         */
+        public static Class<? extends LinkLogic> getEmptyLinkLogicClass() {
+            return Empty.class;
+        }
+
+        /**
+         * Should this callsite relink when an exception is thrown
+         *
+         * @return the relink exception, or null if none
+         */
+        public Class<? extends Throwable> getRelinkException() {
+            return null;
+        }
+
+        /**
+         * Is this link logic class empty - i.e. no special linking logic
+         * supplied
+         *
+         * @param clazz class to check
+         *
+         * @return true if this link logic is empty
+         */
+        public static boolean isEmpty(final Class<? extends LinkLogic> clazz) {
+            return clazz == Empty.class;
+        }
+
+        /**
+         * Is this link logic instance empty - i.e. no special linking logic
+         * supplied
+         *
+         * @return true if this link logic instance is empty
+         */
+        public boolean isEmpty() {
+            return false;
+        }
+
+        /**
+         * Given a callsite, can we link this method based on the receiver and
+         * parameters?
+         *
+         * @param self    receiver
+         * @param desc    callsite descriptor
+         * @param request link request
+         *
+         * @return true if we can link this callsite at this time
+         */
+        public abstract boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request);
+
+        /**
+         * Given a callsite, do we require an extra guard for specialization to
+         * go through?
+         *
+         * @param self receiver
+         *
+         * @return true if a guard is to be woven into the callsite
+         */
+        public boolean needsGuard(final Object self) {
+            return true;
+        }
+
+        /**
+         * Given a callsite, and optional arguments, do we need an extra guard
+         * for specialization to go through - this guard can be a function of
+         * the arguments too
+         *
+         * @param self receiver
+         * @param args arguments
+         *
+         * @return true if a guard is to be woven into the callsite
+         */
+        public boolean needsGuard(final Object self, final Object... args) {
+            return true;
+        }
+
+        /**
+         * Given a callsite, and optional arguments, return any extra guard we
+         * might need for specialization as a method handle.
+         *
+         * @return methodhandle for guard, or null if no guard is needed
+         */
+        public MethodHandle getGuard() {
+            return null;
+        }
+
+        /**
+         * Return the modification SwitchPoint of a particular index from this OptimisticBuiltins
+         * If none exists, one is created and that one is return.
+         *
+         * The implementor must map indexes to specific SwitchPoints for specific events and keep
+         * track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT
+         * might be a useful index mapping
+         *
+         * @param index index for SwitchPoint to get or create
+         * @return modification SwitchPoint of particular index for the receiver
+         */
+        public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
+            return null;
+        }
+
+        /**
+         * Return the modification SwitchPoint from this OptimisticBuiltins. If none
+         * exists, one is created and that one is return.
+         *
+         * @return modification SwitchPoint for the receiver
+         */
+        public SwitchPoint[] getOrCreateModificationSwitchPoints() {
+            return null;
+        }
+
+        /**
+         * Hook to invalidate a modification SwitchPoint by index.
+         *
+         * @param index index for SwitchPoint to invalidate
+         */
+        public void invalidateModificationSwitchPoint(final int index) {
+            //empty
+        }
+
+        /**
+         * Hook to invalidate all modification SwitchPoints for a receiver
+         */
+        public void invalidateModificationSwitchPoints() {
+            //empty
+        }
+
+        /**
+         * Check whether the receiver has an invalidated modification SwitchPoint.
+         *
+         * @param  index index for the modification SwitchPoint
+         * @return true if the particular SwitchPoint at the index is invalidated
+         */
+        public boolean hasInvalidatedModificationSwitchPoint(final int index) {
+            return false;
+        }
+
+        /**
+         * Check whether at least one of the modification SwitchPoints has been
+         * invalidated
+         * @return true if one of the SwitchPoints has been invalidated
+         */
+        public boolean hasInvalidatedModificationSwitchPoints() {
+            return false;
+        }
+
+        /**
+         * Check whether this OptimisticBuiltins has a SwitchPoints of particular
+         * index.
+         *
+         * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
+         * e.g. in the constructor of every subclass.
+         *
+         * @param index index for the modification SwitchPoint
+         * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
+         */
+        public boolean hasModificationSwitchPoint(final int index) {
+            return false;
+        }
+
+        /**
+         * Check whether this OptimisticBuiltins has SwitchPoints.
+         *
+         * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
+         * e.g. in the constructor of every subclass.
+         *
+         * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
+         */
+        public boolean hasModificationSwitchPoints() {
+            return false;
+        }
+
+        /**
+         * Check, given a link request and a receiver, if this specialization
+         * fits This is used by the linker in {@link ScriptFunction} to figure
+         * out if an optimistic builtin can be linked when first discovered
+         *
+         * @param self receiver
+         * @param desc callsite descriptor
+         * @param request link request
+
+         * @return true if we can link, false otherwise - that means we have to
+         *         pick a non specialized target
+         */
+        public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+            // no matter what the modification switchpoints are, if any of them are invalidated,
+            // we can't link. Side effect is that if it's the first time we see this callsite,
+            // we have to create the SwitchPoint(s) so future modification switchpoint invalidations
+            // relink it
+            final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self);
+            if (sps == INVALIDATED_SWITCHPOINTS) {
+                // nope, can't do the fast link as this assumption
+                // has been invalidated already, e.g. length of an
+                // array set to not writable
+                return false;
+            }
+            modificationSwitchPoints = sps; //cache
+
+            // check the link guard, if it says we can link, go ahead
+            return canLink(self, desc, request);
+        }
+
+        private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) {
+            final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints
+            if (sps != null) { //switchpoint exists, but some may be invalidated
+                for (final SwitchPoint sp : sps) {
+                    if (sp.hasBeenInvalidated()) {
+                        return INVALIDATED_SWITCHPOINTS;
+                    }
+                }
+            }
+            return sps;
+        }
+
+        /**
+         * Get the cached modification switchpoints. Only possible to do after a link
+         * check call has been performed, one that has answered "true", or you will get the
+         * wrong information.
+         *
+         * Should be used only from {@link ScriptFunction#findCallMethod}
+         *
+         * @return cached modification switchpoints for this callsite, null if none
+         */
+        public SwitchPoint[] getModificationSwitchPoints() {
+            return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone();
+        }
+    }
+
+    /**
+     * name override for return value polymorphism, for example we can't have
+     * pop(V)I and pop(V)D in the same Java class, so they need to be named,
+     * e.g. popInt(V)I and popDouble(V)D for disambiguation, however, their
+     * names still need to resolve to "pop" to JavaScript so we can still
+     * specialize on return values and so that the linker can find them
+     *
+     * @return name, "" means no override, use the Java function name, e.g.
+     *         "push"
+     */
+    String name() default "";
+
+    /**
+     * Return the guard for this specialized function. The default is no guard.
+     *
+     * @return guard
+     */
+    Class<?> linkLogic() default LinkLogic.Empty.class;
+
+    /**
+     * Is this a specialized constructor?
+     */
+    boolean isConstructor() default false;
+
+    /**
+     * Can this function throw UnwarrantedOptimismExceptions? This works just
+     * like the normal functions, but we need the function to be
+     * immutable/non-state modifying, as we can't generate continuations for
+     * native code. Luckily a lot of the methods we want to specialize have this
+     * property
+     */
+    boolean isOptimistic() default false;
 }
--- a/src/jdk/nashorn/internal/parser/AbstractParser.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java	Tue Oct 07 10:57:55 2014 -0700
@@ -30,7 +30,6 @@
 import static jdk.nashorn.internal.parser.TokenType.EOF;
 import static jdk.nashorn.internal.parser.TokenType.EOL;
 import static jdk.nashorn.internal.parser.TokenType.IDENT;
-
 import java.util.HashMap;
 import java.util.Map;
 import jdk.nashorn.internal.ir.IdentNode;
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Tue Oct 07 10:57:55 2014 -0700
@@ -36,7 +36,6 @@
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
 import static jdk.nashorn.internal.runtime.JSType.getNumberOfAccessorTypes;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.lang.invoke.MethodHandle;
@@ -57,9 +56,7 @@
     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 
     private static final MethodHandle REPLACE_MAP   = findOwnMH_S("replaceMap", Object.class, Object.class, PropertyMap.class);
-    private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class);
-
-    private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
+    private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, AccessorProperty.class, Object.class);
 
     private static final int NOOF_TYPES = getNumberOfAccessorTypes();
     private static final long serialVersionUID = 3371720170182154920L;
@@ -221,7 +218,7 @@
      * @param setter the property setter or null if non writable, non configurable
      */
     private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
-        super(key, flags | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
+        super(key, flags | IS_BUILTIN | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
         assert !isSpill();
 
         // we don't need to prep the setters these will never be invalidated as this is a nasgen
@@ -602,7 +599,6 @@
 
     private Property getWiderProperty(final Class<?> type) {
         return copy(type); //invalidate cache of new property
-
     }
 
     private PropertyMap getWiderMap(final PropertyMap oldMap, final Property newProperty) {
@@ -627,8 +623,10 @@
     }
 
     @SuppressWarnings("unused")
-    private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp) {
-        SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+    private static Object invalidateSwitchPoint(final AccessorProperty property, final Object obj) {
+         if (!property.builtinSwitchPoint.hasBeenInvalidated()) {
+            SwitchPoint.invalidateAll(new SwitchPoint[] { property.builtinSwitchPoint });
+        }
         return obj;
     }
 
@@ -668,12 +666,8 @@
             mh = generateSetter(!forType.isPrimitive() ? Object.class : 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(debugInvalidate(getKey(), ccb), 1, changeCallback));
+        if (isBuiltin()) {
+           mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey()));
         }
 
         assert mh.type().returnType() == void.class : mh.type();
@@ -681,25 +675,6 @@
         return mh;
     }
 
-    /**
-     * 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) {
@@ -724,7 +699,6 @@
         return currentType;
     }
 
-
     private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
         if (!Context.DEBUG || !Global.hasInstance()) {
             return mh;
@@ -780,9 +754,9 @@
         return mh;
     }
 
-    private static MethodHandle debugInvalidate(final String key, final SwitchPoint sp) {
+    private static MethodHandle debugInvalidate(final MethodHandle invalidator, final String key) {
         if (!Context.DEBUG || !Global.hasInstance()) {
-            return INVALIDATE_SP;
+            return invalidator;
         }
 
         final Context context = Context.getContextTrusted();
@@ -790,11 +764,11 @@
 
         return context.addLoggingToHandle(
                 ObjectClassGenerator.class,
-                INVALIDATE_SP,
+                invalidator,
                 new Supplier<String>() {
                     @Override
                     public String get() {
-                        return "Field change callback for " + key + " triggered: " + sp;
+                        return "Field change callback for " + key + " triggered ";
                     }
                 });
     }
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Tue Oct 07 10:57:55 2014 -0700
@@ -81,13 +81,17 @@
 
     /**
      * Store a compiled script for later reuse
+     *
+     * @param cacheKey key to use in cache
      * @param source the script source
      * @param mainClassName the main class name
      * @param classBytes map of class names to class bytes
+     * @param initializers compilation id -> FunctionInitializer map
      * @param constants constants array
+     * @param compilationId compilation id
      */
-    public void storeScript(String cacheKey, Source source, String mainClassName, Map<String, byte[]> classBytes,
-                            Map<Integer, FunctionInitializer> initializers, Object[] constants, int compilationId);
+    public void storeScript(final String cacheKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes,
+            final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId);
 
     /**
      * Load a previously compiled script
@@ -96,4 +100,21 @@
      * @return compiled script data
      */
     public StoredScript loadScript(Source source, String functionKey);
+
+    /**
+     * Returns a new code installer that shares most of the functionality of this code installer, but uses a
+     * new, independent class loader.
+     * @return a new code installer with a new independent class loader.
+     */
+    public CodeInstaller<T> withNewLoader();
+
+    /**
+     * Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
+     * an equivalence relation, and installers are supposed to be compatible with those they create using
+     * {@link #withNewLoader()}.
+     * @param other the other code installer tested for compatibility with this code installer.
+     * @return true if this code installer is compatible with the other code installer.
+     */
+    public boolean isCompatibleWith(CodeInstaller<T> other);
+
 }
--- a/src/jdk/nashorn/internal/runtime/CodeStore.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/CodeStore.java	Tue Oct 07 10:57:55 2014 -0700
@@ -118,6 +118,8 @@
      * @param initializers  the function initializers
      * @param constants     the constants array
      * @param compilationId the compilation id
+     *
+     * @return stored script
      */
     public StoredScript store(final String functionKey,
                               final Source source,
@@ -153,11 +155,13 @@
     /**
      * Returns a new StoredScript instance.
      *
+     * @param source the source
      * @param mainClassName the main class name
      * @param classBytes a map of class bytes
      * @param initializers function initializers
      * @param constants the constants array
      * @param compilationId the compilation id
+     *
      * @return The compiled script
      */
     public StoredScript storedScriptFor(final Source source, final String mainClassName,
@@ -206,7 +210,7 @@
         /**
          * Constructor
          *
-         * @throws IOException
+         * @throws IOException if there are read/write problems with the cache and cache directory
          */
         public DirectoryCodeStore() throws IOException {
             this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE);
@@ -216,8 +220,9 @@
          * Constructor
          *
          * @param path    directory to store code in
+         * @param readOnly is this a read only code store
          * @param minSize minimum file size for caching scripts
-         * @throws IOException
+         * @throws IOException if there are read/write problems with the cache and cache directory
          */
         public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException {
             this.dir = checkDirectory(path, readOnly);
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue Oct 07 10:57:55 2014 -0700
@@ -33,12 +33,13 @@
 import java.lang.invoke.MethodType;
 import java.lang.invoke.MutableCallSite;
 import java.lang.invoke.SwitchPoint;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.TreeMap;
 import java.util.function.Supplier;
 import java.util.logging.Level;
-
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@@ -46,6 +47,7 @@
 import jdk.nashorn.internal.codegen.types.ArrayType;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
 import jdk.nashorn.internal.runtime.events.RecompilationEvent;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -63,6 +65,8 @@
 
     private final DebugLogger log;
 
+    static final Collection<CompiledFunction> NO_FUNCTIONS = Collections.emptySet();
+
     /**
      * The method type may be more specific than the invoker, if. e.g.
      * the invoker is guarded, and a guard with a generic object only
@@ -75,19 +79,38 @@
     private final int flags; // from FunctionNode
     private final MethodType callSiteType;
 
+    private final Specialization specialization;
+
     CompiledFunction(final MethodHandle invoker) {
-        this(invoker, null);
+        this(invoker, null, null);
+    }
+
+    static CompiledFunction createBuiltInConstructor(final MethodHandle invoker, final Specialization specialization) {
+        return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), specialization);
+    }
+
+    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final Specialization specialization) {
+        this(invoker, constructor, 0, null, specialization, DebugLogger.DISABLED_LOGGER);
     }
 
-    static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
-        return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)));
-    }
-
-    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
-        this(invoker, constructor, 0, null, DebugLogger.DISABLED_LOGGER);
-    }
-
-    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final DebugLogger log) {
+    CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final Specialization specialization, final DebugLogger log) {
+        this.specialization = specialization;
+        if (specialization != null && specialization.isOptimistic()) {
+            /*
+             * An optimistic builtin with isOptimistic=true works like any optimistic generated function, i.e. it
+             * can throw unwarranted optimism exceptions. As native functions trivially can't have parts of them
+             * regenerated as restof methods, this only works if the methods are atomic/functional in their behavior
+             * and doesn't modify state before an UOE can be thrown. If they aren't, we can reexecute a wider version
+             * of the same builtin in a recompilation handler for FinalScriptFunctionData. There are several
+             * candidate methods in Native* that would benefit from this, but I haven't had time to implement any
+             * of them currently. In order to fit in with the relinking framework, the current thinking is
+             * that the methods still take a program point to fit in with other optimistic functions, but
+             * it is set to "first", which is the beginning of the method. The relinker can tell the difference
+             * between builtin and JavaScript functions. This might change. TODO
+             */
+            this.invoker = MH.insertArguments(invoker, invoker.type().parameterCount() - 1, UnwarrantedOptimismException.FIRST_PROGRAM_POINT);
+            throw new AssertionError("Optimistic (UnwarrantedOptimismException throwing) builtin functions are currently not in use");
+        }
         this.invoker = invoker;
         this.constructor = constructor;
         this.flags = flags;
@@ -97,7 +120,7 @@
 
     CompiledFunction(final MethodHandle invoker, final RecompilableScriptFunctionData functionData,
             final Map<Integer, Type> invalidatedProgramPoints, final MethodType callSiteType, final int flags) {
-        this(invoker, null, flags, callSiteType, functionData.getLogger());
+        this(invoker, null, flags, callSiteType, null, functionData.getLogger());
         if ((flags & FunctionNode.IS_DEOPTIMIZABLE) != 0) {
             optimismInfo = new OptimismInfo(functionData, invalidatedProgramPoints);
         } else {
@@ -105,10 +128,45 @@
         }
     }
 
+    static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
+        return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), null);
+    }
+
+    boolean isSpecialization() {
+        return specialization != null;
+    }
+
+    boolean hasLinkLogic() {
+        return getLinkLogicClass() != null;
+    }
+
+    Class<? extends LinkLogic> getLinkLogicClass() {
+        if (isSpecialization()) {
+            final Class<? extends LinkLogic> linkLogicClass = specialization.getLinkLogicClass();
+            assert !LinkLogic.isEmpty(linkLogicClass) : "empty link logic classes should have been removed by nasgen";
+            return linkLogicClass;
+        }
+        return null;
+    }
+
     int getFlags() {
         return flags;
     }
 
+    /**
+     * An optimistic specialization is one that can throw UnwarrantedOptimismException.
+     * This is allowed for native methods, as long as they are functional, i.e. don't change
+     * any state between entering and throwing the UOE. Then we can re-execute a wider version
+     * of the method in the continuation. Rest-of method generation for optimistic builtins is
+     * of course not possible, but this approach works and fits into the same relinking
+     * framework
+     *
+     * @return true if optimistic builtin
+     */
+    boolean isOptimistic() {
+        return isSpecialization() ? specialization.isOptimistic() : false;
+    }
+
     boolean isApplyToCall() {
         return (flags & FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION) != 0;
     }
@@ -119,7 +177,19 @@
 
     @Override
     public String toString() {
-        return "[invokerType=" + invoker.type() + " ctor=" + constructor + " weight=" + weight() + " isApplyToCall=" + isApplyToCall() + "]";
+        final StringBuilder sb = new StringBuilder();
+        final Class<? extends LinkLogic> linkLogicClass = getLinkLogicClass();
+
+        sb.append("[invokerType=").
+            append(invoker.type()).
+            append(" ctor=").
+            append(constructor).
+            append(" weight=").
+            append(weight()).
+            append(" linkLogic=").
+            append(linkLogicClass != null ? linkLogicClass.getSimpleName() : "none");
+
+        return sb.toString();
     }
 
     boolean needsCallee() {
@@ -281,10 +351,12 @@
         if (other == null) {
             return true;
         }
-        return betterThanFinal(type(), other.type(), callSiteMethodType);
+        return betterThanFinal(this, other, callSiteMethodType);
     }
 
-    static boolean betterThanFinal(final MethodType thisMethodType, final MethodType otherMethodType, final MethodType callSiteMethodType) {
+    private static boolean betterThanFinal(final CompiledFunction cf, final CompiledFunction other, final MethodType callSiteMethodType) {
+        final MethodType thisMethodType  = cf.type();
+        final MethodType otherMethodType = other.type();
         final int thisParamCount = getParamCount(thisMethodType);
         final int otherParamCount = getParamCount(otherMethodType);
         final int callSiteRawParamCount = getParamCount(callSiteMethodType);
@@ -406,7 +478,17 @@
             return false;
         }
 
-        throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType); // Signatures are identical
+        //if they are equal, pick the specialized one first
+        if (cf.isSpecialization() != other.isSpecialization()) {
+            return cf.isSpecialization(); //always pick the specialized version if we can
+        }
+
+        if (cf.isSpecialization() && other.isSpecialization()) {
+            return cf.getLinkLogicClass() != null; //pick link logic specialization above generic specializations
+        }
+
+        // Signatures are identical
+        throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType);
     }
 
     private static Type[] toTypeWithoutCallee(final MethodType type, final int thisIndex) {
@@ -427,8 +509,8 @@
         return ((ArrayType)paramTypes[paramTypes.length - 1]).getElementType();
     }
 
-    boolean matchesCallSite(final MethodType callSiteType, final boolean pickVarArg) {
-        if (callSiteType.equals(this.callSiteType)) {
+    boolean matchesCallSite(final MethodType other, final boolean pickVarArg) {
+        if (other.equals(this.callSiteType)) {
             return true;
         }
         final MethodType type  = type();
@@ -438,7 +520,7 @@
             return pickVarArg;
         }
 
-        final int csParamCount = getParamCount(callSiteType);
+        final int csParamCount = getParamCount(other);
         final boolean csIsVarArg = csParamCount == Integer.MAX_VALUE;
         final int thisThisIndex = needsCallee() ? 1 : 0; // Index of "this" parameter in this function's type
 
@@ -447,7 +529,7 @@
         // We must match all incoming parameters, except "this". Starting from 1 to skip "this".
         for(int i = 1; i < minParams; ++i) {
             final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex));
-            final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(callSiteType.parameterType(i + 1));
+            final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(other.parameterType(i + 1));
             if(!fnType.isEquivalentTo(csType)) {
                 return false;
             }
@@ -669,9 +751,9 @@
         return sb.toString();
     }
 
-    private void logRecompile(final String reason, final FunctionNode fn, final MethodType callSiteType, final Map<Integer, Type> ipp) {
+    private void logRecompile(final String reason, final FunctionNode fn, final MethodType type, final Map<Integer, Type> ipp) {
         if (log.isEnabled()) {
-            log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", callSiteType, " ", toStringInvalidations(ipp));
+            log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type, " ", toStringInvalidations(ipp));
         }
     }
 
@@ -732,8 +814,6 @@
             compiler.persistClassInfo(cacheKey, normalFn);
         }
 
-        FunctionNode fn2 = effectiveOptInfo.reparse();
-        fn2 = compiler.compile(fn2, CompilationPhases.COMPILE_UPTO_BYTECODE);
         log.info("Done.");
 
         final boolean canBeDeoptimized = normalFn.canBeDeoptimized();
--- a/src/jdk/nashorn/internal/runtime/Context.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Tue Oct 07 10:57:55 2014 -0700
@@ -40,6 +40,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.reflect.Field;
@@ -127,6 +128,16 @@
     private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
     private static MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
 
+    /**
+     * Keeps track of which builtin prototypes and properties have been relinked
+     * Currently we are conservative and associate the name of a builtin class with all
+     * its properties, so it's enough to invalidate a property to break all assumptions
+     * about a prototype. This can be changed to a more fine grained approach, but no one
+     * ever needs this, given the very rare occurance of swapping out only parts of
+     * a builtin v.s. the entire builtin object
+     */
+    private final Map<String, SwitchPoint> builtinSwitchPoints = new HashMap<>();
+
     /* Force DebuggerSupport to be loaded. */
     static {
         DebuggerSupport.FORCELOAD = true;
@@ -148,7 +159,7 @@
         }
 
         /**
-         * Return the context for this installer
+         * Return the script environment for this installer
          * @return ScriptEnvironment
          */
         @Override
@@ -212,6 +223,20 @@
             }
             return null;
         }
+
+        @Override
+        public CodeInstaller<ScriptEnvironment> withNewLoader() {
+            return new ContextCodeInstaller(context, context.createNewLoader(), codeSource);
+        }
+
+        @Override
+        public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) {
+            if (other instanceof ContextCodeInstaller) {
+                final ContextCodeInstaller cci = (ContextCodeInstaller)other;
+                return cci.context == context && cci.codeSource == codeSource;
+            }
+            return false;
+        }
     }
 
     /** Is Context global debug mode enabled ? */
@@ -1371,4 +1396,34 @@
         return null;
     }
 
+    /**
+     * This is a special kind of switchpoint used to guard builtin
+     * properties and prototypes. In the future it might contain
+     * logic to e.g. multiple switchpoint classes.
+     */
+    public static final class BuiltinSwitchPoint extends SwitchPoint {
+        //empty
+    }
+
+    /**
+     * Create a new builtin switchpoint and return it
+     * @param name key name
+     * @return new builtin switchpoint
+     */
+    public SwitchPoint newBuiltinSwitchPoint(final String name) {
+        assert builtinSwitchPoints.get(name) == null;
+        final SwitchPoint sp = new BuiltinSwitchPoint();
+        builtinSwitchPoints.put(name, sp);
+        return sp;
+    }
+
+    /**
+     * Return the builtin switchpoint for a particular key name
+     * @param name key name
+     * @return builtin switchpoint or null if none
+     */
+    public SwitchPoint getBuiltinSwitchPoint(final String name) {
+        return builtinSwitchPoints.get(name);
+    }
+
 }
--- a/src/jdk/nashorn/internal/runtime/Debug.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/Debug.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime;
 
 import static jdk.nashorn.internal.parser.TokenType.EOF;
-
 import jdk.nashorn.internal.parser.Lexer;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenStream;
@@ -42,12 +41,12 @@
 
     /**
      * Return the topmost JavaScript frame in a stack trace
-     * @param e
+     * @param t throwable that contains the stack trace
      * @return line describing the topmost JavaScript frame
      */
-    public static String firstJSFrame(final Throwable e) {
-        for (final StackTraceElement ste : e.getStackTrace()) {
-            if(ECMAErrors.isScriptFrame(ste)) {
+    public static String firstJSFrame(final Throwable t) {
+        for (final StackTraceElement ste : t.getStackTrace()) {
+            if (ECMAErrors.isScriptFrame(ste)) {
                 return ste.toString();
             }
         }
--- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -60,13 +60,13 @@
      * @param specs specializations
      * @param flags {@link ScriptFunctionData} flags
      */
-    FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) {
+    FinalScriptFunctionData(final String name, final MethodHandle mh, final Specialization[] specs, final int flags) {
         super(name, methodHandleArity(mh), flags);
 
         addInvoker(mh);
         if (specs != null) {
-            for (final MethodHandle spec : specs) {
-                addInvoker(spec);
+            for (final Specialization spec : specs) {
+                addInvoker(spec.getMethodHandle(), spec);
             }
         }
     }
@@ -114,16 +114,25 @@
         return MethodType.genericMethodType(max + 1);
     }
 
-    private void addInvoker(final MethodHandle mh) {
+    private CompiledFunction addInvoker(final MethodHandle mh, final Specialization specialization) {
         assert !needsCallee(mh);
+
+        final CompiledFunction invoker;
         if (isConstructor(mh)) {
             // only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
             // is too conservative a check. However, isConstructor(mh) always implies isConstructor param
             assert isConstructor();
-            code.add(CompiledFunction.createBuiltInConstructor(mh));
+            invoker = CompiledFunction.createBuiltInConstructor(mh);
         } else {
-            code.add(new CompiledFunction(mh));
+            invoker = new CompiledFunction(mh, null, specialization);
         }
+        code.add(invoker);
+
+        return invoker;
+    }
+
+    private CompiledFunction addInvoker(final MethodHandle mh) {
+        return addInvoker(mh, null);
     }
 
     private static int methodHandleArity(final MethodHandle mh) {
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java	Tue Oct 07 10:57:55 2014 -0700
@@ -79,6 +79,8 @@
      *
      * @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature
      * @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
+     * @param request link request
+     *
      * @return method handle for the getter
      */
     public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
@@ -102,6 +104,7 @@
      *
      * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
      * @param strict are we in strict mode
+     * @param request link request
      *
      * @return method handle for the getter
      */
--- a/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Tue Oct 07 10:57:55 2014 -0700
@@ -358,8 +358,12 @@
      * @param c constant value
      * @return method handle (with dummy receiver) that returns this constant
      */
+    public static MethodHandle staticConstantGetter(final Object c) {
+        return MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
+    }
+
     private MethodHandle constantGetter(final Object c) {
-        final MethodHandle mh = MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
+        final MethodHandle mh = staticConstantGetter(c);
         if (log.isEnabled()) {
             return MethodHandleFactory.addDebugPrintout(log, Level.FINEST, mh, "getting as constant");
         }
--- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Tue Oct 07 10:57:55 2014 -0700
@@ -42,12 +42,30 @@
     /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
     public static final MethodHandle PARSEINT_OI = findOwnMH("parseInt", double.class, Object.class, Object.class, int.class);
 
+    /** ParseInt - NaN for booleans (thru string conversion to number conversion) */
+    public static final MethodHandle PARSEINT_Z = MH.dropArguments(MH.dropArguments(MH.constant(double.class, Double.NaN), 0, boolean.class), 0, Object.class);
+
+    /** ParseInt - identity for ints */
+    public static final MethodHandle PARSEINT_I = MH.dropArguments(MH.identity(int.class), 0, Object.class);
+
+    /** ParseInt - identity for longs */
+    public static final MethodHandle PARSEINT_J = MH.dropArguments(MH.identity(long.class), 0, Object.class);
+
     /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
     public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class);
 
     /** Methodhandle to implementation of ECMA 15.1.2.3, parseFloat */
     public static final MethodHandle PARSEFLOAT = findOwnMH("parseFloat", double.class, Object.class, Object.class);
 
+    /** isNan for integers - always false */
+    public static final MethodHandle IS_NAN_I = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
+
+    /** isNan for longs - always false */
+    public static final MethodHandle IS_NAN_J = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
+
+    /** IsNan for doubles - use Double.isNaN */
+    public static final MethodHandle IS_NAN_D = MH.dropArguments(MH.findStatic(MethodHandles.lookup(), Double.class, "isNaN", MH.type(boolean.class, double.class)), 0, Object.class);
+
     /** Methodhandle to implementation of ECMA 15.1.2.4, isNaN */
     public static final MethodHandle IS_NAN = findOwnMH("isNaN",      boolean.class, Object.class, Object.class);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/OptimisticBuiltins.java	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,65 @@
+/*
+ * 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.runtime;
+
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
+
+/**
+ * This is an interface for classes that need custom linkage logic. This means Native objects
+ * that contain optimistic native methods, that need special/extra rules for linking, guards and
+ * SwitchPointing, known and internal to the Native object for its linkage
+ */
+public interface OptimisticBuiltins {
+
+    /**
+     * Return an instance of the linking logic we need for a particular LinkLogic
+     * subclass, gotten from the compile time annotation of a specialized builtin method
+     * No assumptions can be made about the lifetime of the instance. The receiver may
+     * keep it as a perpetual final instance field or create new linking logic depending
+     * on its current state for each call, depending on if the global state has changed
+     * or other factors
+     *
+     * @param clazz linking logic class
+     * @return linking logic instance for this class
+     */
+    public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz);
+
+    /**
+     * Does this link logic vary depending on which instance we are working with.
+     * Then we have to sort out certain primitives, as they are created as new
+     * objects in the wrapFilter by JavaScript semantics. An example of instance only
+     * assumptions are switchPoints per instance, as in NativeArray. NativeString is
+     * fine, as it's only static.
+     *
+     * TODO: finer granularity on this, on the function level so certain functions
+     * are forbidden only. Currently we don't have enough specialization to bump into this
+     *
+     * @return true if there are per instance assumptions for the optimism
+     */
+    public boolean hasPerInstanceAssumptions();
+
+}
--- a/src/jdk/nashorn/internal/runtime/Property.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/Property.java	Tue Oct 07 10:57:55 2014 -0700
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
-
 import java.io.Serializable;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.SwitchPoint;
@@ -84,6 +83,9 @@
      */
     public static final int IS_NASGEN_PRIMITIVE     = 1 << 6;
 
+    /** Is this a builtin property, e.g. Function.prototype.apply */
+    public static final int IS_BUILTIN = 1 << 7;
+
     /** Is this property bound to a receiver? This means get/set operations will be delegated to
      *  a statically defined object instead of the object passed as callsite parameter. */
     public static final int IS_BOUND                = 1 << 7;
@@ -101,7 +103,7 @@
     private final int slot;
 
     /** SwitchPoint that is invalidated when property is changed, optional */
-    protected transient SwitchPoint changeCallback;
+    protected transient SwitchPoint builtinSwitchPoint;
 
     private static final long serialVersionUID = 2099814273074501176L;
 
@@ -125,10 +127,10 @@
      * @param property source property
      */
     Property(final Property property, final int flags) {
-        this.key            = property.key;
-        this.slot           = property.slot;
-        this.changeCallback = property.changeCallback;
-        this.flags          = flags;
+        this.key                = property.key;
+        this.slot               = property.slot;
+        this.builtinSwitchPoint = property.builtinSwitchPoint;
+        this.flags              = flags;
     }
 
     /**
@@ -182,8 +184,26 @@
      * changed
      * @param sp SwitchPoint to use for change callback
      */
-    public final void setChangeCallback(final SwitchPoint sp) {
-        this.changeCallback = sp;
+    public final void setBuiltinSwitchPoint(final SwitchPoint sp) {
+        this.builtinSwitchPoint = sp;
+    }
+
+    /**
+     * Builtin properties have an invalidation switchpoint that is
+     * invalidated when they are set, this is a getter for it
+     * @return builtin switchpoint, or null if none
+     */
+    public final SwitchPoint getBuiltinSwitchPoint() {
+        return builtinSwitchPoint;
+    }
+
+    /**
+     * Checks if this is a builtin property, this means that it has
+     * a builtin switchpoint that hasn't been invalidated by a setter
+     * @return true if builtin, untouched (unset) property
+     */
+    public boolean isBuiltin() {
+        return builtinSwitchPoint != null && !builtinSwitchPoint.hasBeenInvalidated();
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue Oct 07 10:57:55 2014 -0700
@@ -950,7 +950,7 @@
 
         @Override
         public void remove() {
-            throw new UnsupportedOperationException();
+            throw new UnsupportedOperationException("remove");
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -31,6 +31,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -268,7 +269,7 @@
         if (this.source == null && this.installer == null) {
             this.source    = src;
             this.installer = inst;
-        } else if (this.source != src || this.installer != inst) {
+        } else if (this.source != src || !this.installer.isCompatibleWith(inst)) {
             // Existing values must be same as those passed as parameters
             throw new IllegalArgumentException();
         }
@@ -407,6 +408,17 @@
         return getCompiler(fn, actualCallSiteType, newLocals(runtimeScope), null, null);
     }
 
+    /**
+     * Returns a code installer for installing new code. If we're using either optimistic typing or loader-per-compile,
+     * then asks for a code installer with a new class loader; otherwise just uses the current installer. We use
+     * a new class loader with optimistic typing so that deoptimized code can get reclaimed by GC.
+     * @return a code installer for installing new code.
+     */
+    private CodeInstaller<ScriptEnvironment> getInstallerForNewCode() {
+        final ScriptEnvironment env = installer.getOwner();
+        return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
+    }
+
     Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType,
             final ScriptObject runtimeScope, final Map<Integer, Type> invalidatedProgramPoints,
             final int[] continuationEntryPoints) {
@@ -417,7 +429,7 @@
         return new Compiler(
                 context,
                 context.getEnv(),
-                installer,
+                getInstallerForNewCode(),
                 functionNode.getSource(),  // source
                 context.getErrorManager(),
                 isStrict() | functionNode.isStrict(), // is strict
@@ -454,7 +466,7 @@
         // CompilationEnvironment#declareLocalSymbol()).
 
         if (log.isEnabled()) {
-            log.info("Type specialization of '", functionName, "' signature: ", actualCallSiteType);
+            log.info("Parameter type specialization of '", functionName, "' signature: ", actualCallSiteType);
         }
 
         final boolean persistentCache = usePersistentCodeCache() && persist;
@@ -463,11 +475,12 @@
             final TypeMap typeMap = typeMap(actualCallSiteType);
             final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
             cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
-            final StoredScript script = installer.loadScript(source, cacheKey);
+            final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode();
+            final StoredScript script = newInstaller.loadScript(source, cacheKey);
 
             if (script != null) {
                 Compiler.updateCompilationId(script.getCompilationId());
-                return install(script);
+                return installStoredScript(script, newInstaller);
             }
         }
 
@@ -481,15 +494,7 @@
         return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
     }
 
-
-    /**
-     * Install this script using the given {@code installer}.
-     *
-     * @param script the compiled script
-     * @return the function initializer
-     */
-    private FunctionInitializer install(final StoredScript script) {
-
+    private static Map<String, Class<?>> installStoredScriptClasses(final StoredScript script, final CodeInstaller<ScriptEnvironment> installer) {
         final Map<String, Class<?>> installedClasses = new HashMap<>();
         final Map<String, byte[]>   classBytes       = script.getClassBytes();
         final String   mainClassName   = script.getMainClassName();
@@ -501,14 +506,25 @@
 
         for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) {
             final String className = entry.getKey();
-            final byte[] code = entry.getValue();
+            final byte[] bytecode = entry.getValue();
 
             if (className.equals(mainClassName)) {
                 continue;
             }
 
-            installedClasses.put(className, installer.install(className, code));
+            installedClasses.put(className, installer.install(className, bytecode));
         }
+        return installedClasses;
+    }
+
+    /**
+     * Install this script using the given {@code installer}.
+     *
+     * @param script the compiled script
+     * @return the function initializer
+     */
+    private FunctionInitializer installStoredScript(final StoredScript script, final CodeInstaller<ScriptEnvironment> newInstaller) {
+        final Map<String, Class<?>> installedClasses = installStoredScriptClasses(script, newInstaller);
 
         final Map<Integer, FunctionInitializer> initializers = script.getInitializers();
         assert initializers != null;
@@ -523,7 +539,7 @@
             }
         }
 
-        installer.initialize(installedClasses.values(), source, constants);
+        newInstaller.initialize(installedClasses.values(), source, constants);
         initializer.setCode(installedClasses.get(initializer.getClassName()));
         return initializer;
     }
@@ -588,15 +604,19 @@
         return lookupCodeMethod(fn.getCompileUnit().getCode(), type);
     }
 
-    MethodHandle lookupCodeMethod(final Class<?> code, final MethodType targetType) {
-        log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
-        return MH.findStatic(LOOKUP, code, functionName, targetType);
+    MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) {
+        if (log.isEnabled()) {
+            log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
+        }
+        return MH.findStatic(LOOKUP, codeClass, functionName, targetType);
     }
 
     /**
      * Initializes this function data with the eagerly generated version of the code. This method can only be invoked
      * by the compiler internals in Nashorn and is public for implementation reasons only. Attempting to invoke it
      * externally will result in an exception.
+     *
+     * @param initializer FunctionInitializer for this data
      */
     public void initializeCode(final FunctionInitializer initializer) {
         // Since the method is public, we double-check that we aren't invoked with an inappropriate compile unit.
@@ -658,8 +678,8 @@
 
 
     @Override
-    synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
-        CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope);
+    synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+        CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope, forbidden);
         if (existingBest == null) {
             existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, true), callSiteType);
         }
@@ -723,6 +743,10 @@
         return functionNodeId;
     }
 
+    /**
+     * Get the source for the script
+     * @return source
+     */
     public Source getSource() {
         return source;
     }
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue Oct 07 10:57:55 2014 -0700
@@ -181,9 +181,6 @@
     /** print symbols and their contents for the script */
     public final boolean _print_symbols;
 
-    /** range analysis for known types */
-    public final boolean _range_analysis;
-
     /** is this environment in scripting mode? */
     public final boolean _scripting;
 
@@ -255,7 +252,6 @@
         _print_parse          = options.getBoolean("print.parse");
         _print_lower_parse    = options.getBoolean("print.lower.parse");
         _print_symbols        = options.getBoolean("print.symbols");
-        _range_analysis       = options.getBoolean("range.analysis");
         _scripting            = options.getBoolean("scripting");
         _strict               = options.getBoolean("strict");
         _version              = options.getBoolean("version");
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Oct 07 10:57:55 2014 -0700
@@ -30,26 +30,29 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.SwitchPoint;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
-
+import java.util.HashSet;
+import java.util.List;
 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.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.objects.NativeFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
 
 /**
  * Runtime representation of a JavaScript function.
@@ -114,7 +117,7 @@
             final MethodHandle methodHandle,
             final PropertyMap map,
             final ScriptObject scope,
-            final MethodHandle[] specs,
+            final Specialization[] specs,
             final int flags) {
 
         this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
@@ -468,13 +471,12 @@
     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final MethodType type = desc.getMethodType();
         assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
-        final CompiledFunction cf = data.getBestConstructor(type, scope);
+        final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
         final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
         //TODO - ClassCastException
         return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
     }
 
-    @SuppressWarnings("unused")
     private static Object wrapFilter(final Object obj) {
         if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
             return obj;
@@ -490,6 +492,35 @@
     }
 
     /**
+     * Some receivers are primitive, in that case, according to the Spec we create a new
+     * native object per callsite with the wrap filter. We can only apply optimistic builtins
+     * if there is no per instance state saved for these wrapped objects (e.g. currently NativeStrings),
+     * otherwise we can't create optimistic versions
+     *
+     * @param self            receiver
+     * @param linkLogicClass  linkLogicClass, or null if no link logic exists
+     * @return link logic instance, or null if one could not be constructed for this receiver
+     */
+    private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
+        if (linkLogicClass == null) {
+            return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
+        }
+
+        if (!Context.getContextTrusted().getEnv()._optimistic_types) {
+            return null; //if optimistic types are off, optimistic builtins are too
+        }
+
+        final Object wrappedSelf = wrapFilter(self);
+        if (wrappedSelf instanceof OptimisticBuiltins) {
+            if (wrappedSelf != self && ((OptimisticBuiltins)wrappedSelf).hasPerInstanceAssumptions()) {
+                return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
+            }
+            return ((OptimisticBuiltins)wrappedSelf).getLinkLogic(linkLogicClass);
+        }
+        return null;
+    }
+
+    /**
      * dyn:call call site signature: (callee, thiz, [args...])
      * generated method signature:   (callee, thiz, [args...])
      *
@@ -547,8 +578,53 @@
             }
         } //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 CompiledFunction cf = data.getBestInvoker(type, scope);
+        int programPoint = INVALID_PROGRAM_POINT;
+        if (NashornCallSiteDescriptor.isOptimistic(desc)) {
+            programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
+        }
+
+        CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
+        final Object self = request.getArguments()[1];
+        final Collection<CompiledFunction> forbidden = new HashSet<>();
+
+        //check for special fast versions of the compiled function
+        final List<SwitchPoint> sps = new ArrayList<>();
+        Class<? extends Throwable> exceptionGuard = null;
+
+        while (cf.isSpecialization()) {
+            final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
+            //if linklogic is null, we can always link with the standard mechanism, it's still a specialization
+            final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
+
+            if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
+                final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
+
+                if (log.isEnabled()) {
+                    log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
+                }
+
+                final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints();
+                if (msps != null) {
+                    for (final SwitchPoint sp : msps) {
+                        if (sp != null) {
+                            assert !sp.hasBeenInvalidated();
+                            sps.add(sp);
+                        }
+                    }
+                }
+
+                exceptionGuard = linkLogic.getRelinkException();
+
+                break;
+            }
+
+            //could not link this specialization because link check failed
+            forbidden.add(cf);
+            final CompiledFunction oldCf = cf;
+            cf = data.getBestInvoker(type, scope, forbidden);
+            assert oldCf != cf;
+        }
+
         final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
         final MethodHandle callHandle = bestInvoker.getInvocation();
 
@@ -588,7 +664,20 @@
 
         boundHandle = pairArguments(boundHandle, type);
 
-        return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this, cf.getFlags()) : guard, bestInvoker.getSwitchPoints(), null);
+        if (bestInvoker.getSwitchPoints() != null) {
+            sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
+        }
+        final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
+
+        return new GuardedInvocation(
+                boundHandle,
+                guard == null ?
+                        getFunctionGuard(
+                                this,
+                                cf.getFlags()) :
+                        guard,
+                        spsArray,
+                exceptionGuard);
     }
 
     private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
@@ -610,7 +699,7 @@
 
         //box call back to apply
         CallSiteDescriptor appliedDesc = desc;
-        final SwitchPoint applyToCallSwitchPoint = Global.instance().getChangeCallback("apply");
+        final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
         //enough to change the proto switchPoint here
 
         final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
@@ -656,7 +745,7 @@
             }
         }
 
-        appliedDesc = appliedDesc.changeMethodType(appliedType);
+        appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
 
         // 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()];
@@ -681,6 +770,7 @@
 
         // Ask the linker machinery for an invocation of the target function
         final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
+
         GuardedInvocation appliedInvocation;
         try {
             appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
@@ -742,7 +832,7 @@
         // We need to account for the dropped (apply|call) function argument.
         guard = MH.dropArguments(guard, 0, descType.parameterType(0));
         // Take the "isApplyFunction" guard, and bind it to this function.
-        MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this);
+        MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
         // Adapt the guard to receive all the arguments that the original guard does.
         applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
         // Fold the original function guard into our apply guard.
@@ -894,6 +984,7 @@
         return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
     }
 
+    //TODO this can probably be removed given that we have builtin switchpoints in the context
     @SuppressWarnings("unused")
     private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
         // NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -28,13 +28,13 @@
 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.ObjectInputStream;
 import java.io.Serializable;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -136,7 +136,7 @@
         final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
 
         if (isConstructor()) {
-            return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args));
+            return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args), null);
         }
 
         return new CompiledFunction(boundInvoker);
@@ -224,18 +224,22 @@
      * @param callSiteType callsite type
      * @return compiled function object representing the best invoker.
      */
-     final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
-        final CompiledFunction cf = getBest(callSiteType, runtimeScope);
+    final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
+        return getBestInvoker(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS);
+    }
+
+    final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+        final CompiledFunction cf = getBest(callSiteType, runtimeScope, forbidden);
         assert cf != null;
         return cf;
     }
 
-    final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope) {
+    final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
         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);
+        final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope, forbidden);
         return cf;
     }
 
@@ -350,7 +354,7 @@
      * scope is not known, but that might cause compilation of code that will need more deoptimization passes.
      * @return the best function for the specified call site type.
      */
-    CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
+    CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
         assert callSiteType.parameterCount() >= 2 : callSiteType; // Must have at least (callee, this)
         assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
 
@@ -363,8 +367,8 @@
         }
 
         CompiledFunction best = null;
-        for(final CompiledFunction candidate: code) {
-            if(candidate.betterThanFinal(best, callSiteType)) {
+        for (final CompiledFunction candidate: code) {
+            if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
                 best = candidate;
             }
         }
@@ -376,7 +380,7 @@
     abstract boolean isRecompilable();
 
     CompiledFunction getGeneric(final ScriptObject runtimeScope) {
-        return getBest(getGenericType(), runtimeScope);
+        return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
     }
 
     /**
@@ -420,7 +424,7 @@
 
         final List<CompiledFunction> boundList = new LinkedList<>();
         final ScriptObject runtimeScope = fn.getScope();
-        final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope));
+        final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope), null);
         boundList.add(bind(bindTarget, fn, self, allArgs));
 
         return new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, boundFlags);
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Oct 07 10:57:55 2014 -0700
@@ -47,7 +47,6 @@
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
 import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -820,6 +819,19 @@
         return false;
     }
 
+    private SwitchPoint findBuiltinSwitchPoint(final String key) {
+        for (ScriptObject myProto = getProto(); myProto != null; myProto = myProto.getProto()) {
+            final Property prop = myProto.getMap().findProperty(key);
+            if (prop != null) {
+                final SwitchPoint sp = prop.getBuiltinSwitchPoint();
+                if (sp != null && !sp.hasBeenInvalidated()) {
+                    return sp;
+                }
+            }
+        }
+        return null;
+    }
+
     /**
      * Add a new property to the object.
      * <p>
@@ -923,10 +935,10 @@
      * creating setters that probably aren't used. Inject directly into the spill pool
      * the defaults for "arguments" and "caller"
      *
-     * @param key
-     * @param propertyFlags
-     * @param getter
-     * @param setter
+     * @param key           property key
+     * @param propertyFlags flags
+     * @param getter        getter for {@link UserAccessorProperty}, null if not present or N/A
+     * @param setter        setter for {@link UserAccessorProperty}, null if not present or N/A
      */
     protected final void initUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
         final int slot = spillLength;
@@ -1514,6 +1526,23 @@
     }
 
     /**
+     * Get the {@link ArrayData}, for this ScriptObject, ensuring it is of a type
+     * that can handle elementType
+     * @param elementType elementType
+     * @return array data
+     */
+    public final ArrayData getArray(final Class<?> elementType) {
+        if (elementType == null) {
+            return arrayData;
+        }
+        final ArrayData newArrayData = arrayData.convert(elementType);
+        if (newArrayData != arrayData) {
+            arrayData = newArrayData;
+        }
+        return newArrayData;
+    }
+
+    /**
      * Get the {@link ArrayData} for this ScriptObject if it is an array
      * @return array data
      */
@@ -1720,8 +1749,8 @@
      */
     public Object put(final Object key, final Object value, final boolean strict) {
         final Object oldValue = get(key);
-        final int flags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
-        set(key, value, flags);
+        final int scriptObjectFlags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
+        set(key, value, scriptObjectFlags);
         return oldValue;
     }
 
@@ -1734,9 +1763,9 @@
      * @param strict strict mode or not
      */
     public void putAll(final Map<?, ?> otherMap, final boolean strict) {
-        final int flags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
+        final int scriptObjectFlags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
         for (final Map.Entry<?, ?> entry : otherMap.entrySet()) {
-            set(entry.getKey(), entry.getValue(), flags);
+            set(entry.getKey(), entry.getValue(), scriptObjectFlags);
         }
     }
 
@@ -1916,17 +1945,6 @@
         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.
      *
@@ -1938,14 +1956,13 @@
      */
     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
         final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
-        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);
+
+        String name;
+        name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+        if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
+            if (Global.isBuiltinFunctionPrototypeApply()) {
+                name = "call";
+            }
         }
 
         if (request.isCallSiteUnstable() || hasWithScope()) {
@@ -2006,7 +2023,7 @@
         assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
 
         final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
-        return inv.addSwitchPoint(reservedNameSwitchPoint);
+        return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
@@ -2029,7 +2046,7 @@
     // Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
     @SuppressWarnings("unused")
     private void declareAndSet(final String key, final Object value) {
-        final PropertyMap map = getMap();
+        final PropertyMap oldMap = getMap();
         final FindProperty find = findProperty(key, false);
         assert find != null;
 
@@ -2037,7 +2054,7 @@
         assert property != null;
         assert property.needsDeclaration();
 
-        final PropertyMap newMap = map.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
+        final PropertyMap newMap = oldMap.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
         setMap(newMap);
         set(key, value, 0);
     }
@@ -2166,7 +2183,7 @@
             }
         }
 
-        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
+        final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
 
         final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
         if (cinv != null) {
@@ -2429,7 +2446,7 @@
 
         @Override
         public void remove() {
-            throw new UnsupportedOperationException();
+            throw new UnsupportedOperationException("remove");
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Tue Oct 07 10:57:55 2014 -0700
@@ -32,9 +32,9 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.syntaxError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.SwitchPoint;
 import java.lang.reflect.Array;
 import java.util.Collections;
 import java.util.Iterator;
@@ -46,6 +46,7 @@
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.codegen.ApplySpecialization;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.ir.debug.JSONWriter;
@@ -113,6 +114,11 @@
     public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
 
     /**
+     * Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself.
+     */
+    public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class);
+
+    /**
      * Converts a switch tag value to a simple integer. deflt value if it can't.
      *
      * @param tag   Switch statement tag value.
@@ -290,7 +296,7 @@
 
         @Override
         public void remove() {
-            throw new UnsupportedOperationException();
+            throw new UnsupportedOperationException("remove");
         }
     }
 
@@ -328,7 +334,7 @@
 
                 @Override
                 public void remove() {
-                    throw new UnsupportedOperationException();
+                    throw new UnsupportedOperationException("remove");
                 }
             };
         }
@@ -998,4 +1004,19 @@
         return nx < ny;
     }
 
+    /**
+     * 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-&gt;call specialization
+     * @param name property name
+     */
+    public static void invalidateReservedBuiltinName(final String name) {
+        final Context context = Context.getContextTrusted();
+        final SwitchPoint sp = context.getBuiltinSwitchPoint(name);
+        assert sp != null;
+        if (sp != null) {
+            context.getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
+            SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+        }
+    }
 }
--- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Tue Oct 07 10:57:55 2014 -0700
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.SwitchPoint;
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -81,8 +80,8 @@
      * Creates the actual guarded invocation that represents the dynamic setter method for the property.
      * @return the actual guarded invocation that represents the dynamic setter method for the property.
      */
-    GuardedInvocation createGuardedInvocation() {
-        return createSetMethod().createGuardedInvocation();
+    GuardedInvocation createGuardedInvocation(final SwitchPoint builtinSwitchPoint) {
+        return createSetMethod(builtinSwitchPoint).createGuardedInvocation();
     }
 
     /**
@@ -119,7 +118,7 @@
         }
     }
 
-    private SetMethod createSetMethod() {
+    private SetMethod createSetMethod(final SwitchPoint builtinSwitchPoint) {
         if (find != null) {
             return createExistingPropertySetter();
         }
@@ -130,7 +129,7 @@
             return createGlobalPropertySetter();
         }
 
-        return createNewPropertySetter();
+        return createNewPropertySetter(builtinSwitchPoint);
     }
 
     private void checkStrictCreateNewVariable() {
@@ -185,8 +184,8 @@
         return new SetMethod(MH.filterArguments(global.addSpill(type, getName()), 0, ScriptObject.GLOBALFILTER), null);
     }
 
-    private SetMethod createNewPropertySetter() {
-        final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter() : createNewSpillPropertySetter();
+    private SetMethod createNewPropertySetter(final SwitchPoint builtinSwitchPoint) {
+        final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter(builtinSwitchPoint) : createNewSpillPropertySetter(builtinSwitchPoint);
         final PropertyListeners listeners = map.getListeners();
         if (listeners != null) {
             listeners.propertyAdded(sm.property);
@@ -194,7 +193,9 @@
         return sm;
     }
 
-    private SetMethod createNewSetter(final Property property) {
+    private SetMethod createNewSetter(final Property property, final SwitchPoint builtinSwitchPoint) {
+        property.setBuiltinSwitchPoint(builtinSwitchPoint);
+
         final PropertyMap oldMap   = getMap();
         final PropertyMap newMap   = getNewMap(property);
         final boolean     isStrict = NashornCallSiteDescriptor.isStrict(desc);
@@ -230,12 +231,12 @@
         return new SetMethod(MH.asType(MH.guardWithTest(extCheck, casGuard, nop), fastSetter.type()), property);
     }
 
-    private SetMethod createNewFieldSetter() {
-        return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type));
+    private SetMethod createNewFieldSetter(final SwitchPoint builtinSwitchPoint) {
+        return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type), builtinSwitchPoint);
     }
 
-    private SetMethod createNewSpillPropertySetter() {
-        return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type));
+    private SetMethod createNewSpillPropertySetter(final SwitchPoint builtinSwitchPoint) {
+        return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type), builtinSwitchPoint);
     }
 
     private PropertyMap getNewMap(final Property property) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/Specialization.java	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,114 @@
+/*
+ * 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.runtime;
+
+import java.lang.invoke.MethodHandle;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
+
+/**
+ * Specialization info for a {@link SpecializedFunction}
+ */
+public final class Specialization {
+    private final MethodHandle mh;
+    private final Class<? extends LinkLogic> linkLogicClass;
+    private final boolean isOptimistic;
+
+    /**
+     * Constructor
+     *
+     * @param mh  invoker method handler
+     */
+    public Specialization(final MethodHandle mh) {
+        this(mh, false);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param mh  invoker method handler
+     * @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
+     *   which would have to lead to a relink and return value processing
+     */
+    public Specialization(final MethodHandle mh, final boolean isOptimistic) {
+        this(mh, null, isOptimistic);
+    }
+
+    /**
+     * Constructor
+     *
+     * @param mh  invoker method handler
+     * @param linkLogicClass extra link logic needed for this function. Instances of this class also contains logic for checking
+     *  if this can be linked on its first encounter, which is needed as per our standard linker semantics
+     * @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
+     *   which would have to lead to a relink and return value processing
+     */
+    public Specialization(final MethodHandle mh, final Class<? extends LinkLogic> linkLogicClass, final boolean isOptimistic) {
+        this.mh             = mh;
+        this.isOptimistic   = isOptimistic;
+        if (linkLogicClass != null) {
+            //null out the "empty" link logic class for optimization purposes
+            //we only use the empty instance because we can't default class annotations
+            //to null
+            this.linkLogicClass = LinkLogic.isEmpty(linkLogicClass) ? null : linkLogicClass;
+        } else {
+            this.linkLogicClass = null;
+        }
+     }
+
+    /**
+     * Get the method handle for the invoker of this ScriptFunction
+     * @return the method handle
+     */
+    public MethodHandle getMethodHandle() {
+        return mh;
+    }
+
+    /**
+     * Get the link logic class for this ScriptFunction
+     * @return link logic class info, i.e. one whose instance contains stuff like
+     *  "do we need exception check for every call", and logic to check if we may link
+     */
+    public Class<? extends LinkLogic> getLinkLogicClass() {
+        return linkLogicClass;
+    }
+
+    /**
+     * An optimistic specialization is one that can throw UnwarrantedOptimismException.
+     * This is allowed for native methods, as long as they are functional, i.e. don't change
+     * any state between entering and throwing the UOE. Then we can re-execute a wider version
+     * of the method in the continuation. Rest-of method generation for optimistic builtins is
+     * of course not possible, but this approach works and fits into the same relinking
+     * framework
+     *
+     * @return true if optimistic
+     */
+    public boolean isOptimistic() {
+        return isOptimistic;
+    }
+
+}
+
--- a/src/jdk/nashorn/internal/runtime/StoredScript.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/StoredScript.java	Tue Oct 07 10:57:55 2014 -0700
@@ -55,8 +55,10 @@
     /**
      * Constructor.
      *
+     * @param compilationId compilation id
      * @param mainClassName main class name
      * @param classBytes map of class names to class bytes
+     * @param initializers initializer map, id -> FunctionInitializer
      * @param constants constants array
      */
     public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) {
@@ -67,6 +69,10 @@
         this.initializers = initializers;
     }
 
+    /**
+     * Get the compilation id for this StoredScript
+     * @return compilation id
+     */
     public int getCompilationId() {
         return compilationId;
     }
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,7 +25,6 @@
 
 package jdk.nashorn.internal.runtime;
 
-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.JSType.CONVERT_OBJECT_OPTIMISTIC;
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.nio.ByteBuffer;
@@ -58,7 +57,7 @@
     /**
      * Length of the array data. Not necessarily length of the wrapped array.
      */
-    private long length;
+    protected long length;
 
     /**
      * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
@@ -520,7 +519,7 @@
      * @param type new element type
      * @return new array data
      */
-    protected abstract ArrayData convert(Class<?> type);
+    public abstract ArrayData convert(Class<?> type);
 
     /**
      * Push an array of items to the end of the array
@@ -537,7 +536,7 @@
         final Class<?>  widest  = widestType(items);
 
         ArrayData newData = convert(widest);
-        long      pos     = newData.length();
+        long      pos     = newData.length;
         for (final Object item : items) {
             newData = newData.ensure(pos); //avoid sparse array
             newData.set((int)pos++, item, strict);
@@ -655,7 +654,7 @@
      * @param size current size
      * @return next size to allocate for internal array
      */
-    protected static int nextSize(final int size) {
+    public static int nextSize(final int size) {
         return alignUp(size + 1) * 2;
     }
 
@@ -681,6 +680,18 @@
         }
     }
 
+   /**
+     * Find a fast call if one exists
+     *
+     * @param clazz    array data class
+     * @param desc     callsite descriptor
+     * @param request  link request
+     * @return fast property getter if one is found
+     */
+    public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
+        return null;
+    }
+
     /**
      * Find a fast property getter if one exists
      *
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -39,7 +39,7 @@
     protected ArrayData underlying;
 
     ArrayFilter(final ArrayData underlying) {
-        super(underlying.length());
+        super(underlying.length);
         this.underlying = underlying;
     }
 
@@ -70,13 +70,13 @@
     @Override
     public void shiftLeft(final int by) {
         underlying.shiftLeft(by);
-        setLength(underlying.length());
+        setLength(underlying.length);
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         underlying = underlying.shiftRight(by);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -84,7 +84,7 @@
     @Override
     public ArrayData ensure(final long safeIndex) {
         underlying = underlying.ensure(safeIndex);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -92,7 +92,7 @@
     @Override
     public ArrayData shrink(final long newLength) {
         underlying = underlying.shrink(newLength);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -100,7 +100,7 @@
     @Override
     public ArrayData set(final int index, final Object value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -108,7 +108,7 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -116,7 +116,7 @@
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -124,7 +124,7 @@
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         underlying = underlying.set(index, value, strict);
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return this;
     }
@@ -189,28 +189,28 @@
     @Override
     public ArrayData delete(final int index) {
         underlying = underlying.delete(index);
-        setLength(underlying.length());
+        setLength(underlying.length);
         return this;
     }
 
     @Override
     public ArrayData delete(final long from, final long to) {
         underlying = underlying.delete(from, to);
-        setLength(underlying.length());
+        setLength(underlying.length);
         return this;
     }
 
     @Override
-    protected ArrayData convert(final Class<?> type) {
+    public ArrayData convert(final Class<?> type) {
         underlying = underlying.convert(type);
-        setLength(underlying.length());
+        setLength(underlying.length);
         return this;
     }
 
     @Override
     public Object pop() {
         final Object value = underlying.pop();
-        setLength(underlying.length());
+        setLength(underlying.length);
 
         return value;
     }
--- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -30,7 +30,6 @@
 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -77,11 +76,11 @@
      * array without reallocating, or if we are overwriting an already
      * allocated element
      *
-     * @param index
+     * @param index index to check
      * @return true if we don't need to do any array reallocation to fit an element at index
      */
     public final boolean hasRoomFor(final int index) {
-        return has(index) || (index == length() && ensure(index) == this);
+        return has(index) || (index == length && ensure(index) == this);
     }
 
     /**
@@ -116,6 +115,12 @@
     }
 
     /**
+     * Returns the type used to store an element in this array
+     * @return element type
+     */
+    public abstract Class<?> getElementType();
+
+    /**
      * Look up a continuous array element getter
      * @param get          getter, sometimes combined with a has check that throws CCE on failure for relink
      * @param returnType   return type
@@ -175,11 +180,6 @@
         return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz));
     }
 
-    @Override
-    public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
-        return null;
-    }
-
     /** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need
       the null case explicitly, which is the one that CCE doesn't handle */
     protected static final MethodHandle FAST_ACCESS_GUARD =
@@ -269,4 +269,72 @@
 
         return null;
     }
+
+    /**
+     * Specialization - fast push implementation
+     * @param arg argument
+     * @return new array length
+     */
+    public long fastPush(final int arg) {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast push implementation
+     * @param arg argument
+     * @return new array length
+     */
+    public long fastPush(final long arg) {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast push implementation
+     * @param arg argument
+     * @return new array length
+     */
+    public long fastPush(final double arg) {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast push implementation
+     * @param arg argument
+     * @return new array length
+     */
+    public long fastPush(final Object arg) {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast pop implementation
+     * @return element value
+     */
+    public int fastPopInt() {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast pop implementation
+     * @return element value
+     */
+    public long fastPopLong() {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast pop implementation
+     * @return element value
+     */
+    public double fastPopDouble() {
+       throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
+
+    /**
+     * Specialization - fast pop implementation
+     * @return element value
+     */
+    public Object fastPopObject() {
+        throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+    }
 }
--- a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.reflect.Array;
 import jdk.nashorn.internal.runtime.BitVector;
 
@@ -40,7 +39,7 @@
     DeletedArrayFilter(final ArrayData underlying) {
         super(underlying);
 
-        this.deleted = new BitVector(underlying.length());
+        this.deleted = new BitVector(underlying.length);
     }
 
     @Override
@@ -80,25 +79,25 @@
     @Override
     public void shiftLeft(final int by) {
         super.shiftLeft(by);
-        deleted.shiftLeft(by, length());
+        deleted.shiftLeft(by, length);
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         super.shiftRight(by);
-        deleted.shiftRight(by, length());
+        deleted.shiftRight(by, length);
 
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
             return new SparseArrayData(this, safeIndex + 1);
         }
 
         super.ensure(safeIndex);
-        deleted.resize(length());
+        deleted.resize(length);
 
         return this;
     }
@@ -106,7 +105,7 @@
     @Override
     public ArrayData shrink(final long newLength) {
         super.shrink(newLength);
-        deleted.resize(length());
+        deleted.resize(length);
 
         return this;
     }
@@ -147,7 +146,7 @@
     @Override
     public ArrayData delete(final int index) {
         final long longIndex = ArrayIndex.toLongIndex(index);
-        assert longIndex >= 0 && longIndex < length();
+        assert longIndex >= 0 && longIndex < length;
         deleted.set(longIndex);
         underlying.setEmpty(index);
         return this;
@@ -155,7 +154,7 @@
 
     @Override
     public ArrayData delete(final long fromIndex, final long toIndex) {
-        assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length();
+        assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length;
         deleted.setRange(fromIndex, toIndex + 1);
         underlying.setEmpty(fromIndex, toIndex);
         return this;
@@ -163,7 +162,7 @@
 
     @Override
     public Object pop() {
-        final long index = length() - 1;
+        final long index = length - 1;
 
         if (super.has((int)index)) {
             final boolean isDeleted = deleted.isSet(index);
@@ -180,7 +179,7 @@
         final ArrayData newArray = underlying.slice(from, to);
         final DeletedArrayFilter newFilter = new DeletedArrayFilter(newArray);
         newFilter.getDeleted().copy(deleted);
-        newFilter.getDeleted().shiftLeft(from, newFilter.length());
+        newFilter.getDeleted().shiftLeft(from, newFilter.length);
 
         return newFilter;
     }
--- a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -45,7 +45,7 @@
         if(hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) {
             return underlying;
         }
-        return new SparseArrayData(underlying, underlying.length());
+        return new SparseArrayData(underlying, underlying.length);
     }
 
     private boolean isEmpty() {
@@ -93,7 +93,7 @@
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
             return new SparseArrayData(this, safeIndex + 1);
         }
 
@@ -110,8 +110,9 @@
     @Override
     public ArrayData shiftRight(final int by) {
         super.shiftRight(by);
-        lo = Math.min(length(), lo + by);
-        hi = Math.min(length() - 1, hi + by);
+        final long len = length;
+        lo = Math.min(len, lo + by);
+        hi = Math.min(len - 1, hi + by);
 
         return isEmpty() ? getUnderlying() : this;
     }
@@ -237,7 +238,7 @@
 
     @Override
     public Object pop() {
-        final int index = (int)(length() - 1);
+        final int index = (int)length - 1;
         if (super.has(index)) {
             final boolean isDeleted = isDeleted(index);
             final Object value      = super.pop();
--- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -38,7 +37,7 @@
  * Implementation of {@link ArrayData} as soon as an int has been
  * written to the array. This is the default data for new arrays
  */
-final class IntArrayData extends ContinuousArrayData {
+final class IntArrayData extends ContinuousArrayData implements IntElements {
     /**
      * The wrapped array
      */
@@ -64,9 +63,19 @@
         this.array = array;
     }
 
+    @Override
+    public Class<?> getElementType() {
+        return int.class;
+    }
+
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
 
+    @Override
+    public Object[] asObjectArray() {
+        return toObjectArray();
+    }
+
     @SuppressWarnings("unused")
     private int getElem(final int index) {
         if (has(index)) {
@@ -96,23 +105,18 @@
 
     @Override
     public ArrayData copy() {
-        return new IntArrayData(array.clone(), (int) length());
-    }
-
-    @Override
-    public Object[] asObjectArray() {
-        return toObjectArray(array, (int) length());
+        return new IntArrayData(array.clone(), (int)length);
     }
 
     @Override
     public Object asArrayOfType(final Class<?> componentType) {
         if (componentType == int.class) {
-            return array.length == length() ? array.clone() : Arrays.copyOf(array, (int) length());
+            return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
         }
         return super.asArrayOfType(componentType);
     }
 
-    private static Object[] toObjectArray(final int[] array, final int length) {
+    private Object[] toObjectArray() {
         assert length <= array.length : "length exceeds internal array size";
         final Object[] oarray = new Object[array.length];
 
@@ -123,7 +127,7 @@
         return oarray;
     }
 
-    private static double[] toDoubleArray(final int[] array, final int length) {
+    private double[] toDoubleArray() {
         assert length <= array.length : "length exceeds internal array size";
         final double[] darray = new double[array.length];
 
@@ -134,7 +138,7 @@
         return darray;
     }
 
-    private static long[] toLongArray(final int[] array, final int length) {
+    private long[] toLongArray() {
         assert length <= array.length : "length exceeds internal array size";
         final long[] larray = new long[array.length];
 
@@ -145,18 +149,30 @@
         return larray;
     }
 
+    private LongArrayData convertToLong() {
+        return new LongArrayData(toLongArray(), (int)length);
+    }
+
+    private NumberArrayData convertToDouble() {
+        return new NumberArrayData(toDoubleArray(), (int)length);
+    }
+
+    private ObjectArrayData convertToObject() {
+        return new ObjectArrayData(toObjectArray(), (int)length);
+    }
+
     @Override
     public ArrayData convert(final Class<?> type) {
         if (type == Integer.class) {
             return this;
         }
-        final int length = (int) length();
         if (type == Long.class) {
-            return new LongArrayData(IntArrayData.toLongArray(array, length), length);
+            return convertToLong();
         } else if (type == Double.class) {
-            return new NumberArrayData(IntArrayData.toDoubleArray(array, length), length);
+            return convertToDouble();
         } else {
-            return new ObjectArrayData(IntArrayData.toObjectArray(array, length), length);
+            assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive());
+            return convertToObject();
         }
     }
 
@@ -167,7 +183,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length() - 1);
+        final ArrayData newData = ensure(by + length - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -213,7 +229,7 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
 
         return this;
     }
@@ -222,7 +238,7 @@
     public ArrayData set(final int index, final long value, final boolean strict) {
         if (JSType.isRepresentableAsInt(value)) {
             array[index] = JSType.toInt32(value);
-            setLength(Math.max(index + 1, length()));
+            setLength(Math.max(index + 1, length));
             return this;
         }
 
@@ -233,7 +249,7 @@
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (JSType.isRepresentableAsInt(value)) {
             array[index] = (int)(long)value;
-            setLength(Math.max(index + 1, length()));
+            setLength(Math.max(index + 1, length));
             return this;
         }
 
@@ -282,7 +298,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -297,11 +313,11 @@
 
     @Override
     public Object pop() {
-        if (length() == 0) {
+        if (length == 0) {
             return ScriptRuntime.UNDEFINED;
         }
 
-        final int newLength = (int) length() - 1;
+        final int newLength = (int)length - 1;
         final int elem = array[newLength];
         array[newLength] = 0;
         setLength(newLength);
@@ -311,7 +327,7 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? from + length() : from;
+        final long start     = from < 0 ? from + length : from;
         final long newLength = to - start;
 
         return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
@@ -319,18 +335,18 @@
 
     @Override
     public final ArrayData push(final boolean strict, final int item) {
-        final long      length = length();
-        final ArrayData newData = ensure(length);
+        final long      len     = length;
+        final ArrayData newData = ensure(len);
         if (newData == this) {
-            array[(int)length] = item;
+            array[(int)len] = item;
             return this;
         }
-        return newData.set((int)length, item, strict);
+        return newData.set((int)len, item, strict);
     }
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length();
+        final long oldLength = length;
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -355,4 +371,41 @@
 
         return returnValue;
     }
+
+    @Override
+    public long fastPush(final int arg) {
+        final int len = (int)length;
+        if (len == array.length) {
+            array = Arrays.copyOf(array, nextSize(len));
+        }
+        array[len] = arg;
+        return ++length;
+    }
+
+    //length must not be zero
+    @Override
+    public int fastPopInt() {
+        if (length == 0) {
+            throw new ClassCastException(); //relink
+        }
+        final int newLength = (int)--length;
+        final int elem = array[newLength];
+        array[newLength] = 0;
+        return elem;
+    }
+
+    @Override
+    public long fastPopLong() {
+        return fastPopInt();
+    }
+
+    @Override
+    public double fastPopDouble() {
+        return fastPopInt();
+    }
+
+    @Override
+    public Object fastPopObject() {
+        return fastPopInt();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntElements.java	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * 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.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with int elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface IntElements extends IntOrLongElements {
+    //empty
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * 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.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with int or long elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface IntOrLongElements extends NumericElements {
+    //empty
+}
--- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -27,7 +27,6 @@
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -39,7 +38,7 @@
  * Implementation of {@link ArrayData} as soon as a long has been
  * written to the array
  */
-final class LongArrayData extends ContinuousArrayData {
+final class LongArrayData extends ContinuousArrayData implements IntOrLongElements {
     /**
      * The wrapped array
      */
@@ -57,13 +56,18 @@
     }
 
     @Override
+    public Class<?> getElementType() {
+        return long.class;
+    }
+
+    @Override
     public ArrayData copy() {
-        return new LongArrayData(array.clone(), (int)length());
+        return new LongArrayData(array.clone(), (int)length);
     }
 
     @Override
     public Object[] asObjectArray() {
-        return toObjectArray(array, (int)length());
+        return toObjectArray(array, (int)length);
     }
 
     private static Object[] toObjectArray(final long[] array, final int length) {
@@ -80,7 +84,7 @@
     @Override
     public Object asArrayOfType(final Class<?> componentType) {
         if (componentType == long.class) {
-            return array.length == length() ? array.clone() : Arrays.copyOf(array, (int)length());
+            return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
         }
         return super.asArrayOfType(componentType);
     }
@@ -101,11 +105,11 @@
         if (type == Integer.class || type == Long.class) {
             return this;
         }
-        final int length = (int) length();
+        final int len = (int)length;
         if (type == Double.class) {
-            return new NumberArrayData(LongArrayData.toDoubleArray(array, length), length);
+            return new NumberArrayData(LongArrayData.toDoubleArray(array, len), len);
         }
-        return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length);
+        return new ObjectArrayData(LongArrayData.toObjectArray(array, len), len);
     }
 
     @Override
@@ -115,7 +119,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length() - 1);
+        final ArrayData newData = ensure(by + length - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -161,14 +165,14 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
@@ -176,7 +180,7 @@
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (JSType.isRepresentableAsLong(value)) {
             array[index] = (long)value;
-            setLength(Math.max(index + 1, length()));
+            setLength(Math.max(index + 1, length));
             return this;
         }
         return convert(Double.class).set(index, value, strict);
@@ -252,7 +256,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -267,11 +271,11 @@
 
     @Override
     public Object pop() {
-        if (length() == 0) {
+        if (length == 0) {
             return ScriptRuntime.UNDEFINED;
         }
 
-        final int newLength = (int) (length() - 1);
+        final int newLength = (int)length - 1;
         final long elem = array[newLength];
         array[newLength] = 0;
         setLength(newLength);
@@ -281,25 +285,25 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? from + length() : from;
+        final long start     = from < 0 ? from + length : from;
         final long newLength = to - start;
         return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
     public final ArrayData push(final boolean strict, final long item) {
-        final long      length = length();
-        final ArrayData newData = ensure(length);
+        final long      len     = length;
+        final ArrayData newData = ensure(len);
         if (newData == this) {
-            array[(int)length] = item;
+            array[(int)len] = item;
             return this;
         }
-        return newData.set((int)length, item, strict);
+        return newData.set((int)len, item, strict);
     }
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length();
+        final long oldLength = length;
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -324,4 +328,40 @@
 
         return returnValue;
     }
+
+    @Override
+    public long fastPush(final int arg) {
+        return fastPush((long)arg);
+    }
+
+    @Override
+    public long fastPush(final long arg) {
+        final int len = (int)length;
+        if (len == array.length) {
+            array = Arrays.copyOf(array, nextSize(len));
+        }
+        array[len] = arg;
+        return ++length;
+    }
+
+    @Override
+    public long fastPopLong() {
+        if (length == 0) {
+            throw new ClassCastException();
+        }
+        final int newLength = (int)--length;
+        final long elem = array[newLength];
+        array[newLength] = 0;
+        return elem;
+    }
+
+    @Override
+    public double fastPopDouble() {
+        return fastPopLong();
+   }
+
+    @Override
+    public Object fastPopObject() {
+        return fastPopLong();
+    }
 }
--- a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -58,19 +58,19 @@
 
     @Override
     public ArrayData convert(final Class<?> type) {
-        final long length = length();
+        final long len = length;
         final ArrayData arrayData;
         if (type == Long.class) {
-            arrayData = new LongArrayData(new long[ArrayData.nextSize((int)length)], (int)length);
+            arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len);
         } else if (type == Double.class) {
-            arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)length)], (int)length);
+            arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len);
         } else if (type == Integer.class) {
-            arrayData = new IntArrayData(new int[ArrayData.nextSize((int)length)], (int)length);
+            arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len);
         } else {
             assert !type.isPrimitive();
-            arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)length)], (int)length);
+            arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len);
         }
-        return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, length - 1);
+        return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1);
     }
 
     @Override
@@ -90,11 +90,11 @@
         }
 
         // Don't trample the shared EMPTY_ARRAY.
-        if (length() == 0) {
-            return new NoTypeArrayData(Math.max(safeIndex + 1, length()));
+        if (length == 0) {
+            return new NoTypeArrayData(Math.max(safeIndex + 1, length));
         }
 
-        setLength(Math.max(safeIndex + 1, length()));
+        setLength(Math.max(safeIndex + 1, length));
         return this;
     }
 
--- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -28,7 +28,6 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -38,7 +37,7 @@
  * Implementation of {@link ArrayData} as soon as a double has been
  * written to the array
  */
-final class NumberArrayData extends ContinuousArrayData {
+final class NumberArrayData extends ContinuousArrayData implements NumericElements {
     /**
      * The wrapped array
      */
@@ -56,13 +55,18 @@
     }
 
     @Override
+    public Class<?> getElementType() {
+        return double.class;
+    }
+
+    @Override
     public ArrayData copy() {
-        return new NumberArrayData(array.clone(), (int) length());
+        return new NumberArrayData(array.clone(), (int)length);
     }
 
     @Override
     public Object[] asObjectArray() {
-        return toObjectArray(array, (int) length());
+        return toObjectArray(array, (int)length);
     }
 
     private static Object[] toObjectArray(final double[] array, final int length) {
@@ -78,7 +82,7 @@
     @Override
     public Object asArrayOfType(final Class<?> componentType) {
         if(componentType == double.class) {
-            return array.length == length() ? array.clone() : Arrays.copyOf(array, (int) length());
+            return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
         }
         return super.asArrayOfType(componentType);
     }
@@ -86,8 +90,8 @@
     @Override
     public ArrayData convert(final Class<?> type) {
         if (type != Double.class && type != Integer.class && type != Long.class) {
-            final int length = (int) length();
-            return new ObjectArrayData(NumberArrayData.toObjectArray(array, length), length);
+            final int len = (int)length;
+            return new ObjectArrayData(NumberArrayData.toObjectArray(array, len), len);
         }
         return this;
     }
@@ -99,7 +103,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length() - 1);
+        final ArrayData newData = ensure(by + length - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -144,21 +148,21 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
@@ -227,7 +231,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -242,11 +246,11 @@
 
     @Override
     public Object pop() {
-        if (length() == 0) {
+        if (length == 0) {
             return UNDEFINED;
         }
 
-        final int newLength = (int) (length() - 1);
+        final int newLength = (int)length - 1;
         final double elem = array[newLength];
         array[newLength] = 0;
         setLength(newLength);
@@ -255,25 +259,25 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? from + length() : from;
+        final long start     = from < 0 ? from + length : from;
         final long newLength = to - start;
         return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
     public final ArrayData push(final boolean strict, final double item) {
-        final long      length = length();
-        final ArrayData newData = ensure(length);
+        final long      len     = length;
+        final ArrayData newData = ensure(len);
         if (newData == this) {
-            array[(int)length] = item;
+            array[(int)len] = item;
             return this;
         }
-        return newData.set((int)length, item, strict);
+        return newData.set((int)len, item, strict);
     }
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length();
+        final long oldLength = length;
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
@@ -298,4 +302,41 @@
 
         return returnValue;
     }
+
+    @Override
+    public long fastPush(final int arg) {
+        return fastPush((double)arg);
+    }
+
+    @Override
+    public long fastPush(final long arg) {
+        return fastPush((double)arg);
+    }
+
+    @Override
+    public long fastPush(final double arg) {
+        final int len = (int)length;
+        if (len == array.length) {
+           //note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
+           array = Arrays.copyOf(array, nextSize(len));
+        }
+        array[len] = arg;
+        return ++length;
+    }
+
+    @Override
+    public double fastPopDouble() {
+        if (length == 0) {
+            throw new ClassCastException();
+        }
+        final int newLength = (int)--length;
+        final double elem = array[newLength];
+        array[newLength] = 0;
+        return elem;
+    }
+
+    @Override
+    public Object fastPopObject() {
+        return fastPopDouble();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,35 @@
+/*
+ * 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.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with numeric elements
+ * (int, long or double)
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface NumericElements {
+    //empty
+}
--- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
@@ -57,20 +56,25 @@
     }
 
     @Override
+    public Class<?> getElementType() {
+        return Object.class;
+    }
+
+    @Override
     public ArrayData copy() {
-        return new ObjectArrayData(array.clone(), (int) length());
+        return new ObjectArrayData(array.clone(), (int)length);
     }
 
     @Override
     public Object[] asObjectArray() {
-        return array.length == length() ? array.clone() : asObjectArrayCopy();
+        return array.length == length ? array.clone() : asObjectArrayCopy();
     }
 
     private Object[] asObjectArrayCopy() {
-        final long l = length();
-        assert l <= Integer.MAX_VALUE;
-        final Object[] copy = new Object[(int)l];
-        System.arraycopy(array, 0, copy, 0, (int)l);
+        final long len = length;
+        assert len <= Integer.MAX_VALUE;
+        final Object[] copy = new Object[(int)len];
+        System.arraycopy(array, 0, copy, 0, (int)len);
         return copy;
     }
 
@@ -86,7 +90,7 @@
 
     @Override
     public ArrayData shiftRight(final int by) {
-        final ArrayData newData = ensure(by + length() - 1);
+        final ArrayData newData = ensure(by + length - 1);
         if (newData != this) {
             newData.shiftRight(by);
             return newData;
@@ -118,28 +122,28 @@
     @Override
     public ArrayData set(final int index, final Object value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         array[index] = value;
-        setLength(Math.max(index + 1, length()));
+        setLength(Math.max(index + 1, length));
         return this;
     }
 
@@ -216,7 +220,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -232,12 +236,48 @@
     }
 
     @Override
+    public long fastPush(final int arg) {
+        return fastPush((Object)arg);
+    }
+
+    @Override
+    public long fastPush(final long arg) {
+        return fastPush((Object)arg);
+    }
+
+    @Override
+    public long fastPush(final double arg) {
+        return fastPush((Object)arg);
+    }
+
+    @Override
+    public long fastPush(final Object arg) {
+        final int len = (int)length;
+        if (len == array.length) {
+            array = Arrays.copyOf(array, nextSize(len));
+        }
+        array[len] = arg;
+        return ++length;
+    }
+
+    @Override
+    public Object fastPopObject() {
+        if (length == 0) {
+            return ScriptRuntime.UNDEFINED;
+        }
+        final int newLength = (int)--length;
+        final Object elem = array[newLength];
+        array[newLength] = ScriptRuntime.EMPTY;
+        return elem;
+    }
+
+    @Override
     public Object pop() {
-        if (length() == 0) {
+        if (length == 0) {
             return ScriptRuntime.UNDEFINED;
         }
 
-        final int newLength = (int) (length() - 1);
+        final int newLength = (int)length - 1;
         final Object elem = array[newLength];
         setEmpty(newLength);
         setLength(newLength);
@@ -246,25 +286,25 @@
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        final long start     = from < 0 ? from + length() : from;
+        final long start     = from < 0 ? from + length : from;
         final long newLength = to - start;
         return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     }
 
     @Override
     public ArrayData push(final boolean strict, final Object item) {
-        final long      length = length();
-        final ArrayData newData = ensure(length);
+        final long      len     = length;
+        final ArrayData newData = ensure(len);
         if (newData == this) {
-            array[(int)length] = item;
+            array[(int)len] = item;
             return this;
         }
-        return newData.set((int)length, item, strict);
+        return newData.set((int)len, item, strict);
     }
 
     @Override
     public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
-        final long oldLength = length();
+        final long oldLength = length;
         final long newLength = oldLength - removed + added;
         if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
             throw new UnsupportedOperationException();
--- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -53,28 +53,28 @@
 
     SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
         super(length);
-        assert underlying.length() <= length;
+        assert underlying.length <= length;
         this.underlying = underlying;
-        this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length());
+        this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length);
         this.sparseMap = sparseMap;
     }
 
     @Override
     public ArrayData copy() {
-        return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap));
+        return new SparseArrayData(underlying.copy(), length, new TreeMap<>(sparseMap));
     }
 
     @Override
     public Object[] asObjectArray() {
-        final int length = (int) Math.min(length(), Integer.MAX_VALUE);
-        final int underlyingLength = (int) Math.min(length, underlying.length());
-        final Object[] objArray = new Object[length];
+        final int len = (int)Math.min(length, Integer.MAX_VALUE);
+        final int underlyingLength = (int)Math.min(len, underlying.length);
+        final Object[] objArray = new Object[len];
 
         for (int i = 0; i < underlyingLength; i++) {
             objArray[i] = underlying.getObject(i);
         }
 
-        Arrays.fill(objArray, underlyingLength, length, ScriptRuntime.UNDEFINED);
+        Arrays.fill(objArray, underlyingLength, len, ScriptRuntime.UNDEFINED);
 
         for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
             final long key = entry.getKey();
@@ -104,14 +104,14 @@
         }
 
         sparseMap = newSparseMap;
-        setLength(Math.max(length() - by, 0));
+        setLength(Math.max(length - by, 0));
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
-        if (underlying.length() + by > maxDenseLength) {
-            for (long i = maxDenseLength - by; i < underlying.length(); i++) {
+        if (underlying.length + by > maxDenseLength) {
+            for (long i = maxDenseLength - by; i < underlying.length; i++) {
                 if (underlying.has((int) i)) {
                     newSparseMap.put(Long.valueOf(i + by), underlying.getObject((int) i));
                 }
@@ -127,23 +127,23 @@
         }
 
         sparseMap = newSparseMap;
-        setLength(length() + by);
+        setLength(length + by);
 
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) {
+        if (safeIndex < maxDenseLength && underlying.length <= safeIndex) {
             underlying = underlying.ensure(safeIndex);
         }
-        setLength(Math.max(safeIndex + 1, length()));
+        setLength(Math.max(safeIndex + 1, length));
         return this;
     }
 
     @Override
     public ArrayData shrink(final long newLength) {
-        if (newLength < underlying.length()) {
+        if (newLength < underlying.length) {
             underlying = underlying.shrink(newLength);
             underlying.setLength(newLength);
             sparseMap.clear();
@@ -160,11 +160,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length(), length()));
+            setLength(Math.max(underlying.length, length));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length()));
+            setLength(Math.max(longIndex + 1, length));
         }
 
         return this;
@@ -175,11 +175,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length(), length()));
+            setLength(Math.max(underlying.length, length));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length()));
+            setLength(Math.max(longIndex + 1, length));
         }
         return this;
     }
@@ -189,11 +189,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length(), length()));
+            setLength(Math.max(underlying.length, length));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length()));
+            setLength(Math.max(longIndex + 1, length));
         }
         return this;
     }
@@ -203,11 +203,11 @@
         if (index >= 0 && index < maxDenseLength) {
             ensure(index);
             underlying = underlying.set(index, value, strict);
-            setLength(Math.max(underlying.length(), length()));
+            setLength(Math.max(underlying.length, length));
         } else {
             final Long longIndex = indexToKey(index);
             sparseMap.put(longIndex, value);
-            setLength(Math.max(longIndex + 1, length()));
+            setLength(Math.max(longIndex + 1, length));
         }
         return this;
     }
@@ -294,7 +294,7 @@
     @Override
     public boolean has(final int index) {
         if (index >= 0 && index < maxDenseLength) {
-            return index < underlying.length() && underlying.has(index);
+            return index < underlying.length && underlying.has(index);
         }
 
         return sparseMap.containsKey(indexToKey(index));
@@ -303,7 +303,7 @@
     @Override
     public ArrayData delete(final int index) {
         if (index >= 0 && index < maxDenseLength) {
-            if (index < underlying.length()) {
+            if (index < underlying.length) {
                 underlying = underlying.delete(index);
             }
         } else {
@@ -315,8 +315,8 @@
 
     @Override
     public ArrayData delete(final long fromIndex, final long toIndex) {
-        if (fromIndex < maxDenseLength && fromIndex < underlying.length()) {
-            underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length() - 1));
+        if (fromIndex < maxDenseLength && fromIndex < underlying.length) {
+            underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length - 1));
         }
         if (toIndex >= maxDenseLength) {
             sparseMap.subMap(fromIndex, true, toIndex, true).clear();
@@ -329,37 +329,37 @@
     }
 
     @Override
-    protected ArrayData convert(final Class<?> type) {
+    public ArrayData convert(final Class<?> type) {
         underlying = underlying.convert(type);
         return this;
     }
 
     @Override
     public Object pop() {
-        if (length() == 0) {
+        if (length == 0) {
             return ScriptRuntime.UNDEFINED;
         }
-        if (length() == underlying.length()) {
+        if (length == underlying.length) {
             final Object result = underlying.pop();
-            setLength(underlying.length());
+            setLength(underlying.length);
             return result;
         }
-        setLength(length() - 1);
-        final Long key = Long.valueOf(length());
+        setLength(length - 1);
+        final Long key = Long.valueOf(length);
         return sparseMap.containsKey(key) ? sparseMap.remove(key) : ScriptRuntime.UNDEFINED;
     }
 
     @Override
     public ArrayData slice(final long from, final long to) {
-        assert to <= length();
-        final long start = from < 0 ? (from + length()) : from;
+        assert to <= length;
+        final long start = from < 0 ? (from + length) : from;
         final long newLength = to - start;
 
         if (start >= 0 && to <= maxDenseLength) {
-            if (newLength <= underlying.length()) {
+            if (newLength <= underlying.length) {
                 return underlying.slice(from, to);
             }
-            return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length(), newLength);
+            return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length, newLength);
         }
 
         ArrayData sliced = EMPTY_ARRAY;
@@ -369,13 +369,13 @@
                 sliced = sliced.set((int)(i - start), getObject((int)i), false);
             }
         }
-        assert sliced.length() == newLength;
+        assert sliced.length == newLength;
         return sliced;
     }
 
     @Override
     public long nextIndex(final long index) {
-        if (index < underlying.length() - 1) {
+        if (index < underlying.length - 1) {
             return underlying.nextIndex(index);
         }
 
@@ -383,6 +383,6 @@
         if (nextKey != null) {
             return nextKey;
         }
-        return length();
+        return length;
     }
 }
--- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
-
 import java.lang.invoke.MethodHandle;
 import java.nio.Buffer;
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -55,11 +54,11 @@
     }
 
     /**
-     * Length in elements. Accessed from {@code ArrayBufferView}
+     * Length in number of elements. Accessed from {@code ArrayBufferView}
      * @return element length
      */
     public final int getElementLength() {
-        return (int)length();
+        return (int)length;
     }
 
     /**
@@ -120,7 +119,7 @@
 
     @Override
     public final boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -134,7 +133,7 @@
     }
 
     @Override
-    protected ArrayData convert(final Class<?> type) {
+    public ArrayData convert(final Class<?> type) {
         throw new UnsupportedOperationException();
     }
 
--- a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,7 +26,6 @@
 package jdk.nashorn.internal.runtime.arrays;
 
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
 import java.lang.reflect.Array;
 import jdk.nashorn.internal.runtime.BitVector;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
@@ -41,7 +40,7 @@
     UndefinedArrayFilter(final ArrayData underlying) {
         super(underlying);
 
-        this.undefined = new BitVector(underlying.length());
+        this.undefined = new BitVector(underlying.length);
     }
 
     @Override
@@ -81,25 +80,25 @@
     @Override
     public void shiftLeft(final int by) {
         super.shiftLeft(by);
-        undefined.shiftLeft(by, length());
+        undefined.shiftLeft(by, length);
     }
 
     @Override
     public ArrayData shiftRight(final int by) {
         super.shiftRight(by);
-        undefined.shiftRight(by, length());
+        undefined.shiftRight(by, length);
 
         return this;
     }
 
     @Override
     public ArrayData ensure(final long safeIndex) {
-        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
+        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
             return new SparseArrayData(this, safeIndex + 1);
         }
 
         super.ensure(safeIndex);
-        undefined.resize(length());
+        undefined.resize(length);
 
         return this;
     }
@@ -107,7 +106,7 @@
     @Override
     public ArrayData shrink(final long newLength) {
         super.shrink(newLength);
-        undefined.resize(length());
+        undefined.resize(length);
 
         return this;
     }
@@ -217,7 +216,7 @@
 
     @Override
     public Object pop() {
-        final long index = length() - 1;
+        final long index = length - 1;
 
         if (super.has((int)index)) {
             final boolean isUndefined = undefined.isSet(index);
@@ -234,7 +233,7 @@
         final ArrayData newArray = underlying.slice(from, to);
         final UndefinedArrayFilter newFilter = new UndefinedArrayFilter(newArray);
         newFilter.getUndefined().copy(undefined);
-        newFilter.getUndefined().shiftLeft(from, newFilter.length());
+        newFilter.getUndefined().shiftLeft(from, newFilter.length);
 
         return newFilter;
     }
--- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Tue Oct 07 10:57:55 2014 -0700
@@ -26,14 +26,16 @@
 package jdk.nashorn.internal.runtime.linker;
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
-
 import java.lang.invoke.MethodHandle;
 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.runtime.Context;
 import jdk.nashorn.internal.runtime.FindProperty;
+import jdk.nashorn.internal.runtime.GlobalConstants;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.UserAccessorProperty;
 
@@ -86,27 +88,41 @@
                                                     final MethodHandle protoFilter) {
         final CallSiteDescriptor desc = request.getCallSiteDescriptor();
 
-        if(desc.getNameTokenCount() > 2) {
+        //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
+        //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
+        //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
+        if (desc.getNameTokenCount() > 2) {
             final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
             final FindProperty find = wrappedReceiver.findProperty(name, true);
-            if(find == null) {
+
+            if (find == null) {
                 // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
                 return null;
-            } else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
+            }
+
+            final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
+            if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
+                return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
+            }
+
+            if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
                 // If property is found in the prototype object bind the method handle directly to
                 // the proto filter instead of going through wrapper instantiation below.
                 final ScriptObject proto = wrappedReceiver.getProto();
                 final GuardedInvocation link = proto.lookup(desc, request);
 
                 if (link != null) {
-                    final MethodHandle invocation = link.getInvocation();
+                    final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
+
                     final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
                     final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
                     final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
+
                     return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
                 }
             }
         }
+
         final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
         if (link != null) {
             MethodHandle method = link.getInvocation();
@@ -116,8 +132,10 @@
                 assert receiverType.isAssignableFrom(wrapType.returnType());
                 method = MH.filterArguments(method, 0, MH.asType(wrapFilter, wrapType.changeReturnType(receiverType)));
             }
+
             return new GuardedInvocation(method, guard, link.getSwitchPoints(), null);
         }
+
         return null;
     }
 }
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java	Tue Oct 07 10:57:55 2014 -0700
@@ -25,6 +25,9 @@
 
 package jdk.nashorn.internal.runtime.regexp;
 
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
 import jdk.nashorn.internal.runtime.ParserException;
 import jdk.nashorn.internal.runtime.options.Options;
 
@@ -39,6 +42,15 @@
     private final static String JDK  = "jdk";
     private final static String JONI = "joni";
 
+    /** Weak cache of already validated regexps - when reparsing, we don't, for example
+     *  need to recompile (reverify) all regexps that have previously been parsed by this
+     *  RegExpFactory in a previous compilation. This saves significant time in e.g. avatar
+     *  startup */
+    private static final Set<String> VALID_CACHE_SET =
+            Collections.newSetFromMap(
+                    Collections.synchronizedMap(
+                            new WeakHashMap<String, Boolean>()));
+
     static {
         final String impl = Options.getStringProperty("nashorn.regexp.impl", JONI);
         switch (impl) {
@@ -88,7 +100,9 @@
      */
     // @SuppressWarnings({"unused"})
     public static void validate(final String pattern, final String flags) throws ParserException {
-        instance.compile(pattern, flags);
+        if (VALID_CACHE_SET.add(pattern + flags)) {
+            instance.compile(pattern, flags);
+        }
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Wed Oct 01 07:47:24 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Tue Oct 07 10:57:55 2014 -0700
@@ -203,6 +203,7 @@
 
 nashorn.option.optimistic.types = {                                                                      \
     name="--optimistic-types",                                                                           \
+    short_name="-ot",                                                                                    \
     is_undocumented=true,                                                                                \
     desc="Use optimistic type assumptions with deoptimizing recompilation.", \
     default=true                                   \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/examples/charcodeat-benchmark.js	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * Simple benchmark to measure charCodeAt specialized method performance
+ */
+
+var str = "sghjkdsfkjghsdfjkfkjdfkjdfjkdfjkfdjkfdkfldjfhdfpkjdhafgksdjfgldfgjldfkjgdlfjgldkfjgkldfj";
+var RESULT1 = 9187;
+var RESULT2 = 1496;
+
+function f() {
+    var len = str.length;
+    var c = 0;
+    for (var i = 0; i < len; i++) {
+	c += str.charCodeAt(i);
+    }
+    return c;
+}
+
+function bench(res) {
+    var d = new Date;
+    var sum = 0;
+    for (var i = 0; i < 1e6; i++) {
+	sum |= f();
+    }
+    if (sum == res) {
+	print("Verified OK"); 
+    } else {
+	print("Verification failed " + sum + " should be " + res);
+    }
+    print((new Date - d) + " ms");
+}
+
+bench(RESULT1);
+
+print("Replacing charCodeAt... ");
+
+String.prototype.charCodeAt = function() { return 17; }
+
+bench(RESULT2);
+
+print("Done");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/examples/push-pop-benchmark.js	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * Simple benchmark to measure push/pop specialized method performance
+ */
+
+var a = [];
+
+var RESULT = 15;
+
+function bench() {
+    var sum = 0;
+    for (var i=0;i<10;i++) {
+	a.push(i);
+    }
+    for (var i=0;i<10;i++) {
+	sum |= a.pop();
+    }
+    return sum;
+}
+
+function runbench() {
+    var sum = 0;
+    for (var iters = 0; iters<1e8; iters++) {
+	sum |= bench();
+    }
+    return sum;
+}
+
+var d = new Date;
+var res = runbench();
+print((new Date - d) + " ms");
+print();
+if (res != RESULT) {
+    print("ERROR: Wrong result - should be " + RESULT);
+} else {
+    print("Verified OK - result is correct");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call5.js	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ *
+ * 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_call5.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() { print("New function for apply - not a property"); }
+  
+test(4712);
+print(x.a);
+
+
+var x2 = {
+    a : 0,
+    b : 0,
+    c : 0,
+    initialize : function(x,y,z) {
+    this.a = x;
+    this.b = y;
+    this.c = z;
+    }
+};
+
+function test2() {
+    x2.initialize.apply(x2, arguments);
+}
+
+test2(4711,23,17);
+print(x2.a);
+print(x2.b);
+print(x2.c);
+
+print("Overwriting apply now");
+x2.initialize['apply'] = function() { print("New function for apply - not a property"); }
+
+test(4712);
+print(x2.a);
+
+var x3 = {
+    a : 0,
+    b : 0,
+    c : 0,
+    initialize : function(x,y,z) {
+    this.a = x;
+    this.b = y;
+    this.c = z;
+    }
+};
+
+function test3() {
+    x3.initialize.apply(x3, arguments);
+}
+
+test3(4711,23,17);
+print(x3.a);
+print(x3.b);
+print(x3.c);
+
+print("Overwriting apply now");
+eval("x3.initialize['apply'] = function() { print('New function for apply - not a property'); }");
+
+test(4712);
+print(x3.a);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call5.js.EXPECTED	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,19 @@
+start
+4711
+23
+17
+Overwriting apply now
+New function for apply - not a property
+4711
+4711
+23
+17
+Overwriting apply now
+New function for apply - not a property
+4711
+4711
+23
+17
+Overwriting apply now
+New function for apply - not a property
+4711
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/fastpushpop.js	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * fastpushpop.js: make sure guards work for fast push implementation
+ * and normal one
+ *
+ * @test
+ * @run
+ */
+
+var a = [1,2,3];
+a.push(4);
+a.push(5);
+a.push(6);
+print(a);
+
+var a2 = Object.defineProperty(a,"length", { writable: false });
+try { 
+    a2.push(7);
+} catch (e) {
+    print("first: " + (e instanceof TypeError));
+}
+
+print(a2);
+
+var b = [1,2,3,,,,4711.17,"dingo!"];
+b.push(4);
+b.push(5);
+b.push(6);
+print(b);
+
+var b2 = Object.defineProperty(b,"length", { writable: false });
+try { 
+    b2.push(7);
+} catch (e) {
+    print("second: " + (e instanceof TypeError));
+}
+
+print(b2);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/fastpushpop.js.EXPECTED	Tue Oct 07 10:57:55 2014 -0700
@@ -0,0 +1,6 @@
+1,2,3,4,5,6
+first: true
+1,2,3,4,5,6,7
+1,2,3,,,,4711.17,dingo!,4,5,6
+second: true
+1,2,3,,,,4711.17,dingo!,4,5,6,7
--- a/test/script/basic/run-octane.js	Wed Oct 01 07:47:24 2014 -0700
+++ b/test/script/basic/run-octane.js	Tue Oct 07 10:57:55 2014 -0700
@@ -54,7 +54,7 @@
         }
     }
 
-    print_verbose(arg, "loading '" + arg.name + "' [" + f + "]...");
+    print_verbose(arg, "loading '" + arg.name + "' [" + f + "]... " + file_name);
     load(file_name);
     }
 
@@ -139,7 +139,7 @@
     mean_score /= iters;
     } catch (e) {
     print_always(arg, "*** Aborted and setting score to zero. Reason: " + e);
-    if (e instanceof java.lang.Throwable) {
+    if (is_this_nashorn() && e instanceof java.lang.Throwable) {
         e.printStackTrace();
     }
     mean_score = min_score = max_score = 0;
@@ -148,7 +148,7 @@
 
     var res = mean_score.toFixed(0);
     if (verbose) {
-    res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
+	res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
     }
     print_always(arg, res);
 }