changeset 1045:076b1f38a5cc jdk8u40-b10

Merge
author asaha
date Tue, 14 Oct 2014 10:20:24 -0700
parents fdb261020de8 (current diff) b962745a8ccc (diff)
children 57c7b273277e
files src/jdk/nashorn/internal/objects/annotations/SpecializedConstructor.java
diffstat 108 files changed, 3371 insertions(+), 999 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/fixwhitespace.sh	Tue Oct 14 10:20:24 2014 -0700
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+# 
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+# 
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+# 
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+# 
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+fix() {
+    #convert tabs to spaces
+    find . -name $1 -exec sed -i "" 's/	/    /g' {} \;
+    #remove trailing whitespace
+    find . -name $1 -exec sed -i "" 's/[ 	]*$//' \{} \;
+}
+
+if [ ! -z $1 ]; then 
+    fix $1;
+else
+    fix "*.java"
+    fix "*.js"
+fi
--- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Wed Oct 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java	Tue Oct 14 10:20:24 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,13 +77,16 @@
 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;
 import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
 
 /**
  * Base class for all method generating classes.
@@ -95,6 +99,8 @@
     private final Type returnType;
     private final Type[] argumentTypes;
 
+    static final Type EMPTY_LINK_LOGIC_TYPE = Type.getType(LinkLogic.getEmptyLinkLogicClass());
+
     MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
         super(ASM4, mv);
         this.access        = access;
@@ -380,6 +386,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 +399,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 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java	Tue Oct 14 10:20:24 2014 -0700
@@ -37,8 +37,8 @@
 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.SpecializedFunction.LinkLogic;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
 
@@ -56,8 +56,8 @@
     static final String SETTER_ANNO_DESC        = Type.getDescriptor(Setter.class);
     static final String PROPERTY_ANNO_DESC      = Type.getDescriptor(Property.class);
     static final String WHERE_ENUM_DESC         = Type.getDescriptor(Where.class);
+    static final String LINK_LOGIC_DESC         = Type.getDescriptor(LinkLogic.class);
     static final String SPECIALIZED_FUNCTION    = Type.getDescriptor(SpecializedFunction.class);
-    static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class);
 
     static final Map<String, Kind> annotations = new HashMap<>();
 
@@ -69,7 +69,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 +118,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 +175,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 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Tue Oct 14 10:20:24 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/make/BuildNashorn.gmk	Wed Oct 08 14:16:54 2014 -0700
+++ b/make/BuildNashorn.gmk	Tue Oct 14 10:20:24 2014 -0700
@@ -65,7 +65,7 @@
     SETUP := GENERATE_NEWBYTECODE_DEBUG, \
     SRC := $(NASGEN_SRC) $(ASM_SRC), \
     BIN := $(NASHORN_OUTPUTDIR)/nasgen_classes, \
-    ADD_JAVAC_FLAGS := -cp $(NASHORN_OUTPUTDIR)/nashorn_classes))
+    ADD_JAVAC_FLAGS := -bootclasspath "$(BOOT_RTJAR)$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes"))
 
 # Nasgen needs nashorn classes
 $(BUILD_NASGEN): $(BUILD_NASHORN)
--- a/make/build.xml	Wed Oct 08 14:16:54 2014 -0700
+++ b/make/build.xml	Tue Oct 14 10:20:24 2014 -0700
@@ -78,7 +78,7 @@
       <istrue value="${jfr}"/>
     </condition>
   </target>
-
+  
   <target name="init" depends="init-conditions, init-cc">
     <!-- extends jvm args -->
     <property name="run.test.jvmargs" value="${run.test.jvmargs.main} ${run.test.cc.jvmargs} ${jfr.options}"/>
@@ -419,6 +419,7 @@
         <propertyref prefix="test-sys-prop-no-security."/>
         <mapper from="test-sys-prop-no-security.*" to="*" type="glob"/>
       </propertyset>
+      <sysproperty key="optimistic.override" value="${optimistic}"/>
       <classpath>
           <pathelement path="${run.test.classpath}"/>
       </classpath>
@@ -430,7 +431,7 @@
     <delete dir="${build.dir}/nashorn_code_cache"/>
     <property name="debug.test.jvmargs" value=""/>
     <testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
-       verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
+	    verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
       <jvmarg line="${ext.class.path}"/>
       <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
       <jvmarg line="${debug.test.jvmargs}"/>
@@ -441,6 +442,7 @@
         <propertyref prefix="test-sys-prop."/>
         <mapper from="test-sys-prop.*" to="*" type="glob"/>
       </propertyset>
+      <sysproperty key="optimistic.override" value="${optimistic}"/>
       <sysproperty key="test.js.excludes.file" value="${exclude.list}"/>
       <classpath>
           <pathelement path="${run.test.classpath}"/>
@@ -448,7 +450,27 @@
     </testng>
   </target>
 
-  <target name="test" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file, -test-security, -test-nosecurity" if="testng.available"/>
+  <target name="test" depends="test-pessimistic, test-optimistic"/>
+
+  <target name="test-optimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
+    <echo message="Running test suite in OPTIMISTIC mode..."/>
+    <antcall target="-test-nosecurity" inheritRefs="true">
+      <param name="optimistic" value="true"/>
+    </antcall>    
+    <antcall target="-test-security" inheritRefs="true">
+      <param name="optimistic" value="true"/>
+    </antcall>
+  </target>
+
+  <target name="test-pessimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
+    <echo message="Running test suite in PESSIMISTIC mode..."/>
+    <antcall target="-test-nosecurity" inheritRefs="true">
+      <param name="optimistic" value="false"/>
+    </antcall>    
+    <antcall target="-test-security" inheritRefs="true">
+      <param name="optimistic" value="false"/>
+    </antcall>
+  </target>
 
   <target name="check-jemmy.jfx.testng" unless="jemmy.jfx.testng.available">
     <echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/>
--- a/make/project.properties	Wed Oct 08 14:16:54 2014 -0700
+++ b/make/project.properties	Tue Oct 14 10:20:24 2014 -0700
@@ -286,7 +286,8 @@
 # turn on assertions for tests
 run.test.jvmargs.main=${run.test.jvmargs.common} -ea
 
-# extra jvmargs that might be useful for debugging
+# Extra jvmargs that might be useful for debugging
+# and performance improvements/monitoring
 #
 # -XX:+UnlockDiagnosticVMOptions 
 #
@@ -304,9 +305,25 @@
 #
 # print all compiled nmethods with oopmaps and lots of other info
 # -XX:+PrintNMethods
+#
+# activate the generic "UseNewCode" flag to test whatever functionality
+# lies behind it. This is the preferred way to test a, yet flagless,
+# feature in HotSpot - for example, the uncommon trap placement fix
+# was hidden behind this flag before it became the default
+#
+# -XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode 
+#
+# Crank up the type profile level to 222, which has some warmup
+# penalties, but produces much better code for JavaScript, where better
+# and more intrusive type profiling is required to get rid of
+# a large amount of unnecessary guard code, that could not otherwise
+# be eliminated
+#
+# -XX:TypeProfileLevel=222
+#
 
 # Use best known performance options for octane
-run.test.jvmargs.octane.main=${run.test.jvmargs.common} -XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode -XX:TypeProfileLevel=222
+run.test.jvmargs.octane.main=${run.test.jvmargs.common} -XX:TypeProfileLevel=222
 
 # Security manager args - make sure that we run with the nashorn.policy that the build creates
 run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${build.dir}/nashorn.policy
--- a/samples/BufferArray.java	Wed Oct 08 14:16:54 2014 -0700
+++ b/samples/BufferArray.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Oct 14 10:20:24 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,16 @@
 
     @Override
     public DebugLogger initLogger(final Context ctxt) {
+        final boolean optimisticTypes = env._optimistic_types;
+        final boolean lazyCompilation = env._lazy_compilation;
+
         return ctxt.getLogger(this.getClass(), new Consumer<DebugLogger>() {
             @Override
             public void accept(final DebugLogger newLogger) {
-                if (!Compiler.this.getScriptEnvironment()._lazy_compilation) {
+                if (!lazyCompilation) {
                     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 +545,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 +565,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 +593,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 +645,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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/Label.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/Lower.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/JumpStatement.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/ir/Symbol.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/Global.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDataView.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeString.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Tue Oct 14 10:20:24 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 08 14:16:54 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/CodeStore.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Tue Oct 14 10:20:24 2014 -0700
@@ -33,13 +33,13 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 import static jdk.nashorn.internal.runtime.Source.sourceFor;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 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 +127,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 +158,7 @@
         }
 
         /**
-         * Return the context for this installer
+         * Return the script environment for this installer
          * @return ScriptEnvironment
          */
         @Override
@@ -212,6 +222,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 ? */
@@ -1113,6 +1137,9 @@
 
         StoredScript storedScript = null;
         FunctionNode functionNode = null;
+        // We only use the code store here if optimistic types are disabled. With optimistic types,
+        // code is stored per function in RecompilableScriptFunctionData.
+        // TODO: This should really be triggered by lazy compilation, not optimistic types.
         final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
         final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
 
@@ -1199,7 +1226,7 @@
         final String   mainClassName   = storedScript.getMainClassName();
         final byte[]   mainClassBytes  = classBytes.get(mainClassName);
         final Class<?> mainClass       = installer.install(mainClassName, mainClassBytes);
-        final Map<Integer, FunctionInitializer> initialzers = storedScript.getInitializers();
+        final Map<Integer, FunctionInitializer> initializers = storedScript.getInitializers();
 
         installedClasses.put(mainClassName, mainClass);
 
@@ -1219,8 +1246,8 @@
             if (constant instanceof RecompilableScriptFunctionData) {
                 final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constant;
                 data.initTransients(source, installer);
-                if (initialzers != null) {
-                    final FunctionInitializer initializer = initialzers.get(data.getFunctionNodeId());
+                final FunctionInitializer initializer = initializers.get(data.getFunctionNodeId());
+                if (initializer != null) {
                     initializer.setCode(installedClasses.get(initializer.getClassName()));
                     data.initializeCode(initializer);
                 }
@@ -1371,4 +1398,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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/Debug.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Tue Oct 14 10:20:24 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 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/Property.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Tue Oct 14 10:20:24 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 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/StoredScript.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Tue Oct 14 10:20:24 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 14 10:20:24 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 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Tue Oct 14 10:20:24 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 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java	Tue Oct 14 10:20:24 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 08 14:16:54 2014 -0700
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Tue Oct 14 10:20:24 2014 -0700
@@ -203,9 +203,9 @@
 
 nashorn.option.optimistic.types = {                                                                      \
     name="--optimistic-types",                                                                           \
-    is_undocumented=true,                                                                                \
-    desc="Use optimistic type assumptions with deoptimizing recompilation.", \
-    default=true                                   \
+    short_name="-ot",                                                                                    \
+    desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently disabled by default, but can be enabled for significantly better peak performance.",                     \
+    default=false                                                                                        \
 }
 
 nashorn.option.loader.per.compile = {              \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/examples/charcodeat-benchmark.js	Tue Oct 14 10:20:24 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 14 10:20:24 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 14 10:20:24 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 14 10:20:24 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 14 10:20:24 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 14 10:20:24 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/octane-payload.js	Wed Oct 08 14:16:54 2014 -0700
+++ b/test/script/basic/octane-payload.js	Tue Oct 14 10:20:24 2014 -0700
@@ -40,7 +40,7 @@
     {name:"gbemu",         files:["gbemu-part1.js", "gbemu-part2.js"], suite:"GameboyBenchmark"},
     {name:"mandreel",      files:["mandreel.js"],                      suite:"MandreelBenchmark"},
     {name:"navier-stokes", files:["navier-stokes.js"],                 suite:"NavierStokes"},
-    {name:"pdfjs",         files:["pdfjs.js"],                         suite:"PdfJS"},
+    {name:"pdfjs",         files:["pdfjs.js"],                         suite:"PdfJS",                cleanUpIteration: function() { canvas_logs = []; }},
     {name:"raytrace",      files:["raytrace.js"],                      suite:"RayTrace"},
     {name:"regexp",        files:["regexp.js"],                        suite:"RegExpSuite"},
     {name:"richards",      files:["richards.js"],                      suite:"Richards"},
--- a/test/script/basic/run-octane.js	Wed Oct 08 14:16:54 2014 -0700
+++ b/test/script/basic/run-octane.js	Tue Oct 14 10:20:24 2014 -0700
@@ -24,8 +24,8 @@
 /**
  * @subtest
  */
-var payload = __DIR__ + "octane-payload.js";
-load(payload);
+var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__;
+load(dir + "octane-payload.js");
 
 var runtime = undefined;
 var verbose = false;
@@ -43,27 +43,27 @@
 function load_bench(arg) {
 
     for (var idx = 0; idx < arg.files.length; idx++) {
-    var f = arg.files[idx];
-    var file = f.split('/');
-    var file_name = path + file[file.length - 1];
+        var f = arg.files[idx];
+        var file = f.split('/');
+        var file_name = path + file[file.length - 1];
 
-    var compile_and_return = should_compile_only(file_name);
-    if (compile_and_return) {
-        if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them
-        return true;
+        var compile_and_return = should_compile_only(file_name);
+        if (compile_and_return) {
+            if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them
+                return true;
+            }
         }
-    }
 
-    print_verbose(arg, "loading '" + arg.name + "' [" + f + "]...");
-    load(file_name);
+        print_verbose(arg, "loading '" + arg.name + "' [" + f + "]... " + file_name);
+        load(file_name);
     }
 
     if (typeof arg.before !== 'undefined') {
-    arg.before();
+        arg.before();
     }
 
     if (compile_and_return) {
-    print_always(arg, "Compiled OK");
+        print_always(arg, "Compiled OK");
     }
     return !compile_and_return;
 
@@ -73,16 +73,16 @@
 function run_one_benchmark(arg, iters) {
 
     if (!load_bench(arg)) {
-    return;
+        return;
     }
 
     var success = true;
     var current_name;
 
     if (iters == undefined) {
-    iters = numberOfIterations;
+        iters = numberOfIterations;
     } else {
-    numberOfIterations = iters;
+        numberOfIterations = iters;
     }
 
     var benchmarks = eval(arg.suite + ".benchmarks");
@@ -91,64 +91,69 @@
     var mean_score = 0;
 
     try {
-    for (var x = 0; x < benchmarks.length ; x++) {
-        //do warmup run
-        //reset random number generator needed as of octane 9 before each run
-        BenchmarkSuite.ResetRNG();
-        benchmarks[x].Setup();
-    }
-    BenchmarkSuite.ResetRNG();
-    print_verbose(arg, "running '" + arg.name + "' for " + iters + " iterations of no less than " + min_time + " seconds");
-
-    var scores = [];
-
-    var min_time_ms = min_time * 1000;
-    var len = benchmarks.length;
-
-    for (var it = 0; it < iters + 1; it++) {
-        //every iteration must take a minimum of 10 secs
-        var ops = 0;
-        var elapsed = 0;
-        var start = new Date;
-        do {
-        for (var i = 0; i < len; i++) {
-            benchmarks[i].run();
-            //important - no timing here like elapsed = new Date() - start, as in the
-            //original harness. This will make timing very non-deterministic.
-            //NOTHING else must live in this loop
+        for (var x = 0; x < benchmarks.length ; x++) {
+            //do warmup run
+            //reset random number generator needed as of octane 9 before each run
+            BenchmarkSuite.ResetRNG();
+            benchmarks[x].Setup();
         }
-        ops += len;
-        elapsed = new Date - start;
-        } while (elapsed < min_time * 1000);
+        BenchmarkSuite.ResetRNG();
+        print_verbose(arg, "running '" + arg.name + "' for " + iters + " iterations of no less than " + min_time + " seconds");
+
+        var scores = [];
+
+        var min_time_ms = min_time * 1000;
+        var len = benchmarks.length;
 
-        var score = ops / elapsed * 1000 * 60;
-        scores.push(score);
-        var name = it == 0 ? "warmup" : "iteration " + it;
-        print_verbose(arg, name + " finished " + score.toFixed(0) + " ops/minute");
-    }
-
-    for (var x = 0; x < benchmarks.length ; x++) {
-        benchmarks[x].TearDown();
-    }
+        for (var it = 0; it < iters + 1; it++) {
+            //every iteration must take a minimum of 10 secs
+            var ops = 0;
+            var elapsed = 0;
+            var start = new Date;
+            do {
+                for (var i = 0; i < len; i++) {
+                    benchmarks[i].run();
+                    //important - no timing here like elapsed = new Date() - start, as in the
+                    //original harness. This will make timing very non-deterministic.
+                    //NOTHING else must live in this loop
+                }
+                ops += len;
+                elapsed = new Date - start;
+            } while (elapsed < min_time * 1000);
 
-    for (var x = 1; x < iters + 1 ; x++) {
-        mean_score += scores[x];
-        min_score = Math.min(min_score, scores[x]);
-        max_score = Math.max(max_score, scores[x]);
-    }
-    mean_score /= iters;
+            var score = ops / elapsed * 1000 * 60;
+            scores.push(score);
+            var name = it == 0 ? "warmup" : "iteration " + it;
+            print_verbose(arg, name + " finished " + score.toFixed(0) + " ops/minute");
+
+            // optional per-iteration cleanup hook
+            if (typeof arg.cleanUpIteration == "function") {
+                arg.cleanUpIteration();
+            }
+        }
+
+        for (var x = 0; x < benchmarks.length ; x++) {
+            benchmarks[x].TearDown();
+        }
+
+        for (var x = 1; x < iters + 1 ; x++) {
+            mean_score += scores[x];
+            min_score = Math.min(min_score, scores[x]);
+            max_score = Math.max(max_score, scores[x]);
+        }
+        mean_score /= iters;
     } catch (e) {
-    print_always(arg, "*** Aborted and setting score to zero. Reason: " + e);
-    if (e instanceof java.lang.Throwable) {
-        e.printStackTrace();
-    }
-    mean_score = min_score = max_score = 0;
-    scores = [0];
+        print_always(arg, "*** Aborted and setting score to zero. Reason: " + e);
+        if (is_this_nashorn() && e instanceof java.lang.Throwable) {
+            e.printStackTrace();
+        }
+        mean_score = min_score = max_score = 0;
+        scores = [0];
     }
 
     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);
 }
@@ -163,13 +168,13 @@
 
 function print_verbose(arg, x) {
     if (verbose) {
-    print_always(arg, x)
+        print_always(arg, x)
     }
 }
 
 function run_suite(tests, iters) {
     for (var idx = 0; idx < tests.length; idx++) {
-    run_one_benchmark(tests[idx], iters);
+        run_one_benchmark(tests[idx], iters);
     }
 }
 
@@ -184,13 +189,13 @@
 var new_args = [];
 for (i in args) {
     if (args[i].toString().indexOf(' ') != -1) {
-    args[i] = args[i].replace(/\/$/, '');
-    var s = args[i].split(' ');
-    for (j in s) {
-        new_args.push(s[j]);
-    }
+        args[i] = args[i].replace(/\/$/, '');
+        var s = args[i].split(' ');
+        for (j in s) {
+            new_args.push(s[j]);
+        }
     } else {
-    new_args.push(args[i]);
+        new_args.push(args[i]);
     }
 }
 
@@ -205,46 +210,46 @@
 for (var i = 0; i < args.length; i++) {
     arg = args[i];
     if (arg == "--iterations") {
-    iters = +args[++i];
-    if (isNaN(iters)) {
-        throw "'--iterations' must be followed by integer";
-    }
+        iters = +args[++i];
+        if (isNaN(iters)) {
+            throw "'--iterations' must be followed by integer";
+        }
     } else if (arg == "--runtime") {
-    runtime = args[++i];
+        runtime = args[++i];
     } else if (arg == "--verbose") {
-    verbose = true;
+        verbose = true;
     } else if (arg == "--min-time") {
-    min_time = +args[++i];
-    if (isNaN(iters)) {
-        throw "'--min-time' must be followed by integer";
-    }
+        min_time = +args[++i];
+        if (isNaN(iters)) {
+            throw "'--min-time' must be followed by integer";
+        }
     } else if (arg == "") {
-    continue; //skip
+        continue; //skip
     } else {
-    var found = false;
-    for (j in tests) {
-        if (tests[j].name === arg) {
-        tests_found.push(tests[j]);
-        found = true;
-        break;
+        var found = false;
+        for (j in tests) {
+            if (tests[j].name === arg) {
+                tests_found.push(tests[j]);
+                found = true;
+                break;
+            }
         }
-    }
-    if (!found) {
-        var str = "unknown test name: '" + arg + "' -- valid names are: ";
-        for (j in tests) {
-        if (j != 0) {
-            str += ", ";
+        if (!found) {
+            var str = "unknown test name: '" + arg + "' -- valid names are: ";
+            for (j in tests) {
+                if (j != 0) {
+                    str += ", ";
+                }
+                str += "'" + tests[j].name + "'";
+            }
+            throw str;
         }
-        str += "'" + tests[j].name + "'";
-        }
-        throw str;
-    }
     }
 }
 
 if (tests_found.length == 0) {
     for (i in tests) {
-    tests_found.push(tests[i]);
+        tests_found.push(tests[i]);
     }
 }
 
@@ -255,21 +260,21 @@
 
 if (is_this_nashorn()) {
     try {
-    read = readFully;
+        read = readFully;
     } catch (e) {
-    print("ABORTING: Cannot find 'readFully'. You must have scripting enabled to use this test harness. (-scripting)");
-    throw e;
+        print("ABORTING: Cannot find 'readFully'. You must have scripting enabled to use this test harness. (-scripting)");
+        throw e;
     }
 }
 
 // run tests in alphabetical order by name
 tests_found.sort(function(a, b) {
     if (a.name < b.name) {
-    return -1;
+        return -1;
     } else if (a.name > b.name) {
-    return 1;
+        return 1;
     } else {
-    return 0;
+        return 0;
     }
 });
 
--- a/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java	Wed Oct 08 14:16:54 2014 -0700
+++ b/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java	Tue Oct 14 10:20:24 2014 -0700
@@ -25,10 +25,10 @@
 
 package jdk.nashorn.internal.runtime;
 
-
 import jdk.nashorn.api.scripting.ClassFilter;
 import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
 import jdk.nashorn.api.scripting.URLReader;
+import jdk.nashorn.internal.test.framework.TestFinder;
 import org.testng.annotations.Test;
 
 import javax.script.ScriptEngine;
@@ -126,9 +126,9 @@
     private void persistentCacheTestImpl() {
         NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
         ScriptEngine engine = factory.getScriptEngine(
-                new String[]{"--persistent-code-cache"},
-                getClass().getClassLoader(),
-                getClassFilter()
+              TestFinder.addExplicitOptimisticTypes(new String[]{"--persistent-code-cache", "--optimistic-types=true"}),
+                  getClass().getClassLoader(),
+                  getClassFilter()
         );
         String testScript = "var a = Java.type('java.lang.String');" + generateCodeForPersistentStore();
         try {
@@ -137,7 +137,7 @@
             fail(exc.getMessage());
         }
         ScriptEngine engineSafe = factory.getScriptEngine(
-                new String[]{"--persistent-code-cache"},
+                TestFinder.addExplicitOptimisticTypes(new String[]{"--persistent-code-cache", "--optimistic-types=true"}),
                 getClass().getClassLoader(),
                 new ClassFilter() {
                     @Override
@@ -151,7 +151,7 @@
             fail("ClassNotFoundException should have been thrown");
         } catch (final Exception exc) {
             if (!(exc.getCause() instanceof ClassNotFoundException)) {
-                fail("ClassNotFoundException expected");
+                fail("ClassNotFoundException expected, got " + exc.getClass());
             }
         }
     }
--- a/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Wed Oct 08 14:16:54 2014 -0700
+++ b/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Tue Oct 14 10:20:24 2014 -0700
@@ -179,7 +179,7 @@
         for (final String str : forkJVMOptions) {
             if(!str.isEmpty()) {
                 cmd.add(str);
-            }
+        }
         }
         cmd.add(Shell.class.getName());
         // now add the rest of the "in process" runtime arguments
--- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Wed Oct 08 14:16:54 2014 -0700
+++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Tue Oct 14 10:20:24 2014 -0700
@@ -56,6 +56,7 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
@@ -75,7 +76,7 @@
  * Utility class to find/parse script test files and to create 'test' instances.
  * Actual 'test' object type is decided by clients of this class.
  */
-final class TestFinder {
+public final class TestFinder {
     private TestFinder() {}
 
     interface TestFactory<T> {
@@ -215,6 +216,8 @@
         final List<String> scriptArguments = new ArrayList<>();
         boolean inComment = false;
 
+        boolean explicitOptimistic = false;
+
         try (Scanner scanner = new Scanner(testFile)) {
             while (scanner.hasNext()) {
                 // TODO: Scan for /ref=file qualifiers, etc, to determine run
@@ -287,7 +290,11 @@
                     scriptArguments.add(scanner.next());
                     break;
                 case "@option":
-                    engineOptions.add(scanner.next());
+                    final String next = scanner.next();
+                    engineOptions.add(next);
+                    if (next.startsWith("--optimistic-types")) {
+                        explicitOptimistic = true;
+                    }
                     break;
                 case "@fork":
                     fork = true;
@@ -336,12 +343,61 @@
                 testOptions.put(OPTIONS_FORK, "true");
             }
 
+            //if there are explicit optimistic type settings, use those - do not override
+            //the test might only work with optimistic types on or off.
+            if (!explicitOptimistic) {
+                addExplicitOptimisticTypes(engineOptions);
+            }
+
             tests.add(factory.createTest(framework, testFile.toFile(), engineOptions, testOptions, scriptArguments));
         } else if (!isNotTest) {
             orphans.add(name);
         }
     }
 
+    //the reverse of the default setting for optimistic types, if enabled, false, otherwise true
+    //thus, true for 8u40, false for 9
+    private static final boolean OPTIMISTIC_OVERRIDE = true;
+
+    /**
+     * Check if there is an optimistic override, that disables the default
+     * false optimistic types and sets them to true, for testing purposes
+     *
+     * @return true if optimistic type override has been set by test suite
+     */
+    public static boolean hasOptimisticOverride() {
+        return Boolean.valueOf(OPTIMISTIC_OVERRIDE).toString().equals(System.getProperty("optimistic.override"));
+    }
+
+    /**
+     * Add an optimistic-types=true option to an argument list if this
+     * is set to override the default false. Add an optimistic-types=true
+     * options to an argument list if this is set to override the default
+     * true
+     *
+     * @args new argument list array
+     */
+    public static String[] addExplicitOptimisticTypes(String[] args) {
+        if (hasOptimisticOverride()) {
+            final List<String> newList = new ArrayList<>(Arrays.asList(args));
+            newList.add("--optimistic-types=" + Boolean.valueOf(OPTIMISTIC_OVERRIDE));
+            return newList.toArray(new String[0]);
+        }
+        return args;
+    }
+
+    /**
+     * Add an optimistic-types=true option to an argument list if this
+     * is set to override the default false
+     *
+     * @args argument list
+     */
+    public static void addExplicitOptimisticTypes(List<String> args) {
+        if (hasOptimisticOverride()) {
+            args.add("--optimistic-types=" + Boolean.valueOf(OPTIMISTIC_OVERRIDE));
+        }
+    }
+
     private static boolean strictModeEnabled() {
         return Boolean.getBoolean(TEST_JS_ENABLE_STRICT_MODE);
     }