changeset 1089:4f97f0da29eb jdk8u40-b12-aarch64

Merge to jdk8u40-b12
author aph
date Tue, 04 Nov 2014 17:21:00 +0000
parents 3378f256c6b2 (current diff) 375a3a3256d0 (diff)
children af0397959d77
files .hgtags make/BuildNashorn.gmk make/build.xml make/project.properties src/jdk/nashorn/api/scripting/NashornScriptEngine.java src/jdk/nashorn/api/scripting/ScriptUtils.java src/jdk/nashorn/internal/codegen/CodeGenerator.java src/jdk/nashorn/internal/codegen/CompilationPhase.java src/jdk/nashorn/internal/codegen/CompileUnit.java src/jdk/nashorn/internal/codegen/Compiler.java src/jdk/nashorn/internal/codegen/Lower.java src/jdk/nashorn/internal/codegen/MethodEmitter.java src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java src/jdk/nashorn/internal/codegen/types/BooleanType.java src/jdk/nashorn/internal/codegen/types/ObjectType.java src/jdk/nashorn/internal/codegen/types/Type.java src/jdk/nashorn/internal/ir/AccessNode.java src/jdk/nashorn/internal/ir/BaseNode.java src/jdk/nashorn/internal/ir/BinaryNode.java src/jdk/nashorn/internal/ir/CallNode.java src/jdk/nashorn/internal/ir/Expression.java src/jdk/nashorn/internal/ir/IdentNode.java src/jdk/nashorn/internal/ir/IndexNode.java src/jdk/nashorn/internal/ir/LexicalContext.java src/jdk/nashorn/internal/ir/LiteralNode.java src/jdk/nashorn/internal/ir/RuntimeNode.java src/jdk/nashorn/internal/ir/Symbol.java src/jdk/nashorn/internal/ir/TernaryNode.java src/jdk/nashorn/internal/ir/UnaryNode.java src/jdk/nashorn/internal/objects/Global.java src/jdk/nashorn/internal/objects/NativeArray.java src/jdk/nashorn/internal/objects/NativeJSAdapter.java src/jdk/nashorn/internal/objects/NativeString.java src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java src/jdk/nashorn/internal/objects/annotations/SpecializedConstructor.java src/jdk/nashorn/internal/parser/AbstractParser.java src/jdk/nashorn/internal/parser/Lexer.java src/jdk/nashorn/internal/runtime/CodeInstaller.java src/jdk/nashorn/internal/runtime/CompiledFunction.java src/jdk/nashorn/internal/runtime/Context.java src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java src/jdk/nashorn/internal/runtime/Property.java src/jdk/nashorn/internal/runtime/PropertyMap.java src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java src/jdk/nashorn/internal/runtime/ScriptFunction.java src/jdk/nashorn/internal/runtime/ScriptFunctionData.java src/jdk/nashorn/internal/runtime/ScriptObject.java src/jdk/nashorn/internal/runtime/ScriptRuntime.java src/jdk/nashorn/internal/runtime/WithObject.java src/jdk/nashorn/internal/runtime/arrays/ArrayData.java src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java src/jdk/nashorn/internal/runtime/linker/NashornLinker.java src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
diffstat 197 files changed, 5982 insertions(+), 2475 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Oct 10 15:53:41 2014 +0100
+++ b/.hgtags	Tue Nov 04 17:21:00 2014 +0000
@@ -308,6 +308,25 @@
 d3da140e179343011017669a6dbfcc52b0e56f52 jdk8u20-b24
 d3da140e179343011017669a6dbfcc52b0e56f52 jdk8u20-b25
 a23ac9db4227d78b3389e01fa94a8cb695a8fb0a jdk8u20-b26
+7001e9f95b443a75e432205a29974c05b88e0fdc jdk8u25-b00
+a9f77bd14874d5f8fdf935704dd54a0451f2bc69 jdk8u25-b01
+895e47783e2ee6823496a5ae84039a4f50311c7d jdk8u25-b02
+b84d92194c367411fcd8b5f510d4589709a8e71e jdk8u25-b03
+894ab2f06c93987f8596f5906985ff0a452f2fb2 jdk8u25-b04
+25b89ca363c41e1a1d90d7e95d5227d23e4292f3 jdk8u25-b05
+0a50d568a901700213fe40c38089748ca1d1af88 jdk8u25-b06
+25b719b33ac8f8ffb7e4353fddcda93ca6027b0d jdk8u25-b07
+0f74f65763a300cfe5f897b6b21f36d64f9d2115 jdk8u25-b08
+158837f537e45fc4664a56ad4759f8a1b30cab73 jdk8u25-b09
+7e00c05fc54b0404bf2eedda35dd38ae1ad23e50 jdk8u25-b10
+8cd6af10dd4de9e28ffe30c9107954fffd15dc99 jdk8u25-b11
+f76715cd4e902602bdbb4ba9a3774c10afeee012 jdk8u25-b12
+34c95bcacff79a5794416a8e715a8e63bfe7fc58 jdk8u25-b13
+6a93467eaa36f732b84ecd463e046c4066fef40c jdk8u25-b14
+71e8403a2f8279315419adf5f4e9d6b232b6835c jdk8u25-b15
+1500138ce513600457be6bfa10979ecce6515aa6 jdk8u25-b16
+4b9cc65dd24d398c4f921c0beccfb8caeaaaf584 jdk8u25-b17
+cdbf34dbef404b47805c8c85b11c65c2afaa6674 jdk8u25-b18
 f2925491b61b22ac42f8c30ee9c6723ffa401a4c jdk8u40-b00
 62468d841b842769d875bd97d10370585c296eb7 jdk8u40-b01
 bdd9c38d1e61edbf770b8733b70a37d0cf0e7055 jdk8u40-b02
@@ -317,3 +336,6 @@
 1196f17cf7bc709766319f5bf7a5394a7251b47a jdk8u40-b06
 0032961e1866c22afe3d0bbbb217f8840be61846 jdk8u40-b07
 89551828b279233825204b72233edafc72d8feb3 jdk8u40-b08
+6a8ecdeae4a9a438eed637b5a5d0d18fddb9f711 jdk8u40-b09
+076b1f38a5ccd4692a6f93939a7fc03bc1a1bbb4 jdk8u40-b10
+57c7b273277e00f7a98fafb18ff07aa3245808f0 jdk8u40-b11
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/fixwhitespace.sh	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/docs/DEVELOPER_README	Fri Oct 10 15:53:41 2014 +0100
+++ b/docs/DEVELOPER_README	Tue Nov 04 17:21:00 2014 +0000
@@ -25,6 +25,14 @@
 > java -Dnashorn.args="--lazy-complation --log=compiler" large-java-app-with-nashorn.jar 
 > ant -Dnashorn.args="--log=codegen" antjob
 
+SYSTEM PROPERTY: -Dnashorn.args.prepend=<string>
+
+This property behaves like nashorn.args, but adds the given arguments
+before the existing ones instead of after them. Later arguments will
+overwrite earlier ones, so this is useful for setting default arguments
+that can be overwritten.
+
+
 SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x
 
 This property controls how many call site misses are allowed before a 
@@ -42,533 +50,38 @@
 The default value is 0x8000 (32768).
 
 
-SYSTEM PROPERTY: -Dnashorn.compiler.intarithmetic
-
-(and integer arithmetic in general)
-
-<currently disabled - this is being refactored for update releases> 
-
-Arithmetic operations in Nashorn (except bitwise ones) typically
-coerce the operands to doubles (as per the JavaScript spec). To switch
-this off and remain in integer mode, for example for "var x = a&b; var
-y = c&d; var z = x*y;", use this flag. This will force the
-multiplication of variables that are ints to be done with the IMUL
-bytecode and the result "z" to become an int.
-
-WARNING: Note that is is experimental only to ensure that type support
-exists for all primitive types. The generated code is unsound. This
-will be the case until we do optimizations based on it. There is a CR
-in Nashorn to do better range analysis, and ensure that this is only
-done where the operation can't overflow into a wider type. Currently
-no overflow checking is done, so at the moment, until range analysis
-has been completed, this option is turned off.
-
-We've experimented by using int arithmetic for everything and putting
-overflow checks afterwards, which would recompute the operation with
-the correct precision, but have yet to find a configuration where this
-is faster than just using doubles directly, even if the int operation
-does not overflow. Getting access to a JVM intrinsic that does branch
-on overflow would probably alleviate this.
-
-The future:
-
-We are transitioning to an optimistic type system that uses int
-arithmetic everywhere until proven wrong. The problem here is mostly
-catch an overflow exception and rolling back the state to a new method
-with less optimistic assumptions for an operation at a particular
-program point. This will most likely not be in the Java 8.0 release
-but likely end up in an update release
-
-For Java 8, several java.lang.Math methods like addExact, subExact and
-mulExact are available to help us. Experiments intrinsifying these
-show a lot of promise, and we have devised a system that basically
-does on stack replacement with exceptions in bytecode to revert
-erroneous assumptions. An explanation of how this works and what we
-are doing can be found here:
-http://www.slideshare.net/lagergren/lagergren-jvmls2013final
-
-Experiments with this show significant ~x2-3 performance increases on
-pretty much everything, provided that optimistic assumptions don't
-fail much. It will affect warmup time negatively, depending on how
-many erroneous too optimistic assumptions are placed in the code at
-compile time. We don't think this will be much of an issue.
-
-For example for a small benchmark that repeatedly executes this
-method taken from the Crypto Octane benchmark 
-
-function am3(i,x,w,j,c,n) {
-  var this_array = this.array;
-  var w_array    = w.array;
-  var xl = x&0x3fff, xh = x>>14;
-  while(--n >= 0) {
-    var l = this_array[i]&0x3fff;
-    var h = this_array[i++]>>14;
-    var m = xh*l+h*xl;
-    l = xl*l+((m&0x3fff)<<14)+w_array[j]+c;
-    c = (l>>28)+(m>>14)+xh*h;
-    w_array[j++] = l&0xfffffff;
-  }
-
-  return c;
-}
-
-The performance increase more than doubles. We are also working hard
-with the code generation team in the Java Virtual Machine to fix
-things that are lacking in invokedynamic performance, which is another
-area where a lot of ongoing performance work takes place
-
-"Pessimistic" bytecode for am3, guaranteed to be semantically correct:
+SYSTEM PROPERTY: -Dnashorn.serialize.compression=<x>
 
-// access flags 0x9
-  public static am3(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-   L0
-    LINENUMBER 12 L0
-    ALOAD 0
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 8
-   L1
-    LINENUMBER 13 L1
-    ALOAD 3
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 9
-   L2
-    LINENUMBER 14 L2
-    ALOAD 2
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    SIPUSH 16383
-    IAND
-    ISTORE 10
-    ALOAD 2
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    BIPUSH 14
-    ISHR
-    ISTORE 11
-   L3
-    LINENUMBER 15 L3
-    GOTO L4
-   L5
-    LINENUMBER 16 L5
-   FRAME FULL [java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Double T java/lang/Object java/lang/Object I I] []
-    ALOAD 8
-    ALOAD 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    SIPUSH 16383
-    IAND
-    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
-    ASTORE 12
-   L6
-    LINENUMBER 17 L6
-    ALOAD 8
-    ALOAD 1
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DUP2
-    DCONST_1
-    DADD
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;D)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    BIPUSH 14
-    ISHR
-    ISTORE 13
-   L7
-    LINENUMBER 18 L7
-    ILOAD 11
-    I2D
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DMUL
-    ILOAD 13
-    I2D
-    ILOAD 10
-    I2D
-    DMUL
-    DADD
-    DSTORE 14
-   L8
-    LINENUMBER 19 L8
-    ILOAD 10
-    I2D
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DMUL
-    DLOAD 14
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I
-    SIPUSH 16383
-    IAND
-    BIPUSH 14
-    ISHL
-    I2D
-    DADD
-    ALOAD 9
-    ALOAD 4
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    INVOKEDYNAMIC ADD:ODO_D(DLjava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
-      // arguments: none
-    ]
-    ALOAD 5
-    INVOKEDYNAMIC ADD:OOO_I(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.runtimeBootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;)
-      // arguments: none
-    ]
-    ASTORE 12
-   L9
-    LINENUMBER 20 L9
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    BIPUSH 28
-    ISHR
-    I2D
-    DLOAD 14
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (D)I
-    BIPUSH 14
-    ISHR
-    I2D
-    DADD
-    ILOAD 11
-    I2D
-    ILOAD 13
-    I2D
-    DMUL
-    DADD
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 5
-   L10
-    LINENUMBER 21 L10
-    ALOAD 9
-    ALOAD 4
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    DUP2
-    DCONST_1
-    DADD
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 4
-    ALOAD 12
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toInt32 (Ljava/lang/Object;)I
-    LDC 268435455
-    IAND
-    INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;DI)V [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-   L4
-   FRAME FULL [java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object java/lang/Object T java/lang/Object java/lang/Object I I] []
-    ALOAD 6
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.toNumber (Ljava/lang/Object;)D
-    LDC -1.0
-    DADD
-    DUP2
-    INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;
-    ASTORE 6
-    DCONST_0
-    DCMPL
-    IFGE L5
-   L11
-    LINENUMBER 24 L11
-    ALOAD 5
-    ARETURN
-
-"Optimistic" bytecode that requires invalidation on e.g overflow. Factor
-x2-3 speedup:
-
-public static am3(Ljava/lang/Object;IILjava/lang/Object;III)I
-   L0
-    LINENUMBER 12 L0
-    ALOAD 0
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 8
-   L1
-    LINENUMBER 13 L1
-    ALOAD 3
-    INVOKEDYNAMIC dyn:getProp|getElem|getMethod:array(Ljava/lang/Object;)Ljava/lang/Object; [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    ASTORE 9
-   L2
-    LINENUMBER 14 L2
-    ILOAD 2
-    SIPUSH 16383
-    IAND
-    ISTORE 10
-    ILOAD 2
-    BIPUSH 14
-    ISHR
-    ISTORE 11
-   L3
-    LINENUMBER 15 L3
-    GOTO L4
-   L5
-    LINENUMBER 16 L5
-   FRAME FULL [java/lang/Object I I java/lang/Object I I I T java/lang/Object java/lang/Object I I] []
-    ALOAD 8
-    ILOAD 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    SIPUSH 16383
-    IAND
-    ISTORE 12
-   L6
-    LINENUMBER 17 L6
-    ALOAD 8
-    ILOAD 1
-    DUP
-    ICONST_1
-    IADD
-    ISTORE 1
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    BIPUSH 14
-    ISHR
-    ISTORE 13
-   L7
-    LINENUMBER 18 L7
-    ILOAD 11
-    ILOAD 12
-    BIPUSH 8
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    ILOAD 13
-    ILOAD 10
-    BIPUSH 9
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    IADD
-    ISTORE 14
-   L8
-    LINENUMBER 19 L8
-    ILOAD 10
-    ILOAD 12
-    BIPUSH 11
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    ILOAD 14
-    SIPUSH 16383
-    IAND
-    BIPUSH 14
-    ISHL
-    IADD
-    ALOAD 9
-    ILOAD 4
-    INVOKEDYNAMIC dyn:getElem|getProp|getMethod(Ljava/lang/Object;I)I [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-    IADD
-    ILOAD 5
-    IADD
-    ISTORE 12
-   L9
-    LINENUMBER 20 L9
-    ILOAD 12
-    BIPUSH 28
-    ISHR
-    ILOAD 14
-    BIPUSH 14
-    ISHR
-    IADD
-    ILOAD 11
-    ILOAD 13
-    BIPUSH 21
-    INVOKESTATIC jdk/nashorn/internal/runtime/JSType.mulExact (III)I
-    IADD
-    ISTORE 5
-   L10
-    LINENUMBER 21 L10
-    ALOAD 9
-    ILOAD 4
-    DUP
-    ICONST_1
-    IADD
-    ISTORE 4
-    ILOAD 12
-    LDC 268435455
-    IAND
-    INVOKEDYNAMIC dyn:setElem|setProp(Ljava/lang/Object;II)V [
-      // handle kind 0x6 : INVOKESTATIC
-      jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap((Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;)
-      // arguments:
-      0
-    ]
-   L4
-   FRAME SAME
-    ILOAD 6
-    ICONST_M1
-    IADD
-    DUP
-    ISTORE 6
-    ICONST_0
-    IF_ICMPGE L5
-   L11
-    LINENUMBER 24 L11
-    ILOAD 5
-    IRETURN
+This property sets the compression level used when deflating serialized
+AST structures of anonymous split functions. Valid values range from 0 to 9,
+the default value is 4. Higher values will reduce memory size of serialized
+AST but increase CPU usage required for compression.
 
 
-SYSTEM PROPERTY: -Dnashorn.codegen.debug, -Dnashorn.codegen.debug.trace=<x>
+SYSTEM PROPERTY: -Dnashorn.codegen.debug.trace=<x>
 
 See the description of the codegen logger below.
 
 
-SYSTEM_PROPERTY: -Dnashorn.fields.debug
+SYSTEM PROPERTY: -Dnashorn.fields.objects
 
-See the description on the fields logger below.
-
-
-SYSTEM PROPERTY: -Dnashorn.fields.dual
+When this property is true, Nashorn will only use object fields for
+AccessorProperties. This means that primitive values must be boxed
+when stored in a field, which is significantly slower than using
+primitive fields.
 
-When this property is true, Nashorn will attempt to use primitive
-fields for AccessorProperties (currently just AccessorProperties, not
-spill properties). Memory footprint for script objects will increase,
-as we need to maintain both a primitive field (a long) as well as an
-Object field for the property value. Ints are represented as the 32
-low bits of the long fields. Doubles are represented as the
-doubleToLongBits of their value. This way a single field can be used
-for all primitive types. Packing and unpacking doubles to their bit
-representation is intrinsified by the JVM and extremely fast.
-
-While dual fields in theory runs significantly faster than Object
-fields due to reduction of boxing and memory allocation overhead,
-there is still work to be done to make this a general purpose
-solution. Research is ongoing.
+By default, Nashorn uses dual object and long fields. Ints are
+represented as the 32 low bits of the long fields. Doubles are
+represented as the doubleToLongBits of their value. This way a
+single field can be used for all primitive types. Packing and
+unpacking doubles to their bit representation is intrinsified by
+the JVM and extremely fast.
 
 In the future, this might complement or be replaced by experimental
 feature sun.misc.TaggedArray, which has been discussed on the mlvm
 mailing list. TaggedArrays are basically a way to share data space
 between primitives and references, and have the GC understand this.
 
-As long as only primitive values are written to the fields and enough
-type information exists to make sure that any reads don't have to be
-uselessly boxed and unboxed, this is significantly faster than the
-standard "Objects only" approach that currently is the default. See
-test/examples/dual-fields-micro.js for an example that runs twice as
-fast with dual fields as without them. Here, the compiler, can
-determine that we are dealing with numbers only throughout the entire
-property life span of the properties involved.
-
-If a "real" object (not a boxed primitive) is written to a field that
-has a primitive representation, its callsite is relinked and an Object
-field is used forevermore for that particular field in that
-PropertyMap and its children, even if primitives are later assigned to
-it.
-
-As the amount of compile time type information is very small in a
-dynamic language like JavaScript, it is frequently the case that
-something has to be treated as an object, because we don't know any
-better. In reality though, it is often a boxed primitive is stored to
-an AccessorProperty. The fastest way to handle this soundly is to use
-a callsite typecheck and avoid blowing the field up to an Object. We
-never revert object fields to primitives. Ping-pong:ing back and forth
-between primitive representation and Object representation would cause
-fatal performance overhead, so this is not an option.
-
-For a general application the dual fields approach is still slower
-than objects only fields in some places, about the same in most cases,
-and significantly faster in very few. This is due the program using
-primitives, but we still can't prove it. For example "local_var a =
-call(); field = a;" may very well write a double to the field, but the
-compiler dare not guess a double type if field is a local variable,
-due to bytecode variables being strongly typed and later non
-interchangeable. To get around this, the entire method would have to
-be replaced and a continuation retained to restart from. We believe
-that the next steps we should go through are instead:
-
-1) Implement method specialization based on callsite, as it's quite
-frequently the case that numbers are passed around, but currently our
-function nodes just have object types visible to the compiler. For
-example "var b = 17; func(a,b,17)" is an example where two parameters
-can be specialized, but the main version of func might also be called
-from another callsite with func(x,y,"string").
-
-2) This requires lazy jitting as the functions have to be specialized
-per callsite.
-
-Even though "function square(x) { return x*x }" might look like a
-trivial function that can always only take doubles, this is not
-true. Someone might have overridden the valueOf for x so that the
-toNumber coercion has side effects. To fulfil JavaScript semantics,
-the coercion has to run twice for both terms of the multiplication
-even if they are the same object. This means that call site
-specialization is necessary, not parameter specialization on the form
-"function square(x) { var xd = (double)x; return xd*xd; }", as one
-might first think.
-
-Generating a method specialization for any variant of a function that
-we can determine by types at compile time is a combinatorial explosion
-of byte code (try it e.g. on all the variants of am3 in the Octane
-benchmark crypto.js). Thus, this needs to be lazy
-
-3) Optimistic callsite writes, something on the form
-
-x = y; //x is a field known to be a primitive. y is only an object as
-far as we can tell
-
-turns into
-
-try {
-  x = (int)y;
-} catch (X is not an integer field right now | ClassCastException e) {
-  x = y;
-}
-
-Mini POC shows that this is the key to a lot of dual field performance
-in seemingly trivial micros where one unknown object, in reality
-actually a primitive, foils it for us. Very common pattern. Once we
-are "all primitives", dual fields runs a lot faster than Object fields
-only.
-
-We still have to deal with objects vs primitives for local bytecode
-slots, possibly through code copying and versioning.
-
-The Future:
-
-We expect the usefulness of dual fields to increase significantly
-after the optimistic type system described in the section on 
-integer arithmetic above is implemented.
-
 
 SYSTEM PROPERTY: -Dnashorn.compiler.symbol.trace=[<x>[,*]], 
   -Dnashorn.compiler.symbol.stacktrace=[<x>[,*]]
@@ -628,6 +141,9 @@
 "identical" - this method compares two script objects for reference
 equality. It is a == Java comparison
 
+"equals" - Returns true if two objects are either referentially
+identical or equal as defined by java.lang.Object.equals.
+
 "dumpCounters" - will dump the debug counters' current values to
 stdout.
 
@@ -648,66 +164,66 @@
 when a callsite has to be relinked, due to a previous assumption of
 object layout being invalidated.
 
+"getContext" - return the current Nashorn context.
 
-SYSTEM PROPERTY: -Dnashorn.methodhandles.debug,
--Dnashorn.methodhandles.debug=create
+"equalWithoutType" - Returns true if if the two objects are both
+property maps, and they have identical properties in the same order,
+but allows the properties to differ in their types.
+
+"diffPropertyMaps" Returns a diagnostic string representing the difference
+of two property maps.
+
+"getClass" - Returns the Java class of an object, or undefined if null.
+
+"toJavaString" - Returns the Java toString representation of an object.
+
+"toIdentString" - Returns a string representation of an object consisting
+of its java class name and hash code.
+
+"getListenerCount" - Return the number of property listeners for a
+script object.
 
-If this property is enabled, each MethodHandle related call that uses
-the java.lang.invoke package gets its MethodHandle intercepted and an
-instrumentation printout of arguments and return value appended to
-it. This shows exactly which method handles are executed and from
-where. (Also MethodTypes and SwitchPoints). This can be augmented with
-more information, for example, instance count, by subclassing or
-further extending the TraceMethodHandleFactory implementation in
-MethodHandleFactory.java.
+"getEventQueueCapacity" - Get the capacity of the event queue.
+
+"setEventQueueCapacity" - Set the event queue capacity.
+
+"addRuntimeEvent" - Add a runtime event to the runtime event queue.
+The queue has a fixed size (see -Dnashorn.runtime.event.queue.size)
+and the oldest entry will be thrown out of the queue is about to overflow.
 
-If the property is specialized with "=create" as its option,
-instrumentation will be shown for method handles upon creation time
-rather than at runtime usage.
+"expandEventQueueCapacity" - Expands the event queue capacity,
+or truncates if capacity is lower than current capacity. Then only
+the newest entries are kept.
+
+"clearRuntimeEvents" - Clear the runtime event queue.
+
+"removeRuntimeEvent" - Remove a specific runtime event from the event queue.
+
+"getRuntimeEvents" - Return all runtime events in the queue as an array.
+
+"getLastRuntimeEvent" - Return the last runtime event in the queue.
 
 
 SYSTEM PROPERTY: -Dnashorn.methodhandles.debug.stacktrace
 
-This does the same as nashorn.methodhandles.debug, but when enabled
-also dumps the stack trace for every instrumented method handle
-operation. Warning: This is enormously verbose, but provides a pretty
+This enhances methodhandles logging (see below) to also dump the
+stack trace for every instrumented method handle operation.
+Warning: This is enormously verbose, but provides a pretty
 decent "grep:able" picture of where the calls are coming from.
 
-See the description of the codegen logger below for a more verbose
-description of this option
-
 
-SYSTEM PROPERTY: -Dnashorn.scriptfunction.specialization.disable
+SYSTEM PROPERTY: -Dnashorn.cce
+
+Setting this system property causes the Nashorn linker to rely on
+ClassCastExceptions for triggering a callsite relink. If not set, the linker
+will add an explicit instanceof guard.
 
-There are several "fast path" implementations of constructors and
-functions in the NativeObject classes that, in their original form,
-take a variable amount of arguments. Said functions are also declared
-to take Object parameters in their original form, as this is what the
-JavaScript specification mandates.
-However, we often know quite a lot more at a callsite of one of these
-functions. For example, Math.min is called with a fixed number (2) of
-integer arguments. The overhead of boxing these ints to Objects and
-folding them into an Object array for the generic varargs Math.min
-function is an order of magnitude slower than calling a specialized
-implementation of Math.min that takes two integers. Specialized
-functions and constructors are identified by the tag
-@SpecializedFunction and @SpecializedConstructor in the Nashorn
-code. The linker will link in the most appropriate (narrowest types,
-right number of types and least number of arguments) specialization if
-specializations are available.
+
+SYSTEM PROPERTY: -Dnashorn.spill.threshold=<x>
 
-Every ScriptFunction may carry specializations that the linker can
-choose from. This framework will likely be extended for user defined
-functions. The compiler can often infer enough parameter type info
-from callsites for in order to generate simpler versions with less
-generic Object types. This feature depends on future lazy jitting, as
-there tend to be many calls to user defined functions, some where the
-callsite can be specialized, some where we mostly see object
-parameters even at the callsite.
-
-If this system property is set to true, the linker will not attempt to
-use any specialized function or constructor for native objects, but
-just call the generic one.
+This property sets the number of fields in an object from which to use
+generic array based spill storage instead of Java fields. The default value
+is 256.
 
 
 SYSTEM PROPERTY: -Dnashorn.tcs.miss.samplePercent=<x>
@@ -719,8 +235,47 @@
 should be logged. Typically this is set to 1 or 5 (percent). 1% is the
 default value.
 
+SYSTEM PROPERTY: -Dnashorn.persistent.code.cache
 
-SYSTEM_PROPERTY: -Dnashorn.profilefile=<filename>
+This property can be used to set the directory where Nashorn stores
+serialized script classes generated with the -pcc/--persistent-code-cache
+option. The default directory name is "nashorn_code_cache".
+
+
+SYSTEM PROPERTY: -Dnashorn.typeInfo.maxFiles
+
+Maximum number of files to store in the type info cache. The type info cache
+is used to cache type data of JavaScript functions when running with
+optimistic types (-ot/--optimistic-types). There is one file per JavaScript
+function in the cache.
+
+The default value is 0 which means the feature is disabled. Setting this
+to something like 20000 is probably good enough for most applications and
+will usually cap the cache directory to about 80MB presuming a 4kB
+filesystem allocation unit. Set this to "unlimited" to run without limit.
+
+If the value is not 0 or "unlimited", Nashorn will spawn a cleanup thread
+that makes sure the number of files in the cache does not exceed the given
+value by deleting the least recently modified files.
+
+
+SYSTEM PROPERTY: -Dnashorn.typeInfo.cacheDir
+
+This property can be used to set the directory where Nashorn stores the
+type info cache when -Dnashorn.typeInfo.maxFiles is set to a nonzero
+value. The default location is platform specific. On Windows, it is
+"${java.io.tmpdir}\com.oracle.java.NashornTypeInfo". On Linux and
+Solaris it is "~/.cache/com.oracle.java.NashornTypeInfo". On Mac OS X,
+it is "~/Library/Caches/com.oracle.java.NashornTypeInfo".
+
+
+SYSTEM PROPERTY: -Dnashorn.typeInfo.cleanupDelaySeconds=<value>
+
+This sets the delay between cleanups of the typeInfo cache, in seconds.
+The default delay is 20 seconds.
+
+
+SYSTEM PROPERTY: -Dnashorn.profilefile=<filename>
 
 When running with the profile callsite options (-pcs), Nashorn will
 dump profiling data for all callsites to stderr as a shutdown hook. To
@@ -736,6 +291,11 @@
 an implementation based on Joni, the regular expression engine used by
 the JRuby project. The default value for this flag is "joni"
 
+SYSTEM PROPERTY: -Dnashorn.runtime.event.queue.size=<value>
+
+Nashorn provides a fixed sized runtime event queue for debugging purposes.
+See -Dnashorn.debug for methods to access the event queue.
+The default value is 1024.
 
 ===============
 2. The loggers.
@@ -767,7 +327,9 @@
 For example: --log=codegen,fields:finest is equivalent to
 --log=codegen:info --log=fields:finest
 
-The subsystems that currently support logging are:
+The following is an incomplete list of subsystems that currently
+support logging. Look for classes implementing
+jdk.nashorn.internal.runtime.logging.Loggable for more loggers.
 
 
 * compiler
@@ -780,6 +342,14 @@
 use.s
 
 
+* recompile
+
+This logger shows information about recompilation of scripts and
+functions at runtime. Recompilation may happen because a function
+was called with different parameter types, or because an optimistic
+assumption failed while executing a function with -ot/--optimistic-types.
+
+
 * codegen
 
 The code generator is the emitter stage of the code pipeline, and
@@ -836,25 +406,13 @@
 Lower is also responsible for determining control flow information
 like end points.
 
-
-* attr
+* symbols
 
-The lowering annotates a FunctionNode with symbols for each identifier
-and transforms high level constructs into lower level ones, that the
-CodeGenerator consumes.
+The symbols logger tracks the assignment os symbols to identifiers.
 
-Lower logging typically outputs things like post pass actions,
-insertions of casts because symbol types have been changed and type
-specialization information. Currently very little info is generated by
-this logger. This will probably change.
-
+* scopedepths
 
-* finalize
-
-This --log=finalize log option outputs information for type finalization,
-the third tier of the compiler. This means things like placement of 
-specialized scope nodes or explicit conversions. 
-
+This logs the calculation of scope depths for non-local symbols.
 
 * fields
 
@@ -896,6 +454,21 @@
 [time] 
 [time] Total runtime: 11994 ms (Non-runtime: 11027 ms [91%])
 
+* methodhandles
+
+If this logger is enabled, each MethodHandle related call that uses
+the java.lang.invoke package gets its MethodHandle intercepted and an
+instrumentation printout of arguments and return value appended to
+it. This shows exactly which method handles are executed and from
+where. (Also MethodTypes and SwitchPoints).
+
+* classcache
+
+This logger shows information about reusing code classes using the
+in-memory class cache. Nashorn will try to avoid compilation of
+scripts by using existing classes. This can significantly improve
+performance when repeatedly evaluating the same script.
+
 =======================
 3. Undocumented options
 =======================
--- a/make/BuildNashorn.gmk	Fri Oct 10 15:53:41 2014 +0100
+++ b/make/BuildNashorn.gmk	Tue Nov 04 17:21:00 2014 +0000
@@ -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-nasgen.xml	Fri Oct 10 15:53:41 2014 +0100
+++ b/make/build-nasgen.xml	Tue Nov 04 17:21:00 2014 +0000
@@ -25,7 +25,7 @@
     <description>Builds and runs nasgen.</description>
     <import file="build.xml"/>
 
-    <target name="build-nasgen" depends="compile-asm">
+    <target name="build-nasgen" depends="prepare">
         <ant inheritAll="false" dir="${basedir}/buildtools/nasgen"
             antfile="build.xml" target="jar"/>
     </target>
--- a/make/build.xml	Fri Oct 10 15:53:41 2014 +0100
+++ b/make/build.xml	Tue Nov 04 17:21:00 2014 +0000
@@ -49,8 +49,6 @@
     <condition property="git.executable" value="/usr/local/bin/git" else="git">
       <available file="/usr/local/bin/git"/>
     </condition>
-    <!-- check if JDK already has ASM classes -->
-    <available property="asm.available" classname="jdk.internal.org.objectweb.asm.Type"/>
     <!-- check if testng.jar is avaiable -->
     <available property="testng.available" file="${file.reference.testng.jar}"/>
     <!-- check if Jemmy ang testng.jar are avaiable -->
@@ -79,7 +77,30 @@
     </condition>
   </target>
 
-  <target name="init" depends="init-conditions, init-cc">
+  <!-- check minimum ant version required to be 1.8.4 -->
+  <target name="check-ant-version">
+    <property name="ant.version.required" value="1.8.4"/>
+    <antversion property="ant.current.version" />
+    <fail message="The current ant version, ${ant.current.version}, is too old. Please use 1.8.4 or above.">
+        <condition>
+            <not>
+                <antversion atleast="${ant.version.required}"/>
+            </not>
+        </condition>
+    </fail>
+  </target>
+
+  <target name="check-java-version">
+    <!-- look for a Class that is available only in jdk1.8 or above -->
+    <!-- core/exposed API class is better than an implementation class -->
+    <available property="jdk1.8+" classname="java.util.stream.Stream"/>
+
+    <!-- need jdk1.8 or above -->
+    <fail message="Unsupported Java version: ${ant.java.version}. Please use Java version 1.8 or greater." unless="jdk1.8+">
+    </fail>
+  </target>
+  
+  <target name="init" depends="check-ant-version, check-java-version, init-conditions, init-cc">
     <!-- extends jvm args -->
     <property name="run.test.jvmargs" value="${run.test.jvmargs.main} ${run.test.cc.jvmargs} ${jfr.options}"/>
     <property name="run.test.jvmargs.octane" value="${run.test.jvmargs.octane.main} ${run.test.cc.jvmargs} ${jfr.options}"/>
@@ -107,19 +128,7 @@
     <delete dir="${dist.dir}"/>
   </target>
 
-  <!-- do it only if ASM is not available -->
-  <target name="compile-asm" depends="prepare" unless="asm.available">
-    <javac srcdir="${jdk.asm.src.dir}"
-           destdir="${build.classes.dir}"
-           excludes="**/optimizer/* **/xml/* **/attrs/*"
-           source="${javac.source}"
-           target="${javac.target}"
-           debug="${javac.debug}"
-           encoding="${javac.encoding}"
-           includeantruntime="false"/>
-  </target>
-
-  <target name="compile" depends="compile-asm" description="Compiles nashorn">
+  <target name="compile" depends="prepare" description="Compiles nashorn">
     <javac srcdir="${src.dir}"
            destdir="${build.classes.dir}"
            classpath="${javac.classpath}"
@@ -407,7 +416,7 @@
     <fileset id="test.nosecurity.classes" dir="${build.test.classes.dir}">
       <include name="**/framework/ScriptTest.class"/>
     </fileset>
-    <testng outputdir="${build.nosecurity.test.results.dir}" classfilesetref="test.nosecurity.classes"
+    <testng outputdir="${build.nosecurity.test.results.dir}/${testResultsSubDir}" classfilesetref="test.nosecurity.classes"
        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} -Dbuild.dir=${build.dir}"/>
@@ -419,6 +428,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>
@@ -429,8 +439,8 @@
   <target name="-test-security">
     <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}">
+    <testng outputdir="${build.test.results.dir}/${testResultsSubDir}" classfilesetref="test.classes"
+	    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 +451,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 +459,31 @@
     </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"/>
+      <param name="testResultsSubDir" value="optimistic"/>
+    </antcall>    
+    <antcall target="-test-security" inheritRefs="true">
+      <param name="optimistic" value="true"/>
+      <param name="testResultsSubDir" value="optimistic"/>
+    </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"/>
+      <param name="testResultsSubDir" value="pessimistic"/>
+    </antcall>    
+    <antcall target="-test-security" inheritRefs="true">
+      <param name="optimistic" value="false"/>
+      <param name="testResultsSubDir" value="pessimistic"/>
+    </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	Fri Oct 10 15:53:41 2014 +0100
+++ b/make/project.properties	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/samples/BufferArray.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/api/scripting/NashornScriptEngine.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue Nov 04 17:21:00 2014 +0000
@@ -229,6 +229,8 @@
     }
 
     private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
+        assert !(thiz instanceof ScriptObject) : "raw ScriptObject not expected here";
+
         if (clazz == null || !clazz.isInterface()) {
             throw new IllegalArgumentException(getMessage("interface.class.expected"));
         }
@@ -254,17 +256,6 @@
             if (! isOfContext(realGlobal, nashornContext)) {
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
-        } else if (thiz instanceof ScriptObject) {
-            // called from script code.
-            realSelf = (ScriptObject)thiz;
-            realGlobal = Context.getGlobal();
-            if (realGlobal == null) {
-                throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
-            }
-
-            if (! isOfContext(realGlobal, nashornContext)) {
-                throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
-            }
         }
 
         if (realSelf == null) {
@@ -368,6 +359,7 @@
 
     private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
         name.getClass(); // null check
+        assert !(selfObject instanceof ScriptObject) : "raw ScriptObject not expected here";
 
         Global invokeGlobal = null;
         ScriptObjectMirror selfMirror = null;
@@ -377,20 +369,6 @@
                 throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
             }
             invokeGlobal = selfMirror.getHomeGlobal();
-        } else if (selfObject instanceof ScriptObject) {
-            // invokeMethod called from script code - in which case we may get 'naked' ScriptObject
-            // Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
-            final Global oldGlobal = Context.getGlobal();
-            invokeGlobal = oldGlobal;
-            if (oldGlobal == null) {
-                throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
-            }
-
-            if (! isOfContext(oldGlobal, nashornContext)) {
-                throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
-            }
-
-            selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal);
         } else if (selfObject == null) {
             // selfObject is null => global function call
             final Global ctxtGlobal = getNashornGlobalFrom(context);
--- a/src/jdk/nashorn/api/scripting/ScriptUtils.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java	Tue Nov 04 17:21:00 2014 +0000
@@ -75,11 +75,8 @@
      * @param sync the object to synchronize on
      * @return a synchronizing wrapper function
      */
-    public static Object makeSynchronizedFunction(final Object func, final Object sync) {
-        if (func instanceof ScriptFunction) {
-           return ((ScriptFunction)func).makeSynchronizedFunction(sync);
-        }
-        throw typeError("not.a.function", ScriptRuntime.safeToString(func));
+    public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
+        return func.makeSynchronizedFunction(unwrap(sync));
     }
 
     /**
@@ -88,12 +85,8 @@
      * @param obj object to be wrapped
      * @return wrapped object
      */
-    public static Object wrap(final Object obj) {
-        if (obj instanceof ScriptObject) {
-            return ScriptObjectMirror.wrap(obj, Context.getGlobal());
-        }
-
-        return obj;
+    public static ScriptObjectMirror wrap(final ScriptObject obj) {
+        return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal());
     }
 
     /**
@@ -160,14 +153,15 @@
         }
 
         final LinkerServices linker = Bootstrap.getLinkerServices();
-        final MethodHandle converter = linker.getTypeConverter(obj.getClass(),  clazz);
+        final Object objToConvert = unwrap(obj);
+        final MethodHandle converter = linker.getTypeConverter(objToConvert.getClass(),  clazz);
         if (converter == null) {
             // no supported conversion!
             throw new UnsupportedOperationException("conversion not supported");
         }
 
         try {
-            return converter.invoke(obj);
+            return converter.invoke(objToConvert);
         } catch (final RuntimeException | Error e) {
             throw e;
         } catch (final Throwable t) {
--- a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Tue Nov 04 17:21:00 2014 +0000
@@ -35,11 +35,11 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
@@ -131,11 +131,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 +146,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 +164,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 +191,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 +274,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;
         }
 
@@ -316,7 +323,7 @@
 
         explodedArguments.pop();
 
-        return newFunctionNode;
+        return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED);
     }
 
     private static boolean isApply(final CallNode callNode) {
--- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Tue Nov 04 17:21:00 2014 +0000
@@ -76,7 +76,6 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -135,9 +134,6 @@
         if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
             functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
         }
-        if (!functionNode.usesReturnSymbol()) {
-            functionNode.compilerConstant(RETURN).setNeedsSlot(false);
-        }
         // Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
         if(!functionNode.isDeclared() && !functionNode.usesSelfSymbol() && !functionNode.isAnonymous()) {
             final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
@@ -511,16 +507,6 @@
 
         thisProperties.push(new HashSet<String>());
 
-        if (functionNode.isDeclared()) {
-            // Can't use lc.getCurrentBlock() as we can have an outermost function in our lexical context that
-            // is not a program - it is a function being compiled on-demand.
-            final Iterator<Block> blocks = lc.getBlocks();
-            if (blocks.hasNext()) {
-                final IdentNode ident = functionNode.getIdent();
-                defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
-            }
-        }
-
         // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
         // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
         // are used in them.
@@ -532,14 +518,34 @@
     @Override
     public boolean enterVarNode(final VarNode varNode) {
         start(varNode);
+        // Normally, a symbol assigned in a var statement is not live for its RHS. Since we also represent function
+        // declarations as VarNodes, they are exception to the rule, as they need to have the symbol visible to the
+        // body of the declared function for self-reference.
+        if (varNode.isFunctionDeclaration()) {
+            defineVarIdent(varNode);
+        }
         return true;
     }
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
+        if (!varNode.isFunctionDeclaration()) {
+            defineVarIdent(varNode);
+        }
+        return super.leaveVarNode(varNode);
+    }
+
+    private void defineVarIdent(final VarNode varNode) {
         final IdentNode ident = varNode.getName();
-        defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
-        return super.leaveVarNode(varNode);
+        final int flags;
+        if (varNode.isAnonymousFunctionDeclaration()) {
+            flags = IS_INTERNAL;
+        } else if (lc.getCurrentFunction().isProgram()) {
+            flags = IS_SCOPE;
+        } else {
+            flags = 0;
+        }
+        defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | flags);
     }
 
     private Symbol exceptionSymbol() {
@@ -1004,7 +1010,7 @@
         boolean previousWasBlock = false;
         for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
             final LexicalContextNode node = it.next();
-            if (node instanceof FunctionNode || node instanceof SplitNode || isSplitArray(node)) {
+            if (node instanceof FunctionNode || isSplitArray(node)) {
                 // We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
                 // It needs to be in scope.
                 return true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/codegen/AstSerializer.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.codegen;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.options.Options;
+
+/**
+ * This static utility class performs serialization of FunctionNode ASTs to a byte array.
+ * The format is a standard Java serialization stream, deflated.
+ */
+final class AstSerializer {
+    // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
+    // and size.
+    private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
+    static byte[] serialize(final FunctionNode fn) {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out,
+                new Deflater(COMPRESSION_LEVEL)))) {
+            oout.writeObject(removeInnerFunctionBodies(fn));
+        } catch (final IOException e) {
+            throw new AssertionError("Unexpected exception serializing function", e);
+        }
+        return out.toByteArray();
+    }
+
+    private static FunctionNode removeInnerFunctionBodies(final FunctionNode fn) {
+        return (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public Node leaveBlock(final Block block) {
+                if (lc.isFunctionBody() && lc.getFunction(block) != lc.getOutermostFunction()) {
+                    return block.setStatements(lc, Collections.<Statement>emptyList());
+                }
+                return super.leaveBlock(block);
+            }
+        });
+    }
+}
--- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -56,16 +56,15 @@
 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;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.debug.NashornClassReader;
 import jdk.nashorn.internal.ir.debug.NashornTextifier;
 import jdk.nashorn.internal.runtime.Context;
@@ -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);
     }
 
     /**
@@ -473,12 +476,6 @@
         methodsStarted.remove(method);
     }
 
-    SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
-        methodCount++;
-        methodNames.add(methodName);
-        return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
-    }
-
     /**
      * Add a new method to the class - defaults to public method
      *
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -34,9 +34,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING;
 import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX;
-import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
@@ -99,11 +97,12 @@
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 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;
@@ -120,7 +119,8 @@
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SetSplitState;
+import jdk.nashorn.internal.ir.SplitReturn;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -492,8 +492,7 @@
         //walk up the chain from starting block and when we bump into the current function boundary, add the external
         //information.
         final FunctionNode fn   = lc.getCurrentFunction();
-        final int          fnId = fn.getId();
-        final int externalDepth = compiler.getScriptFunctionData(fnId).getExternalSymbolDepth(symbol.getName());
+        final int externalDepth = compiler.getScriptFunctionData(fn.getId()).getExternalSymbolDepth(symbol.getName());
 
         //count the number of scopes from this place to the start of the function
 
@@ -553,10 +552,10 @@
     }
 
     MethodEmitter loadBinaryOperands(final BinaryNode binaryNode) {
-        return loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(binaryNode.getWidestOperandType()), false);
+        return loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(binaryNode.getWidestOperandType()), false, false);
     }
 
-    private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final TypeBounds explicitOperandBounds, final boolean baseAlreadyOnStack) {
+    private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final TypeBounds explicitOperandBounds, final boolean baseAlreadyOnStack, final boolean forceConversionSeparation) {
         // ECMAScript 5.1 specification (sections 11.5-11.11 and 11.13) prescribes that when evaluating a binary
         // expression "LEFT op RIGHT", the order of operations must be: LOAD LEFT, LOAD RIGHT, CONVERT LEFT, CONVERT
         // RIGHT, EXECUTE OP. Unfortunately, doing it in this order defeats potential optimizations that arise when we
@@ -573,15 +572,34 @@
         final Type narrowestOperandType = Type.narrowest(Type.widest(lhs.getType(), rhs.getType()), explicitOperandBounds.widest);
         final TypeBounds operandBounds = explicitOperandBounds.notNarrowerThan(narrowestOperandType);
         if (noToPrimitiveConversion(lhs.getType(), explicitOperandBounds.widest) || rhs.isLocal()) {
-            // Can reorder. Combine load and convert into single operations.
-            loadExpression(lhs, operandBounds, baseAlreadyOnStack);
-            loadExpression(rhs, operandBounds, false);
+            // Can reorder. We might still need to separate conversion, but at least we can do it with reordering
+            if (forceConversionSeparation) {
+                // Can reorder, but can't move conversion into the operand as the operation depends on operands
+                // exact types for its overflow guarantees. E.g. with {L}{%I}expr1 {L}* {L}{%I}expr2 we are not allowed
+                // to merge {L}{%I} into {%L}, as that can cause subsequent overflows; test for JDK-8058610 contains
+                // concrete cases where this could happen.
+                final TypeBounds safeConvertBounds = TypeBounds.UNBOUNDED.notNarrowerThan(narrowestOperandType);
+                loadExpression(lhs, safeConvertBounds, baseAlreadyOnStack);
+                method.convert(operandBounds.within(method.peekType()));
+                loadExpression(rhs, safeConvertBounds, false);
+                method.convert(operandBounds.within(method.peekType()));
+            } else {
+                // Can reorder and move conversion into the operand. Combine load and convert into single operations.
+                loadExpression(lhs, operandBounds, baseAlreadyOnStack);
+                loadExpression(rhs, operandBounds, false);
+            }
         } else {
             // Can't reorder. Load and convert separately.
             final TypeBounds safeConvertBounds = TypeBounds.UNBOUNDED.notNarrowerThan(narrowestOperandType);
             loadExpression(lhs, safeConvertBounds, baseAlreadyOnStack);
+            final Type lhsType = method.peekType();
             loadExpression(rhs, safeConvertBounds, false);
-            method.swap().convert(operandBounds.within(method.peekType())).swap().convert(operandBounds.within(method.peekType()));
+            final Type convertedLhsType = operandBounds.within(method.peekType());
+            if (convertedLhsType != lhsType) {
+                // Do it conditionally, so that if conversion is a no-op we don't introduce a SWAP, SWAP.
+                method.swap().convert(convertedLhsType).swap();
+            }
+            method.convert(operandBounds.within(method.peekType()));
         }
         assert Type.generic(method.peekType()) == operandBounds.narrowest;
         assert Type.generic(method.peekType(1)) == operandBounds.narrowest;
@@ -632,19 +650,11 @@
         }
 
         TypeBounds booleanToInt() {
-            return maybeNew(booleanToInt(narrowest), booleanToInt(widest));
+            return maybeNew(CodeGenerator.booleanToInt(narrowest), CodeGenerator.booleanToInt(widest));
         }
 
         TypeBounds objectToNumber() {
-            return maybeNew(objectToNumber(narrowest), objectToNumber(widest));
-        }
-
-        private static Type booleanToInt(final Type t) {
-            return t == Type.BOOLEAN ? Type.INT : t;
-        }
-
-        private static Type objectToNumber(final Type t) {
-            return t.isObject() ? Type.NUMBER : t;
+            return maybeNew(CodeGenerator.objectToNumber(narrowest), CodeGenerator.objectToNumber(widest));
         }
 
         Type within(final Type type) {
@@ -663,6 +673,14 @@
         }
     }
 
+    private static Type booleanToInt(final Type t) {
+        return t == Type.BOOLEAN ? Type.INT : t;
+    }
+
+    private static Type objectToNumber(final Type t) {
+        return t.isObject() ? Type.NUMBER : t;
+    }
+
     MethodEmitter loadExpressionAsType(final Expression expr, final Type type) {
         if(type == Type.BOOLEAN) {
             return loadExpressionAsBoolean(expr);
@@ -1047,6 +1065,13 @@
             }
 
             @Override
+            public boolean enterGetSplitState(final GetSplitState getSplitState) {
+                method.loadScope();
+                method.invoke(Scope.GET_SPLIT_STATE);
+                return false;
+            }
+
+            @Override
             public boolean enterDefault(final Node otherNode) {
                 // Must have handled all expressions that can legally be encountered.
                 throw new AssertionError(otherNode.getClass().getName());
@@ -1204,17 +1229,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._goto(targetLabel);
 
         return false;
     }
@@ -1517,19 +1546,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
@@ -2036,10 +2053,10 @@
     }
 
     private void lineNumber(final int lineNumber) {
-        if (lineNumber != lastLineNumber) {
+        if (lineNumber != lastLineNumber && lineNumber != Node.NO_LINE_NUMBER) {
             method.lineNumber(lineNumber);
-        }
-        lastLineNumber = lineNumber;
+            lastLineNumber = lineNumber;
+        }
     }
 
     int getLastLineNumber() {
@@ -2086,13 +2103,14 @@
                 method.begin();
 
                 defineCommonSplitMethodParameters();
-                defineSplitMethodParameter(3, arrayType);
-
-                fixScopeSlot(currentFunction);
+                defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
+
+                // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
+                // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
+                final int arraySlot = fixScopeSlot(currentFunction, 3);
 
                 lc.enterSplitNode();
 
-                final int arraySlot = SPLIT_ARRAY_ARG.slot();
                 for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
                     method.load(arrayType, arraySlot);
                     storeElement(nodes, elementType, postsets[i]);
@@ -2707,73 +2725,6 @@
         method.convert(newRuntimeNode.getType());
     }
 
-    @Override
-    public boolean enterSplitNode(final SplitNode splitNode) {
-        if(!method.isReachable()) {
-            return false;
-        }
-
-        final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
-
-        final FunctionNode fn   = lc.getCurrentFunction();
-        final String className  = splitCompileUnit.getUnitClassName();
-        final String name       = splitNode.getName();
-
-        final Type returnType = fn.getReturnType();
-
-        final Class<?>   rtype          = fn.getReturnType().getTypeClass();
-        final boolean    needsArguments = fn.needsArguments();
-        final Class<?>[] ptypes         = needsArguments ?
-                new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class, ScriptObject.class} :
-                new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class};
-
-        final MethodEmitter caller = method;
-        unit = lc.pushCompileUnit(splitCompileUnit);
-
-        final Call splitCall = staticCallNoLookup(
-            className,
-            name,
-            methodDescriptor(rtype, ptypes));
-
-        final MethodEmitter splitEmitter =
-                splitCompileUnit.getClassEmitter().method(
-                        splitNode,
-                        name,
-                        rtype,
-                        ptypes);
-
-        pushMethodEmitter(splitEmitter);
-        method.setFunctionNode(fn);
-
-        assert fn.needsCallee() : "split function should require callee";
-        caller.loadCompilerConstant(CALLEE);
-        caller.loadCompilerConstant(THIS);
-        caller.loadCompilerConstant(SCOPE);
-        if (needsArguments) {
-            caller.loadCompilerConstant(ARGUMENTS);
-        }
-        caller.invoke(splitCall);
-        caller.storeCompilerConstant(RETURN, returnType);
-
-        method.begin();
-
-        defineCommonSplitMethodParameters();
-        if(needsArguments) {
-            defineSplitMethodParameter(3, ARGUMENTS);
-        }
-
-        // Copy scope to its target slot as first thing because the original slot could be used by return symbol.
-        fixScopeSlot(fn);
-
-        final int returnSlot = fn.compilerConstant(RETURN).getSlot(returnType);
-        method.defineBlockLocalVariable(returnSlot, returnSlot + returnType.getSlots());
-        method.loadUndefined(returnType);
-        method.storeCompilerConstant(RETURN, returnType);
-
-        lc.enterSplitNode();
-        return true;
-    }
-
     private void defineCommonSplitMethodParameters() {
         defineSplitMethodParameter(0, CALLEE);
         defineSplitMethodParameter(1, THIS);
@@ -2789,114 +2740,40 @@
         method.onLocalStore(type, slot);
     }
 
-    private void fixScopeSlot(final FunctionNode functionNode) {
+    private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
         // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
         final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
         final int defaultScopeSlot = SCOPE.slot();
+        int newExtraSlot = extraSlot;
         if (actualScopeSlot != defaultScopeSlot) {
-            method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1);
+            if (actualScopeSlot == extraSlot) {
+                newExtraSlot = extraSlot + 1;
+                method.defineBlockLocalVariable(newExtraSlot, newExtraSlot + 1);
+                method.load(Type.OBJECT, extraSlot);
+                method.storeHidden(Type.OBJECT, newExtraSlot);
+            } else {
+                method.defineBlockLocalVariable(actualScopeSlot, actualScopeSlot + 1);
+            }
             method.load(SCOPE_TYPE, defaultScopeSlot);
             method.storeCompilerConstant(SCOPE);
         }
+        return newExtraSlot;
     }
 
     @Override
-    public Node leaveSplitNode(final SplitNode splitNode) {
-        assert method instanceof SplitMethodEmitter;
-        lc.exitSplitNode();
-        final boolean hasReturn = method.hasReturn();
-        final SplitMethodEmitter splitMethod = ((SplitMethodEmitter)method);
-        final List<Label> targets = splitMethod.getExternalTargets();
-        final List<BreakableNode> targetNodes  = splitMethod.getExternalTargetNodes();
-        final Type returnType = lc.getCurrentFunction().getReturnType();
-
-        try {
-            // Wrap up this method.
-
-            if(method.isReachable()) {
-                method.loadCompilerConstant(RETURN, returnType);
-                method._return(returnType);
-            }
-            method.end();
-
-            lc.releaseSlots();
-
-            unit   = lc.popCompileUnit(splitNode.getCompileUnit());
-            popMethodEmitter();
-
-        } catch (final Throwable t) {
-            Context.printStackTrace(t);
-            final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentSource().getName());
-            e.initCause(t);
-            throw e;
-        }
-
-        // 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.invoke(Scope.GET_SPLIT_STATE);
-
-        final Label breakLabel = new Label("no_split_state");
-        // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue
-
-        //the common case is that we don't need a switch
-        if (targetCount == 0) {
-            assert hasReturn;
-            caller.ifne(breakLabel);
-            //has to be zero
-            caller.label(new Label("split_return"));
-            caller.loadCompilerConstant(RETURN, returnType);
-            caller._return(returnType);
-            caller.label(breakLabel);
-        } else {
-            assert !targets.isEmpty();
-
-            final int     low         = hasReturn ? 0 : 1;
-            final int     labelCount  = targetCount + 1 - low;
-            final Label[] labels      = new Label[labelCount];
-
-            for (int i = 0; i < labelCount; i++) {
-                labels[i] = new Label(i == 0 ? "split_return" : "split_" + targets.get(i - 1));
-            }
-            caller.tableswitch(low, targetCount, breakLabel, labels);
-            for (int i = low; i <= targetCount; i++) {
-                caller.label(labels[i - low]);
-                if (i == 0) {
-                    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);
-                    }
-                    popScopesUntil(targetNode);
-                    caller.splitAwareGoto(lc, targets.get(i - 1), targetNode);
-                }
-            }
-            caller.label(breakLabel);
-        }
-
-        // If split has a return and caller is itself a split method it needs to propagate the return.
-        if (hasReturn) {
-            caller.setHasReturn();
-        }
-
-        return splitNode;
+    public boolean enterSplitReturn(final SplitReturn splitReturn) {
+        if (method.isReachable()) {
+            method.loadUndefined(lc.getCurrentFunction().getReturnType())._return();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean enterSetSplitState(final SetSplitState setSplitState) {
+        if (method.isReachable()) {
+            method.setSplitState(setSplitState.getState());
+        }
+        return false;
     }
 
     @Override
@@ -3685,13 +3562,15 @@
             void loadStack() {
                 final TypeBounds operandBounds;
                 final boolean isOptimistic = isValid(getProgramPoint());
+                boolean forceConversionSeparation = false;
                 if(isOptimistic) {
                     operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT);
                 } else {
                     // Non-optimistic, non-FP +. Allow it to overflow.
                     operandBounds = new TypeBounds(binaryNode.getWidestOperandType(), Type.OBJECT);
+                    forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest);
                 }
-                loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false);
+                loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation);
             }
 
             @Override
@@ -3802,12 +3681,21 @@
         @Override
         protected void evaluate() {
             final Expression lhs = assignNode.lhs();
-            final Type widest = assignNode.isTokenType(TokenType.ASSIGN_ADD) ? Type.OBJECT : assignNode.getWidestOperationType();
+            final Expression rhs = assignNode.rhs();
+            final Type widestOperationType = assignNode.getWidestOperationType();
+            final Type widest = assignNode.isTokenType(TokenType.ASSIGN_ADD) ? Type.OBJECT : widestOperationType;
             final TypeBounds bounds = new TypeBounds(assignNode.getType(), widest);
             new OptimisticOperation(assignNode, bounds) {
                 @Override
                 void loadStack() {
-                    loadBinaryOperands(lhs, assignNode.rhs(), bounds, true);
+                    final boolean forceConversionSeparation;
+                    if (isValid(getProgramPoint()) || widestOperationType == Type.NUMBER) {
+                        forceConversionSeparation = false;
+                    } else {
+                        final Type operandType = Type.widest(booleanToInt(objectToNumber(lhs.getType())), booleanToInt(objectToNumber(rhs.getType())));
+                        forceConversionSeparation = operandType.narrowerThan(widestOperationType);
+                    }
+                    loadBinaryOperands(lhs, rhs, bounds, true, forceConversionSeparation);
                 }
                 @Override
                 void consumeStack() {
@@ -3830,7 +3718,7 @@
 
         @Override
         protected void evaluate() {
-            loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(assignNode.getWidestOperandType()), true);
+            loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), TypeBounds.UNBOUNDED.notWiderThan(assignNode.getWidestOperandType()), true, false);
             op();
         }
     }
@@ -3953,6 +3841,7 @@
                 @Override
                 void loadStack() {
                     final TypeBounds operandBounds;
+                    boolean forceConversionSeparation = false;
                     if(numericBounds.narrowest == Type.NUMBER) {
                         // Result should be double always. Propagate it into the operands so we don't have lots of I2D
                         // and L2D after operand evaluation.
@@ -3970,9 +3859,10 @@
                             // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
                             operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
                                     numericBounds.widest), Type.NUMBER);
+                            forceConversionSeparation = node.getWidestOperationType().narrowerThan(numericBounds.widest);
                         }
                     }
-                    loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false);
+                    loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false, forceConversionSeparation);
                 }
 
                 @Override
@@ -4386,11 +4276,7 @@
     private void newFunctionObject(final FunctionNode functionNode, final boolean addInitializer) {
         assert lc.peek() == functionNode;
 
-        final int fnId = functionNode.getId();
-
-        final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fnId);
-
-        assert data != null : functionNode.getName() + " has no data";
+        final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(functionNode.getId());
 
         if (functionNode.isProgram() && !compiler.isOnDemandCompilation()) {
             final CompileUnit fnUnit = functionNode.getCompileUnit();
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue Nov 04 17:21:00 2014 +0000
@@ -40,25 +40,19 @@
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
-import java.util.List;
 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;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
 import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -83,7 +77,7 @@
                 PARSED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new FoldConstants(compiler));
+            return transformFunction(fn, new FoldConstants(compiler));
         }
 
         @Override
@@ -106,7 +100,7 @@
                 CONSTANT_FOLDED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new Lower(compiler));
+            return transformFunction(fn, new Lower(compiler));
         }
 
         @Override
@@ -120,23 +114,6 @@
      * optimistic ops a program point so that an UnwarrantedException knows from where
      * a guess went wrong when creating the continuation to roll back this execution
      */
-    PROGRAM_POINT_PHASE(
-            EnumSet.of(
-                INITIALIZED,
-                PARSED,
-                CONSTANT_FOLDED,
-                LOWERED)) {
-        @Override
-        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new ProgramPoints());
-        }
-
-        @Override
-        public String toString() {
-            return "'Program Point Calculation'";
-        }
-    },
-
     TRANSFORM_BUILTINS_PHASE(
             EnumSet.of(
                     INITIALIZED,
@@ -146,13 +123,7 @@
         //we only do this if we have a param type map, otherwise this is not a specialized recompile
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new ApplySpecialization(compiler));
-            return (FunctionNode)newFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-                @Override
-                public Node leaveFunctionNode(final FunctionNode node) {
-                    return node.setState(lc, BUILTINS_TRANSFORMED);
-                }
-            });
+            return setStates(transformFunction(fn, new ApplySpecialization(compiler)), BUILTINS_TRANSFORMED);
         }
 
         @Override
@@ -179,7 +150,7 @@
             FunctionNode newFunctionNode;
 
             //ensure elementTypes, postsets and presets exist for splitter and arraynodes
-            newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            newFunctionNode = transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
                 @Override
                 public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) {
                     return literalNode.initialize(lc);
@@ -187,7 +158,7 @@
             });
 
             newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true);
-
+            newFunctionNode = transformFunction(newFunctionNode, new SplitIntoFunctions(compiler));
             assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
             assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName());
 
@@ -200,6 +171,52 @@
         }
     },
 
+    PROGRAM_POINT_PHASE(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT)) {
+        @Override
+        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+            return transformFunction(fn, new ProgramPoints());
+        }
+
+        @Override
+        public String toString() {
+            return "'Program Point Calculation'";
+        }
+    },
+
+    SERIALIZE_SPLIT_PHASE(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT)) {
+        @Override
+        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+            return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                @Override
+                public boolean enterFunctionNode(final FunctionNode functionNode) {
+                    if (functionNode.isSplit()) {
+                        compiler.serializeAst(functionNode);
+                    }
+                    return true;
+                }
+            });
+        }
+
+        @Override
+        public String toString() {
+            return "'Serialize Split Functions'";
+        }
+    },
+
     SYMBOL_ASSIGNMENT_PHASE(
             EnumSet.of(
                     INITIALIZED,
@@ -210,7 +227,7 @@
                     SPLIT)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new AssignSymbols(compiler));
+            return transformFunction(fn, new AssignSymbols(compiler));
         }
 
         @Override
@@ -230,7 +247,7 @@
                     SYMBOLS_ASSIGNED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return (FunctionNode)fn.accept(new FindScopeDepths(compiler));
+            return transformFunction(fn, new FindScopeDepths(compiler));
         }
 
         @Override
@@ -252,7 +269,7 @@
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             if (compiler.useOptimisticTypes()) {
-                return (FunctionNode)fn.accept(new OptimisticTypesCalculator(compiler));
+                return transformFunction(fn, new OptimisticTypesCalculator(compiler));
             }
             return setStates(fn, OPTIMISTIC_TYPES_ASSIGNED);
         }
@@ -276,8 +293,7 @@
                     OPTIMISTIC_TYPES_ASSIGNED)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new LocalVariableTypesCalculator(compiler));
-
+            final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
             final ScriptEnvironment senv = compiler.getScriptEnvironment();
             final PrintWriter       err  = senv.getErr();
 
@@ -332,13 +348,7 @@
 
             for (final CompileUnit oldUnit : compiler.getCompileUnits()) {
                 assert map.get(oldUnit) == null;
-                final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
-                if (phases.isRestOfCompilation()) {
-                    sb.append("$restOf");
-                }
-                //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
-                //fills those out anyway. Thus no need for a copy constructor
-                final CompileUnit newUnit = compiler.createCompileUnit(sb.toString(), oldUnit.getWeight());
+                final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
                 log.fine("Creating new compile unit ", oldUnit, " => ", newUnit);
                 map.put(oldUnit, newUnit);
                 assert newUnit != null;
@@ -352,47 +362,10 @@
             //replace old compile units in function nodes, if any are assigned,
             //for example by running the splitter on this function node in a previous
             //partial code generation
-            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-                @Override
-                public Node leaveFunctionNode(final FunctionNode node) {
-                    final CompileUnit oldUnit = node.getCompileUnit();
-                    assert oldUnit != null : "no compile unit in function node";
-
-                    final CompileUnit newUnit = map.get(oldUnit);
-                    assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
-
-                    log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
-                    return node.setCompileUnit(lc, newUnit).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
-                }
-
+            final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
                 @Override
-                public Node leaveSplitNode(final SplitNode node) {
-                    final CompileUnit oldUnit = node.getCompileUnit();
-                    assert oldUnit != null : "no compile unit in function node";
-
-                    final CompileUnit newUnit = map.get(oldUnit);
-                    assert newUnit != null : "old unit has no mapping to new unit " + oldUnit;
-
-                    log.fine("Replacing compile unit: ", oldUnit, " => ", newUnit, " in ", quote(node.getName()));
-                    return node.setCompileUnit(lc, newUnit);
-                }
-
-                @Override
-                public Node leaveLiteralNode(final LiteralNode<?> node) {
-                    if (node instanceof ArrayLiteralNode) {
-                        final ArrayLiteralNode aln = (ArrayLiteralNode)node;
-                        if (aln.getUnits() == null) {
-                            return node;
-                        }
-                        final List<ArrayUnit> newArrayUnits = new ArrayList<>();
-                        for (final ArrayUnit au : aln.getUnits()) {
-                            final CompileUnit newUnit = map.get(au.getCompileUnit());
-                            assert newUnit != null;
-                            newArrayUnits.add(new ArrayUnit(newUnit, au.getLo(), au.getHi()));
-                        }
-                        return aln.setUnits(lc, newArrayUnits);
-                    }
-                    return node;
+                CompileUnit getReplacement(CompileUnit original) {
+                    return map.get(original);
                 }
 
                 @Override
@@ -410,7 +383,59 @@
         }
     },
 
-     /**
+    REINITIALIZE_SERIALIZED(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT)) {
+        @Override
+        FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+            final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet();
+            final Map<CompileUnit, CompileUnit> unitMap = new HashMap<>();
+
+            // Ensure that the FunctionNode's compile unit is the first in the list of new units. Install phase
+            // will use that as the root class.
+            createCompileUnit(fn.getCompileUnit(), unitSet, unitMap, compiler, phases);
+
+            final FunctionNode newFn = transformFunction(fn, new ReplaceCompileUnits() {
+                @Override
+                CompileUnit getReplacement(final CompileUnit oldUnit) {
+                    final CompileUnit existing = unitMap.get(oldUnit);
+                    if (existing != null) {
+                        return existing;
+                    }
+                    return createCompileUnit(oldUnit, unitSet, unitMap, compiler, phases);
+                }
+
+                @Override
+                public Node leaveFunctionNode(final FunctionNode fn2) {
+                    return super.leaveFunctionNode(
+                            // restore flags for deserialized nested function nodes
+                            compiler.getScriptFunctionData(fn2.getId()).restoreFlags(lc, fn2));
+                };
+            });
+            compiler.replaceCompileUnits(unitSet);
+            return newFn;
+        }
+
+        private CompileUnit createCompileUnit(final CompileUnit oldUnit, final Set<CompileUnit> unitSet,
+                final Map<CompileUnit, CompileUnit> unitMap, final Compiler compiler, final CompilationPhases phases) {
+            final CompileUnit newUnit = createNewCompileUnit(compiler, phases);
+            unitMap.put(oldUnit, newUnit);
+            unitSet.add(newUnit);
+            return newUnit;
+        }
+
+        @Override
+        public String toString() {
+            return "'Deserialize'";
+        }
+    },
+
+    /**
      * Bytecode generation:
      *
      * Generate the byte code class(es) resulting from the compiled FunctionNode
@@ -445,7 +470,7 @@
             try {
                 // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
                 // in the lazy + optimistic world. See CodeGenerator.skipFunction().
-                newFunctionNode = ((FunctionNode)newFunctionNode.accept(codegen)).setState(null, BYTECODE_GENERATED);
+                newFunctionNode = transformFunction(newFunctionNode, codegen).setState(null, BYTECODE_GENERATED);
                 codegen.generateScopeCalls();
             } catch (final VerifyError e) {
                 if (senv._verify_code || senv._print_code) {
@@ -617,7 +642,7 @@
         if (!AssertsEnabled.assertsEnabled()) {
             return functionNode;
         }
-        return (FunctionNode)functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        return transformFunction(functionNode, new NodeVisitor<LexicalContext>(new LexicalContext()) {
             @Override
             public Node leaveFunctionNode(final FunctionNode fn) {
                 return fn.setState(lc, state);
@@ -627,7 +652,7 @@
 
     /**
      * Start a compilation phase
-     * @param compiler
+     * @param compiler the compiler to use
      * @param functionNode function to compile
      * @return function node
      */
@@ -703,4 +728,17 @@
         return end(compiler, transform(compiler, phases, begin(compiler, functionNode)));
     }
 
+    private static FunctionNode transformFunction(final FunctionNode fn, final NodeVisitor<?> visitor) {
+        return (FunctionNode) fn.accept(visitor);
+    }
+
+    private static CompileUnit createNewCompileUnit(final Compiler compiler, final CompilationPhases phases) {
+        final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName());
+        if (phases.isRestOfCompilation()) {
+            sb.append("$restOf");
+        }
+        //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
+        //fills those out anyway. Thus no need for a copy constructor
+        return compiler.createCompileUnit(sb.toString(), 0);
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/CompileUnit.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java	Tue Nov 04 17:21:00 2014 +0000
@@ -25,24 +25,31 @@
 
 package jdk.nashorn.internal.codegen;
 
+import java.io.Serializable;
 import java.util.Set;
 import java.util.TreeSet;
+import jdk.nashorn.internal.ir.CompileUnitHolder;
 
 /**
- * Used to track split class compilation.
- */
-public final class CompileUnit implements Comparable<CompileUnit> {
+  * Used to track split class compilation. Note that instances of the class are serializable, but all fields are
+  * transient, making the serialized version of the class only useful for tracking the referential topology of other
+  * AST nodes referencing the same or different compile units. We do want to preserve this topology though as
+  * {@link CompileUnitHolder}s in a deserialized AST will undergo reinitialization.
+  */
+public final class CompileUnit implements Comparable<CompileUnit>, Serializable {
+    private static final long serialVersionUID = 1L;
+
     /** Current class name */
-    private final String className;
+    private transient final String className;
 
     /** Current class generator */
-    private ClassEmitter classEmitter;
+    private transient ClassEmitter classEmitter;
 
-    private long weight;
+    private transient long weight;
 
-    private Class<?> clazz;
+    private transient Class<?> clazz;
 
-    private boolean isUsed;
+    private transient boolean isUsed;
 
     private static int emittedUnitCount;
 
@@ -60,6 +67,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 +83,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;
     }
@@ -114,14 +129,6 @@
     }
 
     /**
-     * Get the current weight of the compile unit.
-     * @return the unit's weight
-     */
-    long getWeight() {
-        return weight;
-    }
-
-    /**
      * Check if this compile unit can hold {@code weight} more units of weight
      * @param w weight to check if can be added
      * @return true if weight fits in this compile unit
@@ -147,7 +154,7 @@
     }
 
     private static String shortName(final String name) {
-        return name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
+        return name == null ? null : name.lastIndexOf('/') == -1 ? name : name.substring(name.lastIndexOf('/') + 1);
     }
 
     @Override
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Nov 04 17:21:00 2014 +0000
@@ -35,13 +35,13 @@
 
 import java.io.File;
 import java.lang.invoke.MethodType;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -154,74 +154,148 @@
     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;
+
+    private final Map<Integer, byte[]> serializedAsts = new HashMap<>();
+
+    /**
      * Compilation phases that a compilation goes through
      */
     public static class CompilationPhases implements Iterable<CompilationPhase> {
 
-        /** Singleton that describes a standard eager compilation - this includes code installation */
-        public final static CompilationPhases COMPILE_ALL = new CompilationPhases(
-                "Compile all",
-                new CompilationPhase[] {
-                        CompilationPhase.CONSTANT_FOLDING_PHASE,
-                        CompilationPhase.LOWERING_PHASE,
-                        CompilationPhase.PROGRAM_POINT_PHASE,
-                        CompilationPhase.TRANSFORM_BUILTINS_PHASE,
-                        CompilationPhase.SPLITTING_PHASE,
-                        CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
-                        CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
-                        CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
-                        CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE,
-                        CompilationPhase.BYTECODE_GENERATION_PHASE,
-                        CompilationPhase.INSTALL_PHASE
-                });
+        /**
+         * Singleton that describes compilation up to the phase where a function can be serialized.
+         */
+        private final static CompilationPhases COMPILE_UPTO_SERIALIZABLE = new CompilationPhases(
+                "Common initial phases",
+                CompilationPhase.CONSTANT_FOLDING_PHASE,
+                CompilationPhase.LOWERING_PHASE,
+                CompilationPhase.TRANSFORM_BUILTINS_PHASE,
+                CompilationPhase.SPLITTING_PHASE,
+                CompilationPhase.PROGRAM_POINT_PHASE,
+                CompilationPhase.SERIALIZE_SPLIT_PHASE
+                );
 
-        /** Compile all for a rest of method */
-        public final static CompilationPhases COMPILE_ALL_RESTOF =
-                COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE);
+        private final static CompilationPhases COMPILE_SERIALIZABLE_UPTO_BYTECODE = new CompilationPhases(
+                "After common phases, before bytecode generator",
+                CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
+                CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+                CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
+                CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
+                );
 
-        /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
-        public final static CompilationPhases COMPILE_ALL_NO_INSTALL =
-                COMPILE_ALL.
-                removeLast().
-                setDescription("Compile without install");
-
-        /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
-        public final static CompilationPhases COMPILE_UPTO_BYTECODE =
-                COMPILE_ALL.
-                removeLast().
-                removeLast().
-                setDescription("Compile upto bytecode");
+        /**
+         * Singleton that describes additional steps to be taken after deserializing, all the way up to (but not
+         * including) generating and installing code.
+         */
+        public final static CompilationPhases RECOMPILE_SERIALIZED_UPTO_BYTECODE = new CompilationPhases(
+                "Recompile serialized function up to bytecode",
+                CompilationPhase.REINITIALIZE_SERIALIZED,
+                COMPILE_SERIALIZABLE_UPTO_BYTECODE
+                );
 
         /**
          * Singleton that describes back end of method generation, given that we have generated the normal
          * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE}
          */
-        public final static CompilationPhases COMPILE_FROM_BYTECODE = new CompilationPhases(
+        public final static CompilationPhases GENERATE_BYTECODE_AND_INSTALL = new CompilationPhases(
                 "Generate bytecode and install",
-                new CompilationPhase[] {
-                        CompilationPhase.BYTECODE_GENERATION_PHASE,
-                        CompilationPhase.INSTALL_PHASE
-                });
+                CompilationPhase.BYTECODE_GENERATION_PHASE,
+                CompilationPhase.INSTALL_PHASE
+                );
+
+        /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
+        public final static CompilationPhases COMPILE_UPTO_BYTECODE = new CompilationPhases(
+                "Compile upto bytecode",
+                COMPILE_UPTO_SERIALIZABLE,
+                COMPILE_SERIALIZABLE_UPTO_BYTECODE);
+
+        /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
+        public final static CompilationPhases COMPILE_ALL_NO_INSTALL = new CompilationPhases(
+                "Compile without install",
+                COMPILE_UPTO_BYTECODE,
+                CompilationPhase.BYTECODE_GENERATION_PHASE);
+
+        /** Singleton that describes a standard eager compilation - this includes code installation */
+        public final static CompilationPhases COMPILE_ALL = new CompilationPhases(
+                "Full eager compilation",
+                COMPILE_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL);
+
+        /** Singleton that describes a full compilation - this includes code installation - from serialized state*/
+        public final static CompilationPhases COMPILE_ALL_SERIALIZED = new CompilationPhases(
+                "Eager compilation from serializaed state",
+                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL);
 
         /**
          * Singleton that describes restOf method generation, given that we have generated the normal
          * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE}
          */
-        public final static CompilationPhases COMPILE_FROM_BYTECODE_RESTOF =
-                COMPILE_FROM_BYTECODE.
-                addFirst(CompilationPhase.REUSE_COMPILE_UNITS_PHASE).
-                setDescription("Generate bytecode and install - RestOf method");
+        public final static CompilationPhases GENERATE_BYTECODE_AND_INSTALL_RESTOF = new CompilationPhases(
+                "Generate bytecode and install - RestOf method",
+                CompilationPhase.REUSE_COMPILE_UNITS_PHASE,
+                GENERATE_BYTECODE_AND_INSTALL);
+
+        /** Compile all for a rest of method */
+        public final static CompilationPhases COMPILE_ALL_RESTOF = new CompilationPhases(
+                "Compile all, rest of",
+                COMPILE_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL_RESTOF);
+
+        /** Compile from serialized for a rest of method */
+        public final static CompilationPhases COMPILE_SERIALIZED_RESTOF = new CompilationPhases(
+                "Compile serialized, rest of",
+                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+                GENERATE_BYTECODE_AND_INSTALL_RESTOF);
 
         private final List<CompilationPhase> phases;
 
         private final String desc;
 
         private CompilationPhases(final String desc, final CompilationPhase... phases) {
-            this.desc = desc;
+            this(desc, Arrays.asList(phases));
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhases base, final CompilationPhase... phases) {
+            this(desc, concat(base.phases, Arrays.asList(phases)));
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhase first, final CompilationPhases rest) {
+            this(desc, concat(Collections.singletonList(first), rest.phases));
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhases base) {
+            this(desc, base.phases);
+        }
+
+        private CompilationPhases(final String desc, final CompilationPhases... bases) {
+            this(desc, concatPhases(bases));
+        }
 
-            final List<CompilationPhase> newPhases = new LinkedList<>();
-            newPhases.addAll(Arrays.asList(phases));
-            this.phases = Collections.unmodifiableList(newPhases);
+        private CompilationPhases(final String desc, final List<CompilationPhase> phases) {
+            this.desc = desc;
+            this.phases = phases;
+        }
+
+        private static List<CompilationPhase> concatPhases(final CompilationPhases[] bases) {
+            final ArrayList<CompilationPhase> l = new ArrayList<>();
+            for(final CompilationPhases base: bases) {
+                l.addAll(base.phases);
+            }
+            l.trimToSize();
+            return l;
+        }
+
+        private static <T> List<T> concat(final List<T> l1, final List<T> l2) {
+            final ArrayList<T> l = new ArrayList<>(l1);
+            l.addAll(l2);
+            l.trimToSize();
+            return l;
         }
 
         @Override
@@ -229,45 +303,6 @@
             return "'" + desc + "' " + phases.toString();
         }
 
-        private CompilationPhases setDescription(final String desc) {
-            return new CompilationPhases(desc, phases.toArray(new CompilationPhase[phases.size()]));
-        }
-
-        private CompilationPhases removeLast() {
-            final LinkedList<CompilationPhase> list = new LinkedList<>(phases);
-            list.removeLast();
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
-        private CompilationPhases addFirst(final CompilationPhase phase) {
-            if (phases.contains(phase)) {
-                return this;
-            }
-            final LinkedList<CompilationPhase> list = new LinkedList<>(phases);
-            list.addFirst(phase);
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
-        @SuppressWarnings("unused") //TODO I'll use this soon
-        private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
-            final LinkedList<CompilationPhase> list = new LinkedList<>();
-            for (final CompilationPhase p : phases) {
-                list.add(p == phase ? newPhase : p);
-            }
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
-        private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
-            final LinkedList<CompilationPhase> list = new LinkedList<>();
-            for (final CompilationPhase p : phases) {
-                list.add(p);
-                if (p == phase) {
-                    list.add(newPhase);
-                }
-            }
-            return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
-        }
-
         boolean contains(final CompilationPhase phase) {
             return phases.contains(phase);
         }
@@ -278,7 +313,7 @@
         }
 
         boolean isRestOfCompilation() {
-            return this == COMPILE_ALL_RESTOF || this == COMPILE_FROM_BYTECODE_RESTOF;
+            return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_SERIALIZED_RESTOF;
         }
 
         String getDesc() {
@@ -404,10 +439,29 @@
             baseName = baseName + installer.getUniqueScriptId();
         }
 
-        final String mangled = NameCodec.encode(baseName);
+        // ASM's bytecode verifier does not allow JVM allowed safe escapes using '\' as escape char.
+        // While ASM accepts such escapes for method names, field names, it enforces Java identifier
+        // for class names. Workaround that ASM bug here by replacing JVM 'dangerous' chars with '_'
+        // rather than safe encoding using '\'.
+        final String mangled = env._verify_code? replaceDangerChars(baseName) : NameCodec.encode(baseName);
         return mangled != null ? mangled : baseName;
     }
 
+    private static final String DANGEROUS_CHARS   = "\\/.;:$[]<>";
+    private static String replaceDangerChars(final String name) {
+        final int len = name.length();
+        final StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < len; i++) {
+            final char ch = name.charAt(i);
+            if (DANGEROUS_CHARS.indexOf(ch) != -1) {
+                buf.append('_');
+            } else {
+                buf.append(ch);
+            }
+        }
+        return buf.toString();
+    }
+
     private String firstCompileUnitName() {
         final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE).
                 append('/').
@@ -452,12 +506,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 +593,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 +613,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 +641,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 +693,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);
@@ -715,6 +778,14 @@
         compileUnits.addAll(newUnits);
     }
 
+    void serializeAst(final FunctionNode fn) {
+        serializedAsts.put(fn.getId(), AstSerializer.serialize(fn));
+    }
+
+    byte[] removeSerializedAst(final int fnId) {
+        return serializedAsts.remove(fnId);
+    }
+
     CompileUnit findUnit(final long weight) {
         for (final CompileUnit unit : compileUnits) {
             if (unit.canHold(weight)) {
@@ -737,7 +808,10 @@
     }
 
     RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
-        return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId);
+        assert compiledFunction != null;
+        final RecompilableScriptFunctionData fn = compiledFunction.getScriptFunctionData(functionId);
+        assert fn != null : functionId;
+        return fn;
     }
 
     boolean isGlobalSymbol(final FunctionNode fn, final String name) {
--- a/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Tue Nov 04 17:21:00 2014 +0000
@@ -187,7 +187,6 @@
 
         if (compiler.isOnDemandCompilation()) {
             final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(newFunctionNode.getId());
-            assert data != null : newFunctionNode.getName() + " lacks data";
             if (data.inDynamicContext()) {
                 log.fine("Reviving scriptfunction ", quote(name), " as defined in previous (now lost) dynamic scope.");
                 newFunctionNode = newFunctionNode.setInDynamicContext(lc);
@@ -202,7 +201,7 @@
 
         //create recompilable scriptfunctiondata
         final int fnId = newFunctionNode.getId();
-        final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId);
+        final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.remove(fnId);
 
         assert nestedFunctions != null;
         // Generate the object class and property map in case this function is ever used as constructor
@@ -212,8 +211,8 @@
                 new AllocatorDescriptor(newFunctionNode.getThisProperties()),
                 nestedFunctions,
                 externalSymbolDepths.get(fnId),
-                internalSymbols.get(fnId)
-                );
+                internalSymbols.get(fnId),
+                compiler.removeSerializedAst(fnId));
 
         if (lc.getOutermostFunction() != newFunctionNode) {
             final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
--- a/src/jdk/nashorn/internal/codegen/Label.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/Label.java	Tue Nov 04 17:21:00 2014 +0000
@@ -24,6 +24,7 @@
  */
 package jdk.nashorn.internal.codegen;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -39,7 +40,9 @@
  *
  * see -Dnashorn.codegen.debug, --log=codegen
  */
-public final class Label {
+public final class Label implements Serializable {
+    private static final long serialVersionUID = 1L;
+
     //byte code generation evaluation type stack for consistency check
     //and correct opcode selection. one per label as a label may be a
     //join point
@@ -491,7 +494,7 @@
     private final String name;
 
     /** Type stack at this label */
-    private Label.Stack stack;
+    private transient Label.Stack stack;
 
     /** ASM representation of this label */
     private jdk.internal.org.objectweb.asm.Label label;
@@ -500,9 +503,9 @@
     private final int id;
 
     /** Is this label reachable (anything ever jumped to it)? */
-    private boolean reachable;
+    private transient boolean reachable;
 
-    private boolean breakTarget;
+    private transient boolean breakTarget;
 
     /**
      * Constructor
@@ -590,8 +593,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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -72,7 +72,7 @@
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SplitReturn;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -361,10 +361,6 @@
     // Synthetic return node that we must insert at the end of the function if it's end is reachable.
     private ReturnNode syntheticReturn;
 
-    // Topmost current split node (if any)
-    private SplitNode topSplit;
-    private boolean split;
-
     private boolean alreadyEnteredTopLevelFunction;
 
     // LvarType and conversion information gathered during the top-down pass; applied to nodes in the bottom-up pass.
@@ -464,36 +460,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());
-    }
-
-    private boolean splitAwareJumpToLabel(final JumpStatement jumpStatement, final BreakableNode target, final Label targetLabel) {
-        final JoinPredecessor jumpOrigin;
-        if(topSplit != null && lc.isExternalTarget(topSplit, target)) {
-            // If the jump target is outside the topmost split node, then we'll create a synthetic jump origin in the
-            // split node.
-            jumpOrigin = new JoinPredecessorExpression();
-            topSplit.addJump(jumpOrigin, targetLabel);
-        } else {
-            // Otherwise, the original jump statement is the jump origin
-            jumpOrigin = jumpStatement;
-        }
-
-        jumpToLabel(jumpOrigin, targetLabel, getBreakTargetTypes(target));
+        final BreakableNode target = jump.getTarget(lc);
+        jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
         doesNotContinueSequentially();
         return false;
     }
@@ -704,18 +684,9 @@
     }
 
     @Override
-    public boolean enterSplitNode(final SplitNode splitNode) {
-        if(!reachable) {
-            return false;
-        }
-        // Need to visit inside of split nodes. While it's true that they don't have local variables, we need to visit
-        // breaks, continues, and returns in them.
-        if(topSplit == null) {
-            topSplit = splitNode;
-        }
-        split = true;
-        setType(getCompilerConstantSymbol(lc.getCurrentFunction(), CompilerConstants.RETURN), LvarType.UNDEFINED);
-        return true;
+    public boolean enterSplitReturn(final SplitReturn splitReturn) {
+        doesNotContinueSequentially();
+        return false;
     }
 
     @Override
@@ -1117,15 +1088,6 @@
         if(returnType.isUnknown()) {
             returnType = Type.OBJECT;
         }
-
-        if(split) {
-            // If the function is split, the ":return" symbol is used and needs a slot. Note we can't mark the return
-            // symbol as used in enterSplitNode, as we don't know the final return type of the function earlier than
-            // here.
-            final Symbol retSymbol = getCompilerConstantSymbol(lc.getCurrentFunction(), CompilerConstants.RETURN);
-            retSymbol.setHasSlotFor(returnType);
-            retSymbol.setNeedsSlot(true);
-        }
     }
 
     private void createSyntheticReturn(final Block body) {
--- a/src/jdk/nashorn/internal/codegen/Lower.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/Lower.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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;
@@ -351,8 +352,6 @@
     private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
         assert tryNode.getFinallyBody() == null;
 
-        final LexicalContext lowerLc = lc;
-
         final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
             final List<Node> insideTry = new ArrayList<>();
 
@@ -382,12 +381,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
@@ -401,7 +404,6 @@
                     //still in the try block, store it in a result value and return it afterwards
                     resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
                     newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
-                    lowerLc.setFlag(lowerLc.getCurrentFunction(), FunctionNode.USES_RETURN_SYMBOL);
                 } else {
                     resultNode = null;
                 }
@@ -627,7 +629,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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -89,23 +89,24 @@
 import jdk.nashorn.internal.codegen.types.BitwiseType;
 import jdk.nashorn.internal.codegen.types.NumericType;
 import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.JoinPredecessor;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LocalVariableConversion;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TryNode;
 import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.NativeArray;
 import jdk.nashorn.internal.runtime.ArgumentSetter;
 import jdk.nashorn.internal.runtime.Context;
 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);
     }
@@ -1657,19 +1663,6 @@
     }
 
     /**
-     * Goto, possibly when splitting is taking place. If
-     * a splitNode exists, we need to handle the case that the
-     * jump target is another method
-     *
-     * @param label destination label
-     * @param targetNode the node to which the destination label belongs (the label is normally a break or continue
-     * label)
-     */
-    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
-        _goto(label);
-    }
-
-    /**
      * Perform a comparison of two number types that are popped from the stack
      *
      * @param isCmpG is this a dcmpg semantic, false if it's a dcmpl semantic
@@ -2120,7 +2113,14 @@
 
         int pos = 0;
         for (int i = argCount - 1; i >= 0; i--) {
-            paramTypes[i] = stack.peek(pos++);
+            Type pt = stack.peek(pos++);
+            // "erase" specific ScriptObject subtype info - except for NativeArray.
+            // NativeArray is used for array/List/Deque conversion for Java calls.
+            if (ScriptObject.class.isAssignableFrom(pt.getTypeClass()) &&
+                !NativeArray.class.isAssignableFrom(pt.getTypeClass())) {
+                pt = Type.SCRIPT_OBJECT;
+            }
+            paramTypes[i] = pt;
         }
         final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
         for (int i = 0; i < argCount; i++) {
@@ -2131,10 +2131,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 +2580,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/OptimisticTypesCalculator.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -30,7 +30,6 @@
 import java.util.ArrayDeque;
 import java.util.BitSet;
 import java.util.Deque;
-import jdk.nashorn.internal.IntDeque;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.CallNode;
@@ -49,7 +48,6 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Optimistic;
 import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
@@ -70,8 +68,6 @@
 
     // Per-function bit set of program points that must never be optimistic.
     final Deque<BitSet> neverOptimistic = new ArrayDeque<>();
-    // Per-function depth of split nodes
-    final IntDeque splitDepth = new IntDeque();
 
     OptimisticTypesCalculator(final Compiler compiler) {
         super(new LexicalContext());
@@ -155,7 +151,6 @@
             return false;
         }
         neverOptimistic.push(new BitSet());
-        splitDepth.push(0);
         return true;
     }
 
@@ -190,19 +185,6 @@
     }
 
     @Override
-    public boolean enterSplitNode(final SplitNode splitNode) {
-        splitDepth.getAndIncrement();
-        return true;
-    }
-
-    @Override
-    public Node leaveSplitNode(final SplitNode splitNode) {
-        final int depth = splitDepth.decrementAndGet();
-        assert depth >= 0;
-        return splitNode;
-    }
-
-    @Override
     public boolean enterVarNode(final VarNode varNode) {
         tagNeverOptimistic(varNode.getName());
         return true;
@@ -226,16 +208,11 @@
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         neverOptimistic.pop();
-        final int lastSplitDepth = splitDepth.pop();
-        assert lastSplitDepth == 0;
         return functionNode.setState(lc, CompilationState.OPTIMISTIC_TYPES_ASSIGNED);
     }
 
     @Override
     public Node leaveIdentNode(final IdentNode identNode) {
-        if(inSplitNode()) {
-            return identNode;
-        }
         final Symbol symbol = identNode.getSymbol();
         if(symbol == null) {
             assert identNode.isPropertyName();
@@ -256,7 +233,7 @@
 
     private Expression leaveOptimistic(final Optimistic opt) {
         final int pp = opt.getProgramPoint();
-        if(isValid(pp) && !inSplitNode() && !neverOptimistic.peek().get(pp)) {
+        if(isValid(pp) && !neverOptimistic.peek().get(pp)) {
             return (Expression)opt.setType(compiler.getOptimisticType(opt));
         }
         return (Expression)opt;
@@ -277,8 +254,4 @@
             tagNeverOptimistic(test.getExpression());
         }
     }
-
-    private boolean inSplitNode() {
-        return splitDepth.peek() > 0;
-    }
 }
--- a/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/ProgramPoints.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/ProgramPoints.java	Tue Nov 04 17:21:00 2014 +0000
@@ -85,7 +85,7 @@
 
     @Override
     public boolean enterVarNode(final VarNode varNode) {
-        noProgramPoint.add(varNode.getAssignmentDest());
+        noProgramPoint.add(varNode.getName());
         return true;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+import jdk.nashorn.internal.ir.CompileUnitHolder;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * Base class for a node visitor that replaces {@link CompileUnit}s in {@link CompileUnitHolder}s.
+ */
+abstract class ReplaceCompileUnits extends NodeVisitor<LexicalContext> {
+    ReplaceCompileUnits() {
+        super(new LexicalContext());
+    }
+
+    /**
+     * Override to provide a replacement for an old compile unit.
+     * @param oldUnit the old compile unit to replace
+     * @return the compile unit's replacement.
+     */
+    abstract CompileUnit getReplacement(final CompileUnit oldUnit);
+
+    CompileUnit getExistingReplacement(final CompileUnitHolder node) {
+        final CompileUnit oldUnit = node.getCompileUnit();
+        assert oldUnit != null;
+
+        final CompileUnit newUnit = getReplacement(oldUnit);
+        assert newUnit != null;
+
+        return newUnit;
+    }
+
+    @Override
+    public Node leaveFunctionNode(final FunctionNode node) {
+        return node.setCompileUnit(lc, getExistingReplacement(node)).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
+    }
+
+    @Override
+    public Node leaveLiteralNode(final LiteralNode<?> node) {
+        if (node instanceof ArrayLiteralNode) {
+            final ArrayLiteralNode aln = (ArrayLiteralNode)node;
+            if (aln.getUnits() == null) {
+                return node;
+            }
+            final List<ArrayUnit> newArrayUnits = new ArrayList<>();
+            for (final ArrayUnit au : aln.getUnits()) {
+                newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi()));
+            }
+            return aln.setUnits(lc, newArrayUnits);
+        }
+        return node;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import static jdk.nashorn.internal.ir.Node.NO_FINISH;
+import static jdk.nashorn.internal.ir.Node.NO_LINE_NUMBER;
+import static jdk.nashorn.internal.ir.Node.NO_TOKEN;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+import java.util.Objects;
+import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockLexicalContext;
+import jdk.nashorn.internal.ir.BreakNode;
+import jdk.nashorn.internal.ir.CallNode;
+import jdk.nashorn.internal.ir.CaseNode;
+import jdk.nashorn.internal.ir.ContinueNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.GetSplitState;
+import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.IfNode;
+import jdk.nashorn.internal.ir.JumpStatement;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ReturnNode;
+import jdk.nashorn.internal.ir.SetSplitState;
+import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SplitReturn;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.SwitchNode;
+import jdk.nashorn.internal.ir.VarNode;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
+import jdk.nashorn.internal.parser.TokenType;
+
+/**
+ * A node visitor that replaces {@link SplitNode}s with anonymous function invocations and some additional constructs
+ * to support control flow across splits. By using this transformation, split functions are translated into ordinary
+ * JavaScript functions with nested anonymous functions. The transformations however introduce several AST nodes that
+ * have no JavaScript source representations ({@link GetSplitState}, {@link SetSplitState}, and {@link SplitReturn}),
+ * and therefore such function is no longer reparseable from its source. For that reason, split functions and their
+ * fragments are serialized in-memory and deserialized when they need to be recompiled either for deoptimization or
+ * for type specialization.
+ * NOTE: all {@code leave*()} methods for statements are returning their input nodes. That way, they will not mutate
+ * the original statement list in the block containing the statement, which is fine, as it'll be replaced by the
+ * lexical context when the block is left. If we returned something else (e.g. null), we'd cause a mutation in the
+ * enclosing block's statement list that is otherwise overwritten later anyway.
+ */
+final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
+    private static final int FALLTHROUGH_STATE = -1;
+    private static final int RETURN_STATE = 0;
+    private static final int BREAK_STATE = 1;
+    private static final int FIRST_JUMP_STATE = 2;
+
+    private static final String THIS_NAME = CompilerConstants.THIS.symbolName();
+    private static final String RETURN_NAME = CompilerConstants.RETURN.symbolName();
+    // Used as the name of the formal parameter for passing the current value of :return symbol into a split fragment.
+    private static final String RETURN_PARAM_NAME = RETURN_NAME + "-in";
+
+    private final Deque<FunctionState> functionStates = new ArrayDeque<>();
+    private final Deque<SplitState> splitStates = new ArrayDeque<>();
+    private final Namespace namespace;
+
+    private boolean artificialBlock = false;
+
+    // -1 is program; we need to use negative ones
+    private int nextFunctionId = -2;
+
+    public SplitIntoFunctions(final Compiler compiler) {
+        super(new BlockLexicalContext() {
+            @Override
+            protected Block afterSetStatements(Block block) {
+                for(Statement stmt: block.getStatements()) {
+                    assert !(stmt instanceof SplitNode);
+                }
+                return block;
+            }
+        });
+        namespace = new Namespace(compiler.getScriptEnvironment().getNamespace());
+    }
+
+    @Override
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        functionStates.push(new FunctionState(functionNode));
+        return true;
+    }
+
+    @Override
+    public Node leaveFunctionNode(final FunctionNode functionNode) {
+        functionStates.pop();
+        return functionNode;
+    }
+
+    @Override
+    protected Node leaveDefault(final Node node) {
+        if (node instanceof Statement) {
+            appendStatement((Statement)node);
+        }
+        return node;
+    }
+
+    @Override
+    public boolean enterSplitNode(final SplitNode splitNode) {
+        getCurrentFunctionState().splitDepth++;
+        splitStates.push(new SplitState(splitNode));
+        return true;
+    }
+
+    @Override
+    public Node leaveSplitNode(final SplitNode splitNode) {
+        // Replace the split node with an anonymous function expression call.
+
+        final FunctionState fnState = getCurrentFunctionState();
+
+        final String name = splitNode.getName();
+        Block body = splitNode.getBody();
+        final int firstLineNumber = body.getFirstStatementLineNumber();
+        final long token = body.getToken();
+        final int finish = body.getFinish();
+
+        final FunctionNode originalFn = fnState.fn;
+        assert originalFn == lc.getCurrentFunction();
+        final boolean isProgram = originalFn.isProgram();
+
+        // Change SplitNode({...}) into "function () { ... }", or "function (:return-in) () { ... }" (for program)
+        final long newFnToken = Token.toDesc(TokenType.FUNCTION, nextFunctionId--, 0);
+        final FunctionNode fn = new FunctionNode(
+                originalFn.getSource(),
+                body.getFirstStatementLineNumber(),
+                newFnToken,
+                finish,
+                NO_TOKEN,
+                namespace,
+                createIdent(name),
+                originalFn.getName() + "$" + name,
+                isProgram ? Collections.singletonList(createReturnParamIdent()) : Collections.<IdentNode>emptyList(),
+                FunctionNode.Kind.NORMAL,
+                // We only need IS_SPLIT conservatively, in case it contains any array units so that we force
+                // the :callee's existence, to force :scope to never be in a slot lower than 2. This is actually
+                // quite a horrible hack to do with CodeGenerator.fixScopeSlot not trampling other parameters
+                // and should go away once we no longer have array unit handling in codegen. Note however that
+                // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
+                FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT
+        )
+        .setBody(lc, body)
+        .setCompileUnit(lc, splitNode.getCompileUnit())
+        .copyCompilationState(lc, originalFn);
+
+        // Call the function:
+        //     either "(function () { ... }).call(this)"
+        //     or     "(function (:return-in) { ... }).call(this, :return)"
+        // NOTE: Function.call() has optimized linking that basically does a pass-through to the function being invoked.
+        // NOTE: CompilationPhase.PROGRAM_POINT_PHASE happens after this, so these calls are subject to optimistic
+        // assumptions on their return value (when they return a value), as they should be.
+        final IdentNode thisIdent = createIdent(THIS_NAME);
+        final CallNode callNode = new CallNode(firstLineNumber, token, finish, new AccessNode(NO_TOKEN, NO_FINISH, fn, "call"),
+                isProgram ? Arrays.<Expression>asList(thisIdent, createReturnIdent())
+                          : Collections.<Expression>singletonList(thisIdent),
+                false);
+
+        final SplitState splitState = splitStates.pop();
+        fnState.splitDepth--;
+
+        final Expression callWithReturn;
+        final boolean hasReturn = splitState.hasReturn;
+        if (hasReturn && fnState.splitDepth > 0) {
+            final SplitState parentSplit = splitStates.peek();
+            if (parentSplit != null) {
+                // Propagate hasReturn to parent split
+                parentSplit.hasReturn = true;
+            }
+        }
+        if (hasReturn || isProgram) {
+            // capture return value: ":return = (function () { ... })();"
+            callWithReturn = new BinaryNode(Token.recast(token, TokenType.ASSIGN), createReturnIdent(), callNode);
+        } else {
+            // no return value, just call : "(function () { ... })();"
+            callWithReturn = callNode;
+        }
+        appendStatement(new ExpressionStatement(firstLineNumber, token, finish, callWithReturn));
+
+        Statement splitStateHandler;
+
+        final List<JumpStatement> jumpStatements = splitState.jumpStatements;
+        final int jumpCount = jumpStatements.size();
+        // There are jumps (breaks or continues) that need to be propagated outside the split node. We need to
+        // set up a switch statement for them:
+        // switch(:scope.getScopeState()) { ... }
+        if (jumpCount > 0) {
+            final List<CaseNode> cases = new ArrayList<>(jumpCount + (hasReturn ? 1 : 0));
+            if (hasReturn) {
+                // If the split node also contained a return, we'll slip it as a case in the switch statement
+                addCase(cases, RETURN_STATE, createReturnFromSplit());
+            }
+            int i = FIRST_JUMP_STATE;
+            for (final JumpStatement jump: jumpStatements) {
+                addCase(cases, i++, enblockAndVisit(jump));
+            }
+            splitStateHandler = new SwitchNode(NO_LINE_NUMBER, token, finish, GetSplitState.INSTANCE, cases, null);
+        } else {
+            splitStateHandler = null;
+        }
+
+        // As the switch statement itself is breakable, an unlabelled break can't be in the switch statement,
+        // so we need to test for it separately.
+        if (splitState.hasBreak) {
+            // if(:scope.getScopeState() == Scope.BREAK) { break; }
+            splitStateHandler = makeIfStateEquals(firstLineNumber, token, finish, BREAK_STATE,
+                    enblockAndVisit(new BreakNode(NO_LINE_NUMBER, token, finish, null)), splitStateHandler);
+        }
+
+        // Finally, if the split node had a return statement, but there were no external jumps, we didn't have
+        // the switch statement to handle the return, so we need a separate if for it.
+        if (hasReturn && jumpCount == 0) {
+            // if (:scope.getScopeState() == Scope.RETURN) { return :return; }
+            splitStateHandler = makeIfStateEquals(NO_LINE_NUMBER, token, finish, RETURN_STATE,
+                    createReturnFromSplit(), splitStateHandler);
+        }
+
+        if (splitStateHandler != null) {
+            appendStatement(splitStateHandler);
+        }
+
+        return splitNode;
+    }
+
+    private static void addCase(final List<CaseNode> cases, final int i, final Block body) {
+        cases.add(new CaseNode(NO_TOKEN, NO_FINISH, intLiteral(i), body));
+    }
+
+    private static LiteralNode<Number> intLiteral(final int i) {
+        return LiteralNode.newInstance(NO_TOKEN, NO_FINISH, i);
+    }
+
+    private static Block createReturnFromSplit() {
+        return new Block(NO_TOKEN, NO_FINISH, createReturnReturn());
+    }
+
+    private static ReturnNode createReturnReturn() {
+        return new ReturnNode(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH, createReturnIdent());
+    }
+
+    private static IdentNode createReturnIdent() {
+        return createIdent(RETURN_NAME);
+    }
+
+    private static IdentNode createReturnParamIdent() {
+        return createIdent(RETURN_PARAM_NAME);
+    }
+
+    private static IdentNode createIdent(final String name) {
+        return new IdentNode(NO_TOKEN, NO_FINISH, name);
+    }
+
+    private Block enblockAndVisit(final JumpStatement jump) {
+        artificialBlock = true;
+        final Block block = (Block)new Block(NO_TOKEN, NO_FINISH, jump).accept(this);
+        artificialBlock = false;
+        return block;
+    }
+
+    private static IfNode makeIfStateEquals(final int lineNumber, final long token, final int finish,
+            final int value, final Block pass, final Statement fail) {
+        return new IfNode(lineNumber, token, finish,
+                new BinaryNode(Token.recast(token, TokenType.EQ_STRICT),
+                        GetSplitState.INSTANCE, intLiteral(value)),
+                pass,
+                fail == null ? null : new Block(NO_TOKEN, NO_FINISH, fail));
+    }
+
+    @Override
+    public boolean enterVarNode(VarNode varNode) {
+        if (!inSplitNode()) {
+            return super.enterVarNode(varNode);
+        }
+        assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
+
+        final Expression init = varNode.getInit();
+        if (varNode.isAnonymousFunctionDeclaration()) {
+            // We ain't moving anonymous function declarations.
+            return super.enterVarNode(varNode);
+        }
+
+        // Move a declaration-only var statement to the top of the outermost function.
+        getCurrentFunctionState().varStatements.add(varNode.setInit(null));
+        // If it had an initializer, replace it with an assignment expression statement. Note that "var" is a
+        // statement, so it doesn't contribute to :return of the programs, therefore we are _not_ adding a
+        // ":return = ..." assignment around the original assignment.
+        if (init != null) {
+            final long token = Token.recast(varNode.getToken(), TokenType.ASSIGN);
+            new ExpressionStatement(varNode.getLineNumber(), token, varNode.getFinish(),
+                    new BinaryNode(token, varNode.getName(), varNode.getInit())).accept(this);
+        }
+
+        return false;
+    }
+
+    @Override
+    public Node leaveBlock(final Block block) {
+        if (!artificialBlock) {
+            if (lc.isFunctionBody()) {
+                // Prepend declaration-only var statements to the top of the statement list.
+                lc.prependStatements(getCurrentFunctionState().varStatements);
+            } else if (lc.isSplitBody()) {
+                appendSplitReturn(FALLTHROUGH_STATE, NO_LINE_NUMBER);
+                if (getCurrentFunctionState().fn.isProgram()) {
+                    // If we're splitting the program, make sure every shard ends with "return :return" and
+                    // begins with ":return = :return-in;".
+                    lc.prependStatement(new ExpressionStatement(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH,
+                            new BinaryNode(Token.toDesc(TokenType.ASSIGN, 0, 0), createReturnIdent(), createReturnParamIdent())));
+                }
+            }
+        }
+        return block;
+    }
+
+    @Override
+    public Node leaveBreakNode(final BreakNode breakNode) {
+        return leaveJumpNode(breakNode);
+    }
+
+    @Override
+    public Node leaveContinueNode(final ContinueNode continueNode) {
+        return leaveJumpNode(continueNode);
+    }
+
+    private JumpStatement leaveJumpNode(final JumpStatement jump) {
+        if (inSplitNode()) {
+            final SplitState splitState = getCurrentSplitState();
+            final SplitNode splitNode = splitState.splitNode;
+            if (lc.isExternalTarget(splitNode, jump.getTarget(lc))) {
+                appendSplitReturn(splitState.getSplitStateIndex(jump), jump.getLineNumber());
+                return jump;
+            }
+        }
+        appendStatement(jump);
+        return jump;
+    }
+
+    private void appendSplitReturn(final int splitState, final int lineNumber) {
+        appendStatement(new SetSplitState(splitState, lineNumber));
+        if (getCurrentFunctionState().fn.isProgram()) {
+            // If we're splitting the program, make sure every fragment passes back :return
+            appendStatement(createReturnReturn());
+        } else {
+            appendStatement(SplitReturn.INSTANCE);
+        }
+    }
+
+    @Override
+    public Node leaveReturnNode(final ReturnNode returnNode) {
+        if(inSplitNode()) {
+            appendStatement(new SetSplitState(RETURN_STATE, returnNode.getLineNumber()));
+            getCurrentSplitState().hasReturn = true;
+        }
+        appendStatement(returnNode);
+        return returnNode;
+    }
+
+    private void appendStatement(final Statement statement) {
+        lc.appendStatement(statement);
+    }
+
+    private boolean inSplitNode() {
+        return getCurrentFunctionState().splitDepth > 0;
+    }
+
+    private FunctionState getCurrentFunctionState() {
+        return functionStates.peek();
+    }
+
+    private SplitState getCurrentSplitState() {
+        return splitStates.peek();
+    }
+
+    private static class FunctionState {
+        final FunctionNode fn;
+        final List<Statement> varStatements = new ArrayList<>();
+        int splitDepth;
+
+        FunctionState(final FunctionNode fn) {
+            this.fn = fn;
+        }
+    }
+
+    private static class SplitState {
+        final SplitNode splitNode;
+        boolean hasReturn;
+        boolean hasBreak;
+
+        final List<JumpStatement> jumpStatements = new ArrayList<>();
+
+        int getSplitStateIndex(final JumpStatement jump) {
+            if (jump instanceof BreakNode && jump.getLabelName() == null) {
+                // Unlabelled break is a special case
+                hasBreak = true;
+                return BREAK_STATE;
+            }
+
+            int i = 0;
+            for(final JumpStatement exJump: jumpStatements) {
+                if (jump.getClass() == exJump.getClass() && Objects.equals(jump.getLabelName(), exJump.getLabelName())) {
+                    return i + FIRST_JUMP_STATE;
+                }
+                ++i;
+            }
+            jumpStatements.add(jump);
+            return i + FIRST_JUMP_STATE;
+        }
+
+        SplitState(final SplitNode splitNode) {
+            this.splitNode = splitNode;
+        }
+    }
+}
--- a/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Fri Oct 10 15:53:41 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +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.codegen;
-
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-
-import java.util.ArrayList;
-import java.util.List;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.nashorn.internal.codegen.types.Type;
-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
- * outside the current split node. All external jump targets encountered at method
- * emission are logged, and {@code CodeGenerator#leaveSplitNode(SplitNode)} creates
- * an appropriate jump table when the SplitNode has been iterated through
- */
-public class SplitMethodEmitter extends MethodEmitter {
-
-    private final SplitNode splitNode;
-
-    private final List<Label> externalTargets = new ArrayList<>();
-    /**
-     * In addition to external target labels, we need to track the target breakables too as the code generator needs to
-     * be able to correctly pop the scopes to the target, see {@link CodeGenerator#leaveSplitNode(SplitNode)}. Note that
-     * this is only used within CodeGenerator, which doesn't mutate the AST, so keeping pointers to other nodes is not
-     * incorrect.
-     */
-    private final List<BreakableNode> externalTargetNodes = new ArrayList<>();
-
-    SplitMethodEmitter(final ClassEmitter classEmitter, final MethodVisitor mv, final SplitNode splitNode) {
-        super(classEmitter, mv);
-        this.splitNode = splitNode;
-    }
-
-    @Override
-    void splitAwareGoto(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
-        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;
-        }
-        super.splitAwareGoto(lc, label, targetNode);
-    }
-
-    private int findExternalTarget(final LexicalContext lc, final Label label, final BreakableNode targetNode) {
-        final int index = externalTargets.indexOf(label);
-
-        if (index >= 0) {
-            return index;
-        }
-
-        if (lc.isExternalTarget(splitNode, targetNode)) {
-            externalTargets.add(label);
-            externalTargetNodes.add(targetNode);
-            return externalTargets.size() - 1;
-        }
-        return -1;
-    }
-
-    @Override
-    MethodEmitter registerReturn() {
-        setHasReturn();
-        loadCompilerConstant(SCOPE);
-        checkcast(Scope.class);
-        load(0);
-        invoke(Scope.SET_SPLIT_STATE);
-        return this;
-    }
-
-    final List<Label> getExternalTargets() {
-        return externalTargets;
-    }
-
-    final List<BreakableNode> getExternalTargetNodes() {
-        return externalTargetNodes;
-    }
-}
--- a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -29,16 +29,22 @@
 import static jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
 import static jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
 
+import java.lang.invoke.MethodType;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.Optimistic;
+import jdk.nashorn.internal.objects.ArrayBufferView;
 import jdk.nashorn.internal.objects.NativeArray;
 import jdk.nashorn.internal.runtime.FindProperty;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -47,6 +53,13 @@
  * Used during recompilation.
  */
 final class TypeEvaluator {
+    /**
+     * Type signature for invocation of functions without parameters: we must pass (callee, this) of type
+     * (ScriptFunction, Object) respectively. We also use Object as the return type (we must pass something,
+     * but it'll be ignored; it can't be void, though).
+     */
+    private static final MethodType EMPTY_INVOCATION_TYPE = MethodType.methodType(Object.class, ScriptFunction.class, Object.class);
+
     private final Compiler compiler;
     private final ScriptObject runtimeScope;
 
@@ -190,30 +203,46 @@
                 return null;
             }
             return getPropertyType(runtimeScope, ((IdentNode)expr).getName());
-        }
-
-        if (expr instanceof AccessNode) {
+        } else if (expr instanceof AccessNode) {
             final AccessNode accessNode = (AccessNode)expr;
             final Object base = evaluateSafely(accessNode.getBase());
             if (!(base instanceof ScriptObject)) {
                 return null;
             }
             return getPropertyType((ScriptObject)base, accessNode.getProperty());
-        }
-
-        if (expr instanceof IndexNode) {
+        } else if (expr instanceof IndexNode) {
             final IndexNode indexNode = (IndexNode)expr;
             final Object    base = evaluateSafely(indexNode.getBase());
-            if(!(base instanceof NativeArray)) {
-                // We only know how to deal with NativeArray. TODO: maybe manage buffers too
-                return null;
+            if(base instanceof NativeArray || base instanceof ArrayBufferView) {
+                // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their
+                // underlying array storage, not based on values of individual elements. Thus, a LongArrayData will
+                // throw UOE for every optimistic int linkage attempt, even if the long value being returned in the
+                // first invocation would be representable as int. That way, we can presume that the array's optimistic
+                // type is the most optimistic type for which an element getter has a chance of executing successfully.
+                return ((ScriptObject)base).getArray().getOptimisticType();
             }
-            // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their underlying
-            // array storage, not based on values of individual elements. Thus, a LongArrayData will throw UOE for every
-            // optimistic int linkage attempt, even if the long value being returned in the first invocation would be
-            // representable as int. That way, we can presume that the array's optimistic type is the most optimistic
-            // type for which an element getter has a chance of executing successfully.
-            return ((NativeArray)base).getArray().getOptimisticType();
+        } else if (expr instanceof CallNode) {
+            // Currently, we'll only try to guess the return type of immediately invoked function expressions with no
+            // parameters, that is (function() { ... })(). We could do better, but these are all heuristics and we can
+            // gradually introduce them as needed. An easy one would be to do the same for .call(this) idiom.
+            final CallNode callExpr = (CallNode)expr;
+            final Expression fnExpr = callExpr.getFunction();
+            if (fnExpr instanceof FunctionNode) {
+                final FunctionNode fn = (FunctionNode)fnExpr;
+                if (callExpr.getArgs().isEmpty()) {
+                    final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
+                    if (data != null) {
+                        final Type returnType = Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
+                        if (returnType == Type.BOOLEAN) {
+                            // We don't have optimistic booleans. In fact, optimistic call sites getting back boolean
+                            // currently deoptimize all the way to Object.
+                            return Type.OBJECT;
+                        }
+                        assert returnType == Type.INT || returnType == Type.LONG || returnType == Type.NUMBER || returnType == Type.OBJECT;
+                        return returnType;
+                    }
+                }
+            }
         }
 
         return null;
--- a/src/jdk/nashorn/internal/codegen/types/ArrayType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/ArrayType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -37,6 +37,7 @@
  * This is an array type, i.e. OBJECT_ARRAY, NUMBER_ARRAY.
  */
 public class ArrayType extends ObjectType implements BytecodeArrayOps {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk/nashorn/internal/codegen/types/BitwiseType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/BitwiseType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -29,6 +29,7 @@
  * This class represents a numeric type that can be used for bit operations.
  */
 public abstract class BitwiseType extends NumericType implements BytecodeBitwiseOps {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk/nashorn/internal/codegen/types/BooleanType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/BooleanType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -69,6 +69,7 @@
  * The boolean type class
  */
 public final class BooleanType extends Type {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Boolean.class, "valueOf", Boolean.class, boolean.class);
     private static final CompilerConstants.Call TO_STRING = staticCallNoLookup(Boolean.class, "toString", String.class, boolean.class);
--- a/src/jdk/nashorn/internal/codegen/types/IntType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/IntType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -60,6 +60,7 @@
  * Type class: INT
  */
 class IntType extends BitwiseType {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call TO_STRING = staticCallNoLookup(Integer.class, "toString", String.class, int.class);
     private static final CompilerConstants.Call VALUE_OF  = staticCallNoLookup(Integer.class, "valueOf", Integer.class, int.class);
--- a/src/jdk/nashorn/internal/codegen/types/LongType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/LongType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -54,6 +54,7 @@
  * Type class: LONG
  */
 class LongType extends BitwiseType {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Long.class, "valueOf", Long.class, long.class);
 
--- a/src/jdk/nashorn/internal/codegen/types/NumberType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/NumberType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -46,6 +46,7 @@
 import jdk.nashorn.internal.runtime.JSType;
 
 class NumberType extends NumericType {
+    private static final long serialVersionUID = 1L;
 
     private static final CompilerConstants.Call VALUE_OF = staticCallNoLookup(Double.class, "valueOf", Double.class, double.class);
 
--- a/src/jdk/nashorn/internal/codegen/types/NumericType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/NumericType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -29,6 +29,8 @@
  * This is a numeric type, i.e. NUMBER, LONG, INT, INT32.
  */
 public abstract class NumericType extends Type implements BytecodeNumericOps {
+    private static final long serialVersionUID = 1L;
+
     /**
      * Constructor
      *
--- a/src/jdk/nashorn/internal/codegen/types/ObjectType.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/ObjectType.java	Tue Nov 04 17:21:00 2014 +0000
@@ -47,6 +47,7 @@
  * contain a class that is a more specialized object
  */
 class ObjectType extends Type {
+    private static final long serialVersionUID = 1L;
 
     protected ObjectType() {
         this(Object.class);
--- a/src/jdk/nashorn/internal/codegen/types/Type.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java	Tue Nov 04 17:21:00 2014 +0000
@@ -51,12 +51,15 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.Serializable;
 import java.lang.invoke.CallSite;
 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;
@@ -87,23 +90,34 @@
  * INTs rather than OBJECTs
  */
 
-public abstract class Type implements Comparable<Type>, BytecodeOps {
+public abstract class Type implements Comparable<Type>, BytecodeOps, Serializable {
+    private static final long serialVersionUID = 1L;
 
     /** Human readable name for type */
-    private final String name;
+    private transient final String name;
 
     /** Descriptor for type */
-    private final String descriptor;
+    private transient final String descriptor;
 
     /** The "weight" of the type. Used for picking widest/least specific common type */
-    private final int weight;
+    private transient final int weight;
 
     /** How many bytecode slots does this type occupy */
-    private final int slots;
+    private transient final int slots;
 
     /** 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 transient 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 +136,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 +314,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 +344,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 +372,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) {
@@ -911,6 +937,8 @@
      * This is the singleton for integer arrays
      */
     public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public void astore(final MethodVisitor method) {
             method.visitInsn(IASTORE);
@@ -938,6 +966,8 @@
      * This is the singleton for long arrays
      */
     public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public void astore(final MethodVisitor method) {
             method.visitInsn(LASTORE);
@@ -965,6 +995,8 @@
      * This is the singleton for numeric arrays
      */
     public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public void astore(final MethodVisitor method) {
             method.visitInsn(DASTORE);
@@ -999,6 +1031,8 @@
 
     /** This type, always an object type, just a toString override */
     public static final Type THIS = new ObjectType() {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public String toString() {
             return "this";
@@ -1007,6 +1041,8 @@
 
     /** Scope type, always an object type, just a toString override */
     public static final Type SCOPE = new ObjectType() {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public String toString() {
             return "scope";
@@ -1018,6 +1054,7 @@
     }
 
     private abstract static class ValueLessType extends Type {
+        private static final long serialVersionUID = 1L;
 
         ValueLessType(final String name) {
             super(name, Unknown.class, MIN_WEIGHT, 1);
@@ -1069,6 +1106,8 @@
      * inference. It has the minimum type width
      */
     public static final Type UNKNOWN = new ValueLessType("<unknown>") {
+        private static final long serialVersionUID = 1L;
+
         @Override
         public String getDescriptor() {
             return "<unknown>";
@@ -1085,6 +1124,7 @@
      * inference. It has the minimum type width
      */
     public static final Type SLOT_2 = new ValueLessType("<slot_2>") {
+        private static final long serialVersionUID = 1L;
 
         @Override
         public String getDescriptor() {
@@ -1101,4 +1141,8 @@
         cache.put(type.getTypeClass(), type);
         return type;
     }
+
+    protected final Object readResolve() {
+        return Type.typeFor(clazz);
+    }
 }
--- a/src/jdk/nashorn/internal/ir/AccessNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -34,6 +34,8 @@
  */
 @Immutable
 public final class AccessNode extends BaseNode {
+    private static final long serialVersionUID = 1L;
+
     /** Property name. */
     private final String property;
 
--- a/src/jdk/nashorn/internal/ir/BaseNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/BaseNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -39,6 +39,7 @@
  */
 @Immutable
 public abstract class BaseNode extends Expression implements FunctionCall, Optimistic {
+    private static final long serialVersionUID = 1L;
 
     /** Base Node. */
     protected final Expression base;
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -43,6 +43,8 @@
  */
 @Immutable
 public final class BinaryNode extends Expression implements Assignment<Expression>, Optimistic {
+    private static final long serialVersionUID = 1L;
+
     // Placeholder for "undecided optimistic ADD type". Unfortunately, we can't decide the type of ADD during optimistic
     // type calculation as it can have local variables as its operands that will decide its ultimate type.
     private static final Type OPTIMISTIC_UNDECIDED_TYPE = Type.typeFor(new Object(){/*empty*/}.getClass());
@@ -56,8 +58,8 @@
 
     private final Type type;
 
-    private Type cachedType;
-    private Object cachedTypeFunction;
+    private transient Type cachedType;
+    private transient Object cachedTypeFunction;
 
     @Ignore
     private static final Set<TokenType> CAN_OVERFLOW =
--- a/src/jdk/nashorn/internal/ir/Block.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/Block.java	Tue Nov 04 17:21:00 2014 +0000
@@ -42,6 +42,8 @@
  */
 @Immutable
 public class Block extends Node implements BreakableNode, Terminal, Flags<Block> {
+    private static final long serialVersionUID = 1L;
+
     /** List of statements */
     protected final List<Statement> statements;
 
--- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Tue Nov 04 17:21:00 2014 +0000
@@ -109,6 +109,16 @@
     }
 
     /**
+     * Prepend a list of statement to the block being generated
+     * @param statements a list of statements to prepend
+     */
+    public void prependStatements(final List<Statement> statements) {
+        assert statements != null;
+        sstack.peek().addAll(0, statements);
+    }
+
+
+    /**
      * Get the last statement that was emitted into a block
      * @return the last statement emitted
      */
--- a/src/jdk/nashorn/internal/ir/BlockStatement.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/BlockStatement.java	Tue Nov 04 17:21:00 2014 +0000
@@ -32,6 +32,8 @@
  * Represents a block used as a statement.
  */
 public class BlockStatement extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Block to execute. */
     private final Block block;
 
--- a/src/jdk/nashorn/internal/ir/BreakNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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;
 
@@ -33,6 +34,7 @@
  */
 @Immutable
 public final class BreakNode extends JumpStatement {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
@@ -68,4 +70,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/BreakableStatement.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/BreakableStatement.java	Tue Nov 04 17:21:00 2014 +0000
@@ -32,6 +32,7 @@
 
 @Immutable
 abstract class BreakableStatement extends LexicalContextStatement implements BreakableNode {
+    private static final long serialVersionUID = 1L;
 
     /** break label. */
     protected final Label breakLabel;
--- a/src/jdk/nashorn/internal/ir/CallNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/CallNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -27,6 +27,7 @@
 
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 
+import java.io.Serializable;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Function;
@@ -40,6 +41,7 @@
  */
 @Immutable
 public final class CallNode extends LexicalContextExpression implements Optimistic {
+    private static final long serialVersionUID = 1L;
 
     /** Function identifier or function body. */
     private final Expression function;
@@ -64,7 +66,8 @@
     /**
      * Arguments to be passed to builtin {@code eval} function
      */
-    public static class EvalArgs {
+    public static class EvalArgs implements Serializable {
+        private static final long serialVersionUID = 1L;
         private final List<Expression> args;
 
         /** location string for the eval call */
--- a/src/jdk/nashorn/internal/ir/CaseNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/CaseNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -37,6 +37,8 @@
  */
 @Immutable
 public final class CaseNode extends Node implements JoinPredecessor, Labels, Terminal {
+    private static final long serialVersionUID = 1L;
+
     /** Test expression. */
     private final Expression test;
 
--- a/src/jdk/nashorn/internal/ir/CatchNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/CatchNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class CatchNode extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Exception identifier. */
     private final IdentNode exception;
 
--- a/src/jdk/nashorn/internal/ir/ContinueNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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;
 
@@ -33,6 +34,8 @@
  */
 @Immutable
 public class ContinueNode extends JumpStatement {
+    private static final long serialVersionUID = 1L;
+
     /**
      * Constructor
      *
@@ -67,5 +70,15 @@
     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/EmptyNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/EmptyNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,7 @@
  */
 @Immutable
 public final class EmptyNode extends Statement {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Constructor
--- a/src/jdk/nashorn/internal/ir/Expression.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/Expression.java	Tue Nov 04 17:21:00 2014 +0000
@@ -35,6 +35,8 @@
  *
  */
 public abstract class Expression extends Node {
+    private static final long serialVersionUID = 1L;
+
     static final String OPT_IDENTIFIER = "%";
 
     private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
--- a/src/jdk/nashorn/internal/ir/ExpressionStatement.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/ExpressionStatement.java	Tue Nov 04 17:21:00 2014 +0000
@@ -35,6 +35,8 @@
  */
 @Immutable
 public final class ExpressionStatement extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Expression to execute. */
     private final Expression expression;
 
--- a/src/jdk/nashorn/internal/ir/ForNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/ForNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class ForNode extends LoopNode {
+    private static final long serialVersionUID = 1L;
+
     /** Initialize expression for an ordinary for statement, or the LHS expression receiving iterated-over values in a
      * for-in statement. */
     private final Expression init;
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -57,6 +57,8 @@
  */
 @Immutable
 public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode>, CompileUnitHolder {
+    private static final long serialVersionUID = 1L;
+
     /** Type used for all FunctionNodes */
     public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
 
@@ -107,7 +109,7 @@
     }
 
     /** Source of entity. */
-    private final Source source;
+    private transient final Source source;
 
     /**
      * Opaque object representing parser state at the end of the function. Used when reparsing outer functions
@@ -141,7 +143,7 @@
     private final long lastToken;
 
     /** Method's namespace. */
-    private final Namespace namespace;
+    private transient final Namespace namespace;
 
     /** Current compilation state */
     @Ignore
@@ -207,56 +209,52 @@
     /** Are we vararg, but do we just pass the arguments along to apply or call */
     public static final int HAS_APPLY_TO_CALL_SPECIALIZATION = 1 << 12;
 
-    /** Does this function explicitly use the {@link CompilerConstants#RETURN} symbol? Some functions are known to
-     * always use the return symbol, namely a function that is a program (as it must track its last executed expression
-     * statement's value) as well as functions that are split (to communicate return values from inner to outer
-     * partitions). Other functions normally don't use the return symbol (so we optimize away its slot), except in some
-     * very special cases, e.g. when containing a return statement in a finally block. These special cases set this
-     * flag. */
-    public static final int USES_RETURN_SYMBOL = 1 << 13;
-
     /**
      * Is this function the top-level program?
      */
-    public static final int IS_PROGRAM = 1 << 14;
+    public static final int IS_PROGRAM = 1 << 13;
 
     /**
      * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
      * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
      * use the symbol in their parent scope instead when they reference themselves by name.
      */
-    public static final int USES_SELF_SYMBOL = 1 << 15;
+    public static final int USES_SELF_SYMBOL = 1 << 14;
 
     /** Does this function use the "this" keyword? */
-    public static final int USES_THIS = 1 << 16;
+    public static final int USES_THIS = 1 << 15;
 
     /** Is this declared in a dynamic context */
-    public static final int IN_DYNAMIC_CONTEXT = 1 << 17;
+    public static final int IN_DYNAMIC_CONTEXT = 1 << 16;
 
     /**
      * The following flags are derived from directive comments within this function.
      * Note that even IS_STRICT is one such flag but that requires special handling.
      */
 
-    // parser, lower debugging this function
-    public static final int IS_PRINT_PARSE       = 1 << 18;
-    public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
-    public static final int IS_PRINT_AST         = 1 << 20;
-    public static final int IS_PRINT_LOWER_AST   = 1 << 21;
-    public static final int IS_PRINT_SYMBOLS     = 1 << 22;
-
-    /** profile callsites in this function? */
-    public static final int IS_PROFILE         = 1 << 23;
+    /** parser, print parse tree */
+    public static final int IS_PRINT_PARSE       = 1 << 17;
+    /** parser, print lower parse tree */
+    public static final int IS_PRINT_LOWER_PARSE = 1 << 18;
+    /** parser, print AST */
+    public static final int IS_PRINT_AST         = 1 << 19;
+    /** parser, print lower AST */
+    public static final int IS_PRINT_LOWER_AST   = 1 << 20;
+    /** parser, print symbols */
+    public static final int IS_PRINT_SYMBOLS     = 1 << 21;
 
     // callsite tracing, profiling within this function
+    /** profile callsites in this function? */
+    public static final int IS_PROFILE         = 1 << 22;
+
     /** trace callsite enterexit in this function? */
-    public static final int IS_TRACE_ENTEREXIT = 1 << 24;
+    public static final int IS_TRACE_ENTEREXIT = 1 << 23;
 
     /** trace callsite misses in this function? */
-    public static final int IS_TRACE_MISSES    = 1 << 25;
+    public static final int IS_TRACE_MISSES    = 1 << 24;
 
     /** trace callsite values in this function? */
-    public static final int IS_TRACE_VALUES    = 1 << 26;
+    public static final int IS_TRACE_VALUES    = 1 << 25;
 
     /**
      * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
@@ -264,7 +262,7 @@
      * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
      * will, however, cache the value of this flag.
      */
-    public static final int NEEDS_CALLEE       = 1 << 27;
+    public static final int NEEDS_CALLEE       = 1 << 26;
 
     /** extension callsite flags mask */
     public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
@@ -281,8 +279,8 @@
     /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
     private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
 
-    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval. */
-    private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL;
+    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval, or it's the program. */
+    public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM;
 
     /** What is the return type of this function? */
     private Type returnType = Type.UNKNOWN;
@@ -337,7 +335,7 @@
     private FunctionNode(
         final FunctionNode functionNode,
         final long lastToken,
-        Object endParserState,
+        final Object endParserState,
         final int flags,
         final String name,
         final Type returnType,
@@ -346,7 +344,8 @@
         final Block body,
         final List<IdentNode> parameters,
         final int thisProperties,
-        final Class<?> rootClass) {
+        final Class<?> rootClass,
+        final Source source, Namespace namespace) {
         super(functionNode);
 
         this.endParserState    = endParserState;
@@ -361,11 +360,11 @@
         this.parameters       = parameters;
         this.thisProperties   = thisProperties;
         this.rootClass        = rootClass;
+        this.source           = source;
+        this.namespace        = namespace;
 
         // the fields below never change - they are final and assigned in constructor
-        this.source          = functionNode.source;
         this.ident           = functionNode.ident;
-        this.namespace       = functionNode.namespace;
         this.kind            = functionNode.kind;
         this.firstToken      = functionNode.firstToken;
     }
@@ -431,6 +430,39 @@
     }
 
     /**
+     * Sets the source and namespace for this function. It can only set a non-null source and namespace for a function
+     * that currently has both a null source and a null namespace. This is used to re-set the source and namespace for
+     * a deserialized function node.
+     * @param source the source for the function.
+     * @param namespace the namespace for the function
+     * @return a new function node with the set source and namespace
+     * @throws IllegalArgumentException if the specified source or namespace is null
+     * @throws IllegalStateException if the function already has either a source or namespace set.
+     */
+    public FunctionNode initializeDeserialized(final Source source, final Namespace namespace) {
+        if (source == null || namespace == null) {
+            throw new IllegalArgumentException();
+        } else if (this.source == source && this.namespace == namespace) {
+            return this;
+        } else if (this.source != null || this.namespace != null) {
+            throw new IllegalStateException();
+        }
+        return new FunctionNode(
+            this,
+            lastToken,
+            endParserState,
+            flags,
+            name,
+            returnType,
+            compileUnit,
+            compilationState,
+            body,
+            parameters,
+            thisProperties,
+            rootClass, source, namespace);
+    }
+
+    /**
      * Get the unique ID for this function within the script file.
      * @return the id
      */
@@ -531,6 +563,28 @@
         }
         final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
         newState.add(state);
+        return setCompilationState(lc, newState);
+    }
+
+    /**
+     * Copy a compilation state from an original function to this function. Used when creating synthetic
+     * function nodes by the splitter.
+     *
+     * @param lc lexical context
+     * @param original the original function node to copy compilation state from
+     * @return function node or a new one if state was changed
+     */
+    public FunctionNode copyCompilationState(final LexicalContext lc, final FunctionNode original) {
+        final EnumSet<CompilationState> origState = original.compilationState;
+        if (!AssertsEnabled.assertsEnabled() || this.compilationState.containsAll(origState)) {
+            return this;
+        }
+        final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
+        newState.addAll(origState);
+        return setCompilationState(lc, newState);
+    }
+
+    private FunctionNode setCompilationState(final LexicalContext lc, final EnumSet<CompilationState> compilationState) {
         return Node.replaceInLexicalContext(
                 lc,
                 this,
@@ -542,13 +596,14 @@
                         name,
                         returnType,
                         compileUnit,
-                        newState,
+                        compilationState,
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
+
     /**
      * Create a unique name in the namespace of this FunctionNode
      * @param base prefix for name
@@ -618,7 +673,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     @Override
@@ -693,18 +748,11 @@
      * @return true if the function's generated Java method needs a {@code callee} parameter.
      */
     public boolean needsCallee() {
+        // NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
         return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
     }
 
     /**
-     * Check if this function uses the return symbol
-     * @return true if uses the return symbol
-     */
-    public boolean usesReturnSymbol() {
-        return isProgram() || isSplit() || getFlag(USES_RETURN_SYMBOL);
-    }
-
-    /**
      * Return {@code true} if this function makes use of the {@code this} object.
      *
      * @return true if function uses {@code this} object
@@ -766,7 +814,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -834,7 +882,7 @@
      * @return true if the function needs parent scope.
      */
     public boolean needsParentScope() {
-        return getFlag(NEEDS_PARENT_SCOPE) || isProgram();
+        return getFlag(NEEDS_PARENT_SCOPE);
     }
 
     /**
@@ -862,7 +910,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -923,7 +971,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -958,7 +1006,10 @@
                         compilationState,
                         body,
                         parameters,
-                        thisProperties, rootClass));
+                        thisProperties,
+                        rootClass,
+                        source,
+                        namespace));
     }
 
     /**
@@ -994,7 +1045,9 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass,
+                        source,
+                        namespace));
     }
 
     /**
@@ -1008,9 +1061,9 @@
     }
 
     /**
-     * Checks if this function is a sub-function generated by splitting a larger one
+     * Checks if this function is split into several smaller fragments.
      *
-     * @return true if this function is split from a larger one
+     * @return true if this function is split into several smaller fragments.
      */
     public boolean isSplit() {
         return getFlag(IS_SPLIT);
@@ -1060,7 +1113,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -1139,7 +1192,7 @@
                 body,
                 parameters,
                 thisProperties,
-                rootClass
+                rootClass, source, namespace
                 ));
    }
 
@@ -1187,7 +1240,7 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 
     /**
@@ -1243,6 +1296,6 @@
                         body,
                         parameters,
                         thisProperties,
-                        rootClass));
+                        rootClass, source, namespace));
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/GetSplitState.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 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.ir;
+
+import java.util.function.Function;
+import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.Scope;
+
+/**
+ * Synthetic AST node that represents loading of the scope object and invocation of the {@link Scope#getSplitState()}
+ * method on it. It has no JavaScript source representation and only occurs in synthetic functions created by
+ * the split-into-functions transformation.
+ */
+public final class GetSplitState extends Expression {
+    private static final long serialVersionUID = 1L;
+
+    /** The sole instance of this AST node. */
+    public final static GetSplitState INSTANCE = new GetSplitState();
+
+    private GetSplitState() {
+        super(NO_TOKEN, NO_FINISH);
+    }
+
+    @Override
+    public Type getType(final Function<Symbol, Type> localVariableTypes) {
+        return Type.INT;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return visitor.enterGetSplitState(this) ? visitor.leaveGetSplitState(this) : this;
+    }
+
+    @Override
+    public void toString(final StringBuilder sb, final boolean printType) {
+        if (printType) {
+            sb.append("{I}");
+        }
+        sb.append(CompilerConstants.SCOPE.symbolName()).append('.').append(Scope.GET_SPLIT_STATE.name()).append("()");
+    }
+
+    private Object readResolve() {
+        return INSTANCE;
+    }
+}
--- a/src/jdk/nashorn/internal/ir/IdentNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -42,6 +42,8 @@
  */
 @Immutable
 public final class IdentNode extends Expression implements PropertyKey, FunctionCall, Optimistic, JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     private static final int PROPERTY_NAME     = 1 << 0;
     private static final int INITIALIZED_HERE  = 1 << 1;
     private static final int FUNCTION          = 1 << 2;
--- a/src/jdk/nashorn/internal/ir/IfNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/IfNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class IfNode extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Test expression. */
     private final Expression test;
 
--- a/src/jdk/nashorn/internal/ir/IndexNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class IndexNode extends BaseNode {
+    private static final long serialVersionUID = 1L;
+
     /** Property index. */
     private final Expression index;
 
--- a/src/jdk/nashorn/internal/ir/JoinPredecessorExpression.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/JoinPredecessorExpression.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,7 @@
  * A wrapper for an expression that is in a position to be a join predecessor.
  */
 public class JoinPredecessorExpression extends Expression implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
 
     private final Expression expression;
     private final LocalVariableConversion conversion;
--- a/src/jdk/nashorn/internal/ir/JumpStatement.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/JumpStatement.java	Tue Nov 04 17:21:00 2014 +0000
@@ -25,10 +25,13 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.codegen.Label;
+
 /**
  * Common base class for jump statements (e.g. {@code break} and {@code continue}).
  */
 public abstract class JumpStatement extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
 
     private final String labelName;
     private final LocalVariableConversion conversion;
@@ -82,6 +85,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/LabelNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/LabelNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -35,6 +35,8 @@
  */
 @Immutable
 public final class LabelNode extends LexicalContextStatement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Label ident. */
     private final String labelName;
 
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java	Tue Nov 04 17:21:00 2014 +0000
@@ -440,6 +440,14 @@
     }
 
     /**
+     * Is the topmost lexical context element body of a SplitNode?
+     * @return true if it's the body of a split node.
+     */
+    public boolean isSplitBody() {
+        return sp >= 2 && stack[sp - 1] instanceof Block && stack[sp - 2] instanceof SplitNode;
+    }
+
+    /**
      * Get the parent function for a function in the lexical context
      * @param functionNode function for which to get parent
      * @return parent function of functionNode or null if none (e.g. if functionNode is the program)
@@ -472,9 +480,6 @@
             final LexicalContextNode node = iter.next();
             if (node == until) {
                 break;
-            } else if (node instanceof SplitNode) {
-                // Don't bother popping scopes if we're going to do a return from a split method anyway.
-                return 0;
             }
             assert !(node instanceof FunctionNode); // Can't go outside current function
             if (node instanceof WithNode || node instanceof Block && ((Block)node).needsScope()) {
--- a/src/jdk/nashorn/internal/ir/LexicalContextExpression.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/LexicalContextExpression.java	Tue Nov 04 17:21:00 2014 +0000
@@ -28,6 +28,7 @@
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
 abstract class LexicalContextExpression extends Expression implements LexicalContextNode {
+    private static final long serialVersionUID = 1L;
 
     LexicalContextExpression(final LexicalContextExpression expr) {
         super(expr);
--- a/src/jdk/nashorn/internal/ir/LexicalContextStatement.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/LexicalContextStatement.java	Tue Nov 04 17:21:00 2014 +0000
@@ -28,6 +28,8 @@
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
 abstract class LexicalContextStatement extends Statement implements LexicalContextNode {
+    private static final long serialVersionUID = 1L;
+
     /**
      * Constructor
      *
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import java.io.Serializable;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -49,6 +50,8 @@
  */
 @Immutable
 public abstract class LiteralNode<T> extends Expression implements PropertyKey {
+    private static final long serialVersionUID = 1L;
+
     /** Literal value */
     protected final T value;
 
@@ -237,6 +240,10 @@
         return value;
     }
 
+    private static Expression[] valueToArray(final List<Expression> value) {
+        return value.toArray(new Expression[value.size()]);
+    }
+
     /**
      * Create a new null literal
      *
@@ -266,6 +273,8 @@
      * @param <T> the literal type
      */
     public static class PrimitiveLiteralNode<T> extends LiteralNode<T> {
+        private static final long serialVersionUID = 1L;
+
         private PrimitiveLiteralNode(final long token, final int finish, final T value) {
             super(token, finish, value);
         }
@@ -300,6 +309,7 @@
 
     @Immutable
     private static final class BooleanLiteralNode extends PrimitiveLiteralNode<Boolean> {
+        private static final long serialVersionUID = 1L;
 
         private BooleanLiteralNode(final long token, final int finish, final boolean value) {
             super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
@@ -352,6 +362,7 @@
 
     @Immutable
     private static final class NumberLiteralNode extends PrimitiveLiteralNode<Number> {
+        private static final long serialVersionUID = 1L;
 
         private final Type type = numberGetType(value);
 
@@ -414,6 +425,8 @@
     }
 
     private static class UndefinedLiteralNode extends PrimitiveLiteralNode<Undefined> {
+        private static final long serialVersionUID = 1L;
+
         private UndefinedLiteralNode(final long token, final int finish) {
             super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
         }
@@ -450,6 +463,8 @@
 
     @Immutable
     private static class StringLiteralNode extends PrimitiveLiteralNode<String> {
+        private static final long serialVersionUID = 1L;
+
         private StringLiteralNode(final long token, final int finish, final String value) {
             super(Token.recast(token, TokenType.STRING), finish, value);
         }
@@ -493,6 +508,8 @@
 
     @Immutable
     private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
+        private static final long serialVersionUID = 1L;
+
         private LexerTokenLiteralNode(final long token, final int finish, final LexerToken value) {
             super(Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
         }
@@ -556,6 +573,7 @@
     }
 
     private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
+        private static final long serialVersionUID = 1L;
 
         private NullLiteralNode(final long token, final int finish) {
             super(Token.recast(token, TokenType.OBJECT), finish, null);
@@ -586,6 +604,7 @@
      */
     @Immutable
     public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode {
+        private static final long serialVersionUID = 1L;
 
         /** Array element type. */
         private final Type elementType;
@@ -603,7 +622,9 @@
          * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
          * be split if they are too large, for bytecode generation reasons
          */
-        public static final class ArrayUnit implements CompileUnitHolder {
+        public static final class ArrayUnit implements CompileUnitHolder, Serializable {
+            private static final long serialVersionUID = 1L;
+
             /** Compile unit associated with the postsets range. */
             private final CompileUnit compileUnit;
 
@@ -651,13 +672,13 @@
         private static final class ArrayLiteralInitializer {
 
             static ArrayLiteralNode initialize(final ArrayLiteralNode node) {
-                final Type elementType = computeElementType(node.value, node.elementType);
+                final Type elementType = computeElementType(node.value);
                 final int[] postsets = computePostsets(node.value);
                 final Object presets = computePresets(node.value, elementType, postsets);
                 return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units);
             }
 
-            private static Type computeElementType(final Expression[] value, final Type elementType) {
+            private static Type computeElementType(final Expression[] value) {
                 Type widestElementType = Type.INT;
 
                 for (final Expression elem : value) {
@@ -981,10 +1002,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 +1014,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/LoopNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/LoopNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -34,6 +34,8 @@
  * A loop node, for example a while node, do while node or for node
  */
 public abstract class LoopNode extends BreakableStatement {
+    private static final long serialVersionUID = 1L;
+
     /** loop continue label. */
     protected final Label continueLabel;
 
--- a/src/jdk/nashorn/internal/ir/Node.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/Node.java	Tue Nov 04 17:21:00 2014 +0000
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -34,7 +35,18 @@
 /**
  * Nodes are used to compose Abstract Syntax Trees.
  */
-public abstract class Node implements Cloneable {
+public abstract class Node implements Cloneable, Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** Constant used for synthetic AST nodes that have no line number. */
+    public static final int NO_LINE_NUMBER = -1;
+
+    /** Constant used for synthetic AST nodes that have no token. */
+    public static final long NO_TOKEN = 0L;
+
+    /** Constant used for synthetic AST nodes that have no finish. */
+    public static final int NO_FINISH = 0;
+
     /** Start of source range. */
     protected final int start;
 
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -37,6 +37,7 @@
  */
 @Immutable
 public final class ObjectNode extends Expression {
+    private static final long serialVersionUID = 1L;
 
     /** Literal elements. */
     private final List<PropertyNode> elements;
--- a/src/jdk/nashorn/internal/ir/PropertyNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/PropertyNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,7 @@
  */
 @Immutable
 public final class PropertyNode extends Node {
+    private static final long serialVersionUID = 1L;
 
     /** Property key. */
     private final PropertyKey key;
--- a/src/jdk/nashorn/internal/ir/ReturnNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/ReturnNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -36,6 +36,8 @@
  */
 @Immutable
 public class ReturnNode extends Statement {
+    private static final long serialVersionUID = 1L;
+
     /** Optional expression. */
     private final Expression expression;
 
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -42,6 +42,7 @@
  */
 @Immutable
 public class RuntimeNode extends Expression implements Optimistic {
+    private static final long serialVersionUID = 1L;
 
     /**
      * Request enum used for meta-information about the runtime request
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/SetSplitState.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 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.ir;
+
+import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.Scope;
+
+/**
+ * Synthetic AST node that represents loading of the scope object and invocation of the {@link Scope#setSplitState(int)}
+ * method on it. It has no JavaScript source representation and only occurs in synthetic functions created by
+ * the split-into-functions transformation.
+ */
+public final class SetSplitState extends Statement {
+    private static final long serialVersionUID = 1L;
+
+    private final int state;
+
+    /**
+     * Creates a new split state setter
+     * @param state the state to set
+     * @param lineNumber the line number where it is inserted
+     */
+    public SetSplitState(final int state, final int lineNumber) {
+        super(lineNumber, NO_TOKEN, NO_FINISH);
+        this.state = state;
+    }
+
+    /**
+     * Returns the state this setter sets.
+     * @return the state this setter sets.
+     */
+    public int getState() {
+        return state;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return visitor.enterSetSplitState(this) ? visitor.leaveSetSplitState(this) : this;
+    }
+
+    @Override
+    public void toString(final StringBuilder sb, final boolean printType) {
+        sb.append(CompilerConstants.SCOPE.symbolName()).append('.').append(Scope.SET_SPLIT_STATE.name())
+        .append('(').append(state).append(");");
+    }
+}
--- a/src/jdk/nashorn/internal/ir/SplitNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/SplitNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -25,13 +25,10 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
 import jdk.nashorn.internal.codegen.CompileUnit;
-import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
@@ -39,7 +36,9 @@
  * Node indicating code is split across classes.
  */
 @Immutable
-public class SplitNode extends LexicalContextStatement implements Labels, CompileUnitHolder {
+public class SplitNode extends LexicalContextStatement implements CompileUnitHolder {
+    private static final long serialVersionUID = 1L;
+
     /** Split node method name. */
     private final String name;
 
@@ -49,8 +48,6 @@
     /** Body of split code. */
     private final Block body;
 
-    private Map<Label, JoinPredecessor> jumps;
-
     /**
      * Constructor
      *
@@ -65,19 +62,18 @@
         this.compileUnit = compileUnit;
     }
 
-    private SplitNode(final SplitNode splitNode, final Block body, final CompileUnit compileUnit, final Map<Label, JoinPredecessor> jumps) {
+    private SplitNode(final SplitNode splitNode, final Block body, final CompileUnit compileUnit) {
         super(splitNode);
         this.name        = splitNode.name;
         this.body        = body;
         this.compileUnit = compileUnit;
-        this.jumps       = jumps;
     }
 
     /**
      * Get the body for this split node - i.e. the actual code it encloses
      * @return body for split node
      */
-    public Node getBody() {
+    public Block getBody() {
         return body;
     }
 
@@ -85,7 +81,7 @@
         if (this.body == body) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit, jumps));
+        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit));
     }
 
     @Override
@@ -131,33 +127,12 @@
         if (this.compileUnit == compileUnit) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit, jumps));
+        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body, compileUnit));
     }
 
-    /**
-     * Adds a jump that crosses this split node's boundary (it originates within the split node, and goes to a target
-     * outside of it).
-     * @param jumpOrigin the join predecessor that's the origin of the jump
-     * @param targetLabel the label that's the target of the jump.
-     */
-    public void addJump(final JoinPredecessor jumpOrigin, final Label targetLabel) {
-        if (jumps == null) {
-            jumps = new HashMap<>();
-        }
-        jumps.put(targetLabel, jumpOrigin);
-    }
-
-    /**
-     * Returns the jump origin within this split node for a target.
-     * @param targetLabel the target for which a jump origin is sought.
-     * @return the jump origin, or null.
-     */
-    public JoinPredecessor getJumpOrigin(final Label targetLabel) {
-        return jumps == null ? null : jumps.get(targetLabel);
-    }
-
-    @Override
-    public List<Label> getLabels() {
-        return Collections.unmodifiableList(new ArrayList<>(jumps.keySet()));
+    private void writeObject(final ObjectOutputStream out) throws IOException {
+        // We are only serializing the AST after we run SplitIntoFunctions; no SplitNodes can remain for the
+        // serialization.
+        throw new NotSerializableException(getClass().getName());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/SplitReturn.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 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.ir;
+
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * Synthetic AST node that represents return from a split fragment of a split function for control flow reasons (break
+ * or continue into a target outside the current fragment). It has no JavaScript source representation and only occurs
+ * in synthetic functions created by the split-into-functions transformation. It is different from a return node in
+ * that the return value is irrelevant, and doesn't affect the function's return type calculation.
+ */
+public final class SplitReturn extends Statement {
+    private static final long serialVersionUID = 1L;
+
+    /** The sole instance of this AST node. */
+    public static final SplitReturn INSTANCE = new SplitReturn();
+
+    private SplitReturn() {
+        super(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH);
+    }
+
+    @Override
+    public boolean isTerminal() {
+        return true;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return visitor.enterSplitReturn(this) ? visitor.leaveSplitReturn(this) : this;
+    }
+
+    @Override
+    public void toString(StringBuilder sb, boolean printType) {
+        sb.append(":splitreturn;");
+    }
+
+    private Object readResolve() {
+        return INSTANCE;
+    }
+}
--- a/src/jdk/nashorn/internal/ir/Statement.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/Statement.java	Tue Nov 04 17:21:00 2014 +0000
@@ -31,6 +31,7 @@
  * location information is the Statement
  */
 public abstract class Statement extends Node implements Terminal {
+    private static final long serialVersionUID = 1L;
 
     private final int lineNumber;
 
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -37,6 +37,8 @@
  */
 @Immutable
 public final class SwitchNode extends BreakableStatement {
+    private static final long serialVersionUID = 1L;
+
     /** Switch expression. */
     private final Expression expression;
 
--- a/src/jdk/nashorn/internal/ir/Symbol.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/Symbol.java	Tue Nov 04 17:21:00 2014 +0000
@@ -97,7 +97,7 @@
     private int firstSlot = -1;
 
     /** Field number in scope or property; array index in varargs when not using arguments object. */
-    private int fieldIndex;
+    private int fieldIndex = -1;
 
     /** Number of times this symbol is used in code */
     private int useCount;
@@ -135,28 +135,15 @@
      *
      * @param name  name of symbol
      * @param flags symbol flags
-     * @param slot  bytecode slot for this symbol
      */
-    protected Symbol(final String name, final int flags, final int slot) {
+    public Symbol(final String name, final int flags) {
         this.name       = name;
         this.flags      = flags;
-        this.firstSlot  = slot;
-        this.fieldIndex = -1;
         if(shouldTrace()) {
             trace("CREATE SYMBOL " + name);
         }
     }
 
-    /**
-     * Constructor
-     *
-     * @param name  name of symbol
-     * @param flags symbol flags
-     */
-    public Symbol(final String name, final int flags) {
-        this(name, flags, -1);
-    }
-
     private static String align(final String string, final int max) {
         final StringBuilder sb = new StringBuilder();
         sb.append(string.substring(0, Math.min(string.length(), max)));
@@ -448,14 +435,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/ir/TernaryNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -37,6 +37,8 @@
  */
 @Immutable
 public final class TernaryNode extends Expression {
+    private static final long serialVersionUID = 1L;
+
     private final Expression test;
     private final JoinPredecessorExpression trueExpr;
     private final JoinPredecessorExpression falseExpr;
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/ThrowNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class ThrowNode extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Exception expression. */
     private final Expression expression;
 
--- a/src/jdk/nashorn/internal/ir/TryNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/TryNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -36,6 +36,8 @@
  */
 @Immutable
 public final class TryNode extends Statement implements JoinPredecessor {
+    private static final long serialVersionUID = 1L;
+
     /** Try statements. */
     private final Block body;
 
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -46,6 +46,8 @@
  */
 @Immutable
 public final class UnaryNode extends Expression implements Assignment<Expression>, Optimistic {
+    private static final long serialVersionUID = 1L;
+
     /** Right hand side argument. */
     private final Expression expression;
 
--- a/src/jdk/nashorn/internal/ir/VarNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/VarNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -34,6 +34,8 @@
  */
 @Immutable
 public final class VarNode extends Statement implements Assignment<IdentNode> {
+    private static final long serialVersionUID = 1L;
+
     /** Var name. */
     private final IdentNode name;
 
@@ -272,4 +274,12 @@
     public boolean isFunctionDeclaration() {
         return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
     }
+
+    /**
+     * Returns true if this is an anonymous function declaration.
+     * @return true if this is an anonymous function declaration.
+     */
+    public boolean isAnonymousFunctionDeclaration() {
+        return isFunctionDeclaration() && ((FunctionNode)init).isAnonymous();
+    }
 }
--- a/src/jdk/nashorn/internal/ir/WhileNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -34,6 +34,8 @@
  */
 @Immutable
 public final class WhileNode extends LoopNode {
+    private static final long serialVersionUID = 1L;
+
 
     /** is this a do while node ? */
     private final boolean isDoWhile;
--- a/src/jdk/nashorn/internal/ir/WithNode.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/WithNode.java	Tue Nov 04 17:21:00 2014 +0000
@@ -33,6 +33,8 @@
  */
 @Immutable
 public final class WithNode extends LexicalContextStatement {
+    private static final long serialVersionUID = 1L;
+
    /** This expression. */
     private final Expression expression;
 
--- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue Nov 04 17:21:00 2014 +0000
@@ -38,6 +38,7 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
@@ -50,7 +51,9 @@
 import jdk.nashorn.internal.ir.PropertyNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
+import jdk.nashorn.internal.ir.SetSplitState;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.SplitReturn;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.ThrowNode;
@@ -390,6 +393,26 @@
     }
 
     /**
+     * Callback for entering a {@link GetSplitState}.
+     *
+     * @param  getSplitState the get split state expression
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterGetSplitState(final GetSplitState getSplitState) {
+        return enterDefault(getSplitState);
+    }
+
+    /**
+     * Callback for leaving a {@link GetSplitState}.
+     *
+     * @param  getSplitState the get split state expression
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveGetSplitState(final GetSplitState getSplitState) {
+        return leaveDefault(getSplitState);
+    }
+
+    /**
      * Callback for entering an IdentNode
      *
      * @param  identNode the node
@@ -570,6 +593,26 @@
     }
 
     /**
+     * Callback for entering a {@link SetSplitState}.
+     *
+     * @param  setSplitState the set split state statement
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterSetSplitState(final SetSplitState setSplitState) {
+        return enterDefault(setSplitState);
+    }
+
+    /**
+     * Callback for leaving a {@link SetSplitState}.
+     *
+     * @param  setSplitState the set split state expression
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveSetSplitState(final SetSplitState setSplitState) {
+        return leaveDefault(setSplitState);
+    }
+
+    /**
      * Callback for entering a SplitNode
      *
      * @param  splitNode the node
@@ -590,6 +633,26 @@
     }
 
     /**
+     * Callback for entering a SplitReturn
+     *
+     * @param  splitReturn the node
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterSplitReturn(final SplitReturn splitReturn) {
+        return enterDefault(splitReturn);
+    }
+
+    /**
+     * Callback for leaving a SplitReturn
+     *
+     * @param  splitReturn the node
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveSplitReturn(final SplitReturn splitReturn) {
+        return leaveDefault(splitReturn);
+    }
+
+    /**
      * Callback for entering a SwitchNode
      *
      * @param  switchNode the node
--- a/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Tue Nov 04 17:21:00 2014 +0000
@@ -48,7 +48,7 @@
 /**
  * This class is abstraction for all method handle, switchpoint and method type
  * operations. This enables the functionality interface to be subclassed and
- * intrumensted, as it has been proven vital to keep the number of method
+ * instrumented, as it has been proven vital to keep the number of method
  * handles in the system down.
  *
  * All operations of the above type should go through this class, and not
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/ArrayBufferView.java	Tue Nov 04 17:21:00 2014 +0000
@@ -45,7 +45,7 @@
 import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
 
 @ScriptClass("ArrayBufferView")
-abstract class ArrayBufferView extends ScriptObject {
+public abstract class ArrayBufferView extends ScriptObject {
     private final NativeArrayBuffer buffer;
     private final int byteOffset;
 
--- a/src/jdk/nashorn/internal/objects/Global.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/Global.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeDataView.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -85,6 +85,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return double.class;
+        }
+
+        @Override
         protected MethodHandle getGetElem() {
             return GET_ELEM;
         }
@@ -137,6 +142,11 @@
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getDouble(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -94,6 +94,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return double.class;
+        }
+
         private double getElem(final int index) {
             try {
                 return nb.get(index);
@@ -137,6 +142,11 @@
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getDouble(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -95,6 +95,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
@@ -120,16 +125,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -113,21 +113,41 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -93,6 +93,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index);
@@ -118,16 +123,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/NativeJava.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeJava.java	Tue Nov 04 17:21:00 2014 +0000
@@ -90,7 +90,11 @@
      */
     @Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
     public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
-        return ScriptUtils.makeSynchronizedFunction(func, obj);
+        if (func instanceof ScriptFunction) {
+            return ((ScriptFunction)func).makeSynchronizedFunction(obj);
+        }
+
+        throw typeError("not.a.function", ScriptRuntime.safeToString(func));
     }
 
     /**
--- a/src/jdk/nashorn/internal/objects/NativeJavaImporter.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeJavaImporter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
 
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -36,9 +37,11 @@
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.NativeJavaPackage;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
 
 /**
@@ -94,33 +97,30 @@
     }
 
     /**
-     * "No such property" call placeholder.
-     *
-     * This can never be called as we override {@link ScriptObject#noSuchProperty}. We do declare it here as it's a signal
-     * to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a {@code noSuchProperty} on this object.
+     * "No such property" handler.
      *
      * @param self self reference
      * @param name property name
-     * @return never returns
+     * @return value of the missing property
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object __noSuchProperty__(final Object self, final Object name) {
-        throw new AssertionError("__noSuchProperty__ placeholder called");
+        if (! (self instanceof NativeJavaImporter)) {
+            throw typeError("not.a.java.importer", ScriptRuntime.safeToString(self));
+        }
+        return ((NativeJavaImporter)self).createProperty(JSType.toString(name));
     }
 
     /**
-     * "No such method call" placeholder
-     *
-     * This can never be called as we override {@link ScriptObject#noSuchMethod}. We do declare it here as it's a signal
-     * to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a noSuchProperty on this object.
+     * "No such method call" handler
      *
      * @param self self reference
      * @param args arguments to method
-     * @return never returns
+     * @return never returns always throw TypeError
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object __noSuchMethod__(final Object self, final Object... args) {
-        throw new AssertionError("__noSuchMethod__ placeholder called");
+       throw typeError("not.a.function", ScriptRuntime.safeToString(args[0]));
     }
 
     @Override
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeString.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -119,21 +119,41 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -128,6 +128,11 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return long.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return (int)getLong(index);
         }
@@ -138,11 +143,21 @@
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getLong(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getLong(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getLong(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java	Tue Nov 04 17:21:00 2014 +0000
@@ -119,21 +119,41 @@
         }
 
         @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
+        @Override
         public int getInt(final int index) {
             return getElem(index);
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java	Tue Nov 04 17:21:00 2014 +0000
@@ -98,6 +98,11 @@
             return SET_ELEM;
         }
 
+        @Override
+        public Class<?> getElementType() {
+            return int.class;
+        }
+
         private int getElem(final int index) {
             try {
                 return nb.get(index) & 0xff;
@@ -154,16 +159,31 @@
         }
 
         @Override
+        public int getIntOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public long getLong(final int index) {
             return getInt(index);
         }
 
         @Override
+        public long getLongOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public double getDouble(final int index) {
             return getInt(index);
         }
 
         @Override
+        public double getDoubleOptimistic(final int index, final int programPoint) {
+            return getElem(index);
+        }
+
+        @Override
         public Object getObject(final int index) {
             return getInt(index);
         }
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ /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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/parser/Lexer.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/parser/Lexer.java	Tue Nov 04 17:21:00 2014 +0000
@@ -46,6 +46,7 @@
 import static jdk.nashorn.internal.parser.TokenType.STRING;
 import static jdk.nashorn.internal.parser.TokenType.XML;
 
+import java.io.Serializable;
 import jdk.nashorn.internal.runtime.ECMAErrors;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -1717,7 +1718,9 @@
      * Helper class for Lexer tokens, e.g XML or RegExp tokens.
      * This is the abstract superclass
      */
-    public static abstract class LexerToken {
+    public static abstract class LexerToken implements Serializable {
+        private static final long serialVersionUID = 1L;
+
         private final String expression;
 
         /**
@@ -1741,6 +1744,8 @@
      * Temporary container for regular expressions.
      */
     public static class RegexToken extends LexerToken {
+        private static final long serialVersionUID = 1L;
+
         /** Options. */
         private final String options;
 
@@ -1773,6 +1778,7 @@
      * Temporary container for XML expression.
      */
     public static class XMLToken extends LexerToken {
+        private static final long serialVersionUID = 1L;
 
         /**
          * Constructor.
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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 ";
                     }
                 });
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/AstDeserializer.java	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,47 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.zip.InflaterInputStream;
+import jdk.nashorn.internal.ir.FunctionNode;
+
+/**
+ * This static utility class performs deserialization of FunctionNode ASTs from a byte array.
+ * The format is a standard Java serialization stream, deflated.
+ */
+final class AstDeserializer {
+    static FunctionNode deserialize(final byte[] serializedAst) {
+        try {
+            return (FunctionNode)new ObjectInputStream(new InflaterInputStream(new ByteArrayInputStream(
+                    serializedAst))).readObject();
+        } catch (final ClassNotFoundException | IOException e) {
+            // This is internal, can't happen
+            throw new AssertionError("Unexpected exception deserializing function", e);
+        }
+    }
+}
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/CodeStore.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java	Tue Nov 04 17:21:00 2014 +0000
@@ -27,18 +27,20 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
+
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 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 +48,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 +66,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 +80,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 +121,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 +129,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 +178,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 +352,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 +479,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 +510,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 +521,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 +530,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 +752,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));
         }
     }
 
@@ -704,6 +787,7 @@
         // isn't available, we'll use the old one bound into the call site.
         final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
         FunctionNode fn = effectiveOptInfo.reparse();
+        final boolean serialized = effectiveOptInfo.isSerialized();
         final Compiler compiler = effectiveOptInfo.getCompiler(fn, callSiteType, re); //set to non rest-of
 
         if (!shouldRecompile) {
@@ -711,17 +795,17 @@
             // recompiled a deoptimized version for an inner invocation.
             // We still need to do the rest of from the beginning
             logRecompile("Rest-of compilation [STANDALONE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
-            return restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
+            return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
         }
 
         logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
-        fn = compiler.compile(fn, CompilationPhases.COMPILE_UPTO_BYTECODE);
+        fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
         log.info("Reusable IR generated");
 
         // compile the rest of the function, and install it
         log.info("Generating and installing bytecode from reusable IR...");
         logRecompile("Rest-of compilation [CODE PIPELINE REUSE] ", fn, callSiteType, effectiveOptInfo.invalidatedProgramPoints);
-        final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.COMPILE_FROM_BYTECODE);
+        final FunctionNode normalFn = compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL);
 
         if (effectiveOptInfo.data.usePersistentCodeCache()) {
             final RecompilableScriptFunctionData data = effectiveOptInfo.data;
@@ -732,8 +816,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();
@@ -749,7 +831,7 @@
         constructor = null; // Will be regenerated when needed
 
         log.info("Done: ", invoker);
-        final MethodHandle restOf = restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.COMPILE_FROM_BYTECODE_RESTOF), canBeDeoptimized);
+        final MethodHandle restOf = restOfHandle(effectiveOptInfo, compiler.compile(fn, CompilationPhases.GENERATE_BYTECODE_AND_INSTALL_RESTOF), canBeDeoptimized);
 
         // Note that we only adjust the switch point after we set the invoker/constructor. This is important.
         if (canBeDeoptimized) {
@@ -841,6 +923,10 @@
         FunctionNode reparse() {
             return data.reparse();
         }
+
+        boolean isSerialized() {
+            return data.isSerialized();
+        }
     }
 
     @SuppressWarnings("unused")
--- a/src/jdk/nashorn/internal/runtime/Context.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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;
@@ -140,6 +150,13 @@
         private final Context      context;
         private final ScriptLoader loader;
         private final CodeSource   codeSource;
+        private int usageCount = 0;
+        private int bytesDefined = 0;
+
+        // We reuse this installer for 10 compilations or 200000 defined bytes. Usually the first condition
+        // will occur much earlier, the second is a safety measure for very large scripts/functions.
+        private final static int MAX_USAGES = 10;
+        private final static int MAX_BYTES_DEFINED = 200_000;
 
         private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) {
             this.context    = context;
@@ -148,7 +165,7 @@
         }
 
         /**
-         * Return the context for this installer
+         * Return the script environment for this installer
          * @return ScriptEnvironment
          */
         @Override
@@ -158,6 +175,8 @@
 
         @Override
         public Class<?> install(final String className, final byte[] bytecode) {
+            usageCount++;
+            bytesDefined += bytecode.length;
             final String   binaryName = Compiler.binaryName(className);
             return loader.installClass(binaryName, bytecode, codeSource);
         }
@@ -212,6 +231,24 @@
             }
             return null;
         }
+
+        @Override
+        public CodeInstaller<ScriptEnvironment> withNewLoader() {
+            // Reuse this installer if we're within our limits.
+            if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
+                return this;
+            }
+            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 +1150,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 +1239,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 +1259,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 +1411,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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/Debug.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java	Tue Nov 04 17:21:00 2014 +0000
@@ -31,7 +31,6 @@
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
-
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.SwitchPoint;
@@ -328,7 +327,9 @@
         }
 
         if (!acc.mayRetry()) {
-            log.info("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            if (log.isEnabled()) {
+                log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            }
             return null;
         }
 
@@ -358,8 +359,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");
         }
@@ -400,7 +405,9 @@
         }
 
         if (acc.hasBeenInvalidated() || acc.guardFailed()) {
-            log.fine("*** GET: Giving up on " + quote(name) + " - retry count has exceeded");
+            if (log.isEnabled()) {
+                log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
+            }
             return null;
         }
 
--- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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 Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/Property.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue Nov 04 17:21:00 2014 +0000
@@ -950,7 +950,7 @@
 
         @Override
         public void remove() {
-            throw new UnsupportedOperationException();
+            throw new UnsupportedOperationException("remove");
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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;
@@ -42,6 +43,7 @@
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.FunctionSignature;
+import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
 import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
 import jdk.nashorn.internal.codegen.TypeMap;
@@ -78,6 +80,9 @@
     /** Source from which FunctionNode was parsed. */
     private transient Source source;
 
+    /** Serialized, compressed form of the AST. Used by split functions as they can't be reparsed from source. */
+    private final byte[] serializedAst;
+
     /** Token of this function within the source. */
     private final long token;
 
@@ -126,6 +131,7 @@
      * @param nestedFunctions     nested function map
      * @param externalScopeDepths external scope depths
      * @param internalSymbols     internal symbols to method, defined in its scope
+     * @param serializedAst       a serialized AST representation. Normally only used for split functions.
      */
     public RecompilableScriptFunctionData(
         final FunctionNode functionNode,
@@ -133,7 +139,8 @@
         final AllocatorDescriptor allocationDescriptor,
         final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
         final Map<String, Integer> externalScopeDepths,
-        final Set<String> internalSymbols) {
+        final Set<String> internalSymbols,
+        final byte[] serializedAst) {
 
         super(functionName(functionNode),
               Math.min(functionNode.getParameters().size(), MAX_ARITY),
@@ -157,6 +164,7 @@
             nfn.setParent(this);
         }
 
+        this.serializedAst = serializedAst;
         createLogger();
     }
 
@@ -211,10 +219,7 @@
      */
     public int getExternalSymbolDepth(final String symbolName) {
         final Integer depth = externalScopeDepths.get(symbolName);
-        if (depth == null) {
-            return -1;
-        }
-        return depth;
+        return depth == null ? -1 : depth;
     }
 
     /**
@@ -268,7 +273,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();
         }
@@ -353,8 +358,15 @@
         return allocationStrategy.allocate(map);
     }
 
+    boolean isSerialized() {
+        return serializedAst != null;
+    }
+
     FunctionNode reparse() {
-        // NOTE: If we aren't recompiling the top-level program, we decrease functionNodeId 'cause we'll have a synthetic program node
+        if (isSerialized()) {
+            return deserialize();
+        }
+
         final int descPosition = Token.descPosition(token);
         final Context context = Context.getContextTrusted();
         final Parser parser = new Parser(
@@ -362,8 +374,10 @@
             source,
             new Context.ThrowErrorManager(),
             isStrict(),
+            // source starts at line 0, so even though lineNumber is the correct declaration line, back off
+            // one to make it exclusive
             lineNumber - 1,
-            context.getLogger(Parser.class)); // source starts at line 0, so even though lineNumber is the correct declaration line, back off one to make it exclusive
+            context.getLogger(Parser.class));
 
         if (getFunctionFlag(FunctionNode.IS_ANONYMOUS)) {
             parser.setFunctionName(functionName);
@@ -377,6 +391,17 @@
         return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
     }
 
+    private FunctionNode deserialize() {
+        final ScriptEnvironment env = installer.getOwner();
+        final Timing timing = env._timing;
+        final long t1 = System.nanoTime();
+        try {
+            return AstDeserializer.deserialize(serializedAst).initializeDeserialized(source, new Namespace(env.getNamespace()));
+        } finally {
+            timing.accumulateTime("'Deserialize'", System.nanoTime() - t1);
+        }
+    }
+
     private boolean getFunctionFlag(final int flag) {
         return (functionFlags & flag) != 0;
     }
@@ -407,6 +432,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 +453,7 @@
         return new Compiler(
                 context,
                 context.getEnv(),
-                installer,
+                getInstallerForNewCode(),
                 functionNode.getSource(),  // source
                 context.getErrorManager(),
                 isStrict() | functionNode.isStrict(), // is strict
@@ -454,7 +490,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,17 +499,19 @@
             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);
             }
         }
 
         final FunctionNode fn = reparse();
         final Compiler compiler = getCompiler(fn, actualCallSiteType, runtimeScope);
-        final FunctionNode compiledFn = compiler.compile(fn, CompilationPhases.COMPILE_ALL);
+        final FunctionNode compiledFn = compiler.compile(fn,
+                isSerialized() ? CompilationPhases.COMPILE_ALL_SERIALIZED : CompilationPhases.COMPILE_ALL);
 
         if (persist && !compiledFn.getFlag(FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION)) {
             compiler.persistClassInfo(cacheKey, compiledFn);
@@ -481,15 +519,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 +531,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 +564,7 @@
             }
         }
 
-        installer.initialize(installedClasses.values(), source, constants);
+        newInstaller.initialize(installedClasses.values(), source, constants);
         initializer.setCode(installedClasses.get(initializer.getClassName()));
         return initializer;
     }
@@ -588,15 +629,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(functionName), " 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.
@@ -656,10 +701,26 @@
         return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
     }
 
+    /**
+     * Returns the return type of a function specialization for particular parameter types.<br>
+     * <b>Be aware that the way this is implemented, it forces full materialization (compilation and installation) of
+     * code for that specialization.</b>
+     * @param callSiteType the parameter types at the call site. It must include the mandatory {@code callee} and
+     * {@code this} parameters, so it needs to start with at least {@code ScriptFunction.class} and
+     * {@code Object.class} class. Since the return type of the function is calculated from the code itself, it is
+     * irrelevant and should be set to {@code Object.class}.
+     * @param runtimeScope a current runtime scope. Can be null but when it's present it will be used as a source of
+     * current runtime values that can improve the compiler's type speculations (and thus reduce the need for later
+     * recompilations) if the specialization is not already present and thus needs to be freshly compiled.
+     * @return the return type of the function specialization.
+     */
+    public Class<?> getReturnType(final MethodType callSiteType, final ScriptObject runtimeScope) {
+        return getBest(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS).type().returnType();
+    }
 
     @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 +784,10 @@
         return functionNodeId;
     }
 
+    /**
+     * Get the source for the script
+     * @return source
+     */
     public Source getSource() {
         return source;
     }
@@ -777,6 +842,26 @@
         return true;
     }
 
+    /**
+     * Restores the {@link #getFunctionFlags()} flags to a function node. During on-demand compilation, we might need
+     * to restore flags to a function node that was otherwise not subjected to a full compile pipeline (e.g. its parse
+     * was skipped, or it's a nested function of a deserialized function.
+     * @param lc current lexical context
+     * @param fn the function node to restore flags onto
+     * @return the transformed function node
+     */
+    public FunctionNode restoreFlags(final LexicalContext lc, final FunctionNode fn) {
+        assert fn.getId() == functionNodeId;
+        FunctionNode newFn = fn.setFlags(lc, functionFlags);
+        // This compensates for missing markEval() in case the function contains an inner function
+        // that contains eval(), that now we didn't discover since we skipped the inner function.
+        if (newFn.hasNestedEval()) {
+            assert newFn.hasScopeBlock();
+            newFn = newFn.setBody(lc, newFn.getBody().setNeedsScope(null));
+        }
+        return newFn;
+    }
+
     private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
         in.defaultReadObject();
         createLogger();
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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 Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/StoredScript.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/WithObject.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/WithObject.java	Tue Nov 04 17:21:00 2014 +0000
@@ -210,6 +210,19 @@
     }
 
     @Override
+    protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+        FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
+        if (find != null) {
+            final Object func = find.getObjectValue();
+            if (func instanceof ScriptFunction) {
+                return ScriptRuntime.apply((ScriptFunction)func, expression, name);
+            }
+        }
+
+        return getProto().invokeNoSuchProperty(name, programPoint);
+    }
+
+    @Override
     public void setSplitState(final int state) {
         getNonWithParent().setSplitState(state);
     }
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -38,6 +38,7 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -77,11 +78,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 +117,17 @@
     }
 
     /**
+     * Returns the type used to store an element in this array
+     * @return element type
+     */
+    public abstract Class<?> getElementType();
+
+    @Override
+    public Type getOptimisticType() {
+        return Type.typeFor(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 +187,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 +276,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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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() {
@@ -66,9 +66,9 @@
     public Object[] asObjectArray() {
         final Object[] value = super.asObjectArray();
 
-        if (lo <= Integer.MAX_VALUE) {
-            final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
-            for (int i = (int)lo; i <= intHi; i++) {
+        if (lo < Integer.MAX_VALUE) {
+            final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
+            for (int i = (int)lo; i < end; i++) {
                 value[i] = ScriptRuntime.UNDEFINED;
             }
         }
@@ -81,9 +81,9 @@
         final Object value = super.asArrayOfType(componentType);
         final Object undefValue = convertUndefinedValue(componentType);
 
-        if (lo <= Integer.MAX_VALUE) {
-            final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
-            for (int i = (int)lo; i <= intHi; i++) {
+        if (lo < Integer.MAX_VALUE) {
+            final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
+            for (int i = (int)lo; i < end; i++) {
                 Array.set(value, i, undefValue);
             }
         }
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -30,7 +30,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -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(true);
+    }
+
     @SuppressWarnings("unused")
     private int getElem(final int index) {
         if (has(index)) {
@@ -96,25 +105,20 @@
 
     @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(final boolean trim) {
         assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[array.length];
+        final Object[] oarray = new Object[trim ? (int)length : array.length];
 
         for (int index = 0; index < length; index++) {
             oarray[index] = Integer.valueOf(array[index]);
@@ -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(false), (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;
         }
 
@@ -241,11 +257,6 @@
     }
 
     @Override
-    public Type getOptimisticType() {
-        return Type.INT;
-    }
-
-    @Override
     public int getInt(final int index) {
         return array[index];
     }
@@ -282,7 +293,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -297,11 +308,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 +322,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 +330,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 +366,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 Nov 04 17:21:00 2014 +0000
@@ -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 Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -31,7 +31,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -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,18 +56,23 @@
     }
 
     @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(true);
     }
 
-    private static Object[] toObjectArray(final long[] array, final int length) {
+    private Object[] toObjectArray(final boolean trim) {
         assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[array.length];
+        final Object[] oarray = new Object[trim ? (int)length : array.length];
 
         for (int index = 0; index < length; index++) {
             oarray[index] = Long.valueOf(array[index]);
@@ -80,12 +84,12 @@
     @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);
     }
 
-    private static double[] toDoubleArray(final long[] array, final int length) {
+    private double[] toDoubleArray() {
         assert length <= array.length : "length exceeds internal array size";
         final double[] darray = new double[array.length];
 
@@ -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(toDoubleArray(), len);
         }
-        return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length);
+        return new ObjectArrayData(toObjectArray(false), 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,17 +180,12 @@
     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);
     }
 
-    @Override
-    public Type getOptimisticType() {
-        return Type.LONG;
-    }
-
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle();
 
@@ -252,7 +251,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -267,11 +266,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 +280,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 +323,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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -32,13 +32,12 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
-import jdk.nashorn.internal.codegen.types.Type;
 
 /**
  * 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,18 +55,23 @@
     }
 
     @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(true);
     }
 
-    private static Object[] toObjectArray(final double[] array, final int length) {
+    private Object[] toObjectArray(final boolean trim) {
         assert length <= array.length : "length exceeds internal array size";
-        final Object[] oarray = new Object[array.length];
+        final Object[] oarray = new Object[trim ? (int)length : array.length];
 
         for (int index = 0; index < length; index++) {
             oarray[index] = Double.valueOf(array[index]);
@@ -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(toObjectArray(false), 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,29 +148,24 @@
     @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;
     }
 
-    @Override
-    public Type getOptimisticType() {
-        return Type.NUMBER;
-    }
-
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "getElem", double.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), NumberArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
 
@@ -227,7 +226,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -242,11 +241,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 +254,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 +297,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 Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -30,7 +30,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.util.Arrays;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
@@ -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;
     }
 
@@ -151,15 +155,11 @@
 
     @Override
     public ArrayData setEmpty(final long lo, final long hi) {
-        Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
+        // hi parameter is inclusive, but Arrays.fill toIndex parameter is exclusive
+        Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi + 1, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
         return this;
     }
 
-    @Override
-    public Type getOptimisticType() {
-        return Type.OBJECT;
-    }
-
     private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle();
     private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle();
 
@@ -216,7 +216,7 @@
 
     @Override
     public boolean has(final int index) {
-        return 0 <= index && index < length();
+        return 0 <= index && index < length;
     }
 
     @Override
@@ -232,12 +232,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 +282,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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -53,32 +53,32 @@
 
     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();
-            if (key <= Integer.MAX_VALUE) {
+            if (key < Integer.MAX_VALUE) {
                 objArray[(int)key] = entry.getValue();
             } else {
                 break; // ascending key order
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/JavaAdapterBytecodeGenerator.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Tue Nov 04 17:21:00 2014 +0000
@@ -152,6 +152,7 @@
     static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
     static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
 
+    private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
     private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
     private static final Type STRING_TYPE = Type.getType(String.class);
     private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
@@ -536,8 +537,8 @@
         final int argLen = originalArgTypes.length;
         final Type[] newArgTypes = new Type[argLen + 1];
 
-        // Insert ScriptFunction|Object as the last argument to the constructor
-        final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE;
+        // Insert ScriptFunction|ScriptObject as the last argument to the constructor
+        final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
         newArgTypes[argLen] = extraArgumentType;
         System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
 
@@ -588,6 +589,34 @@
         // Initialize converters
         generateConverterInit(mv, fromFunction);
         endInitMethod(mv);
+
+        if (! fromFunction) {
+            newArgTypes[argLen] = OBJECT_TYPE;
+            final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
+                Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
+            generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor());
+        }
+    }
+
+    // Object additional param accepting constructor - generated to handle null and undefined value
+    // for script adapters. This is effectively to throw TypeError on such script adapters. See
+    // JavaAdapterServices.getHandle as well.
+    private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final Constructor<?> ctor, final String ctorDescriptor) {
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        final Class<?>[] argTypes = ctor.getParameterTypes();
+        int offset = 1; // First arg is at position 1, after this.
+        for (int i = 0; i < argTypes.length; ++i) {
+            final Type argType = Type.getType(argTypes[i]);
+            mv.load(offset, argType);
+            offset += argType.getSize();
+        }
+        mv.invokespecial(superClassName, INIT, ctorDescriptor, false);
+        mv.visitVarInsn(ALOAD, offset);
+        mv.visitInsn(ACONST_NULL);
+        mv.visitInsn(ACONST_NULL);
+        mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
+        endInitMethod(mv);
     }
 
     private static void endInitMethod(final InstructionAdapter mv) {
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java	Tue Nov 04 17:21:00 2014 +0000
@@ -39,6 +39,7 @@
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
 
 /**
  * This class encapsulates the bytecode of the adapter class and can be used to load it into the JVM as an actual Class.
@@ -51,7 +52,7 @@
     private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader");
     private static final AccessControlContext GET_CONTEXT_ACC_CTXT = ClassAndLoader.createPermAccCtxt(Context.NASHORN_GET_CONTEXT);
     private static final Collection<String> VISIBLE_INTERNAL_CLASS_NAMES = Collections.unmodifiableCollection(new HashSet<>(
-            Arrays.asList(JavaAdapterServices.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
+            Arrays.asList(JavaAdapterServices.class.getName(), ScriptObject.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
 
     private final String className;
     private final byte[] classBytes;
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java	Tue Nov 04 17:21:00 2014 +0000
@@ -47,7 +47,6 @@
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
-import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -220,7 +219,7 @@
      * @return the filtered return value.
      */
     public static Object exportReturnValue(final Object obj) {
-        return ScriptUtils.wrap(NashornBeansLinker.exportArgument(obj));
+        return NashornBeansLinker.exportArgument(obj, true);
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Tue Nov 04 17:21:00 2014 +0000
@@ -35,17 +35,28 @@
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.linker.LinkerServices;
 import jdk.internal.dynalink.support.Lookup;
+import jdk.nashorn.api.scripting.ScriptUtils;
+import jdk.nashorn.internal.objects.NativeArray;
 import jdk.nashorn.internal.runtime.ConsString;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.options.Options;
 
 /**
  * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
  * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
- * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
+ * observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
  * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
  * the target method handle parameter signature is {@code Object}.
  */
 public class NashornBeansLinker implements GuardingDynamicLinker {
+    // System property to control whether to wrap ScriptObject->ScriptObjectMirror for
+    // Object type arguments of Java method calls, field set and array set.
+    private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
+
     private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
+    private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
+    private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
+    private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class);
 
     private final BeansLinker beansLinker = new BeansLinker();
 
@@ -67,8 +78,39 @@
         return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
     }
 
-    static Object exportArgument(final Object arg) {
-        return arg instanceof ConsString ? arg.toString() : arg;
+    @SuppressWarnings("unused")
+    private static Object exportArgument(final Object arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object exportNativeArray(final NativeArray arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object exportScriptObject(final ScriptObject arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object exportScriptArray(final NativeArray arg) {
+        return exportArgument(arg, MIRROR_ALWAYS);
+    }
+
+    static Object exportArgument(final Object arg, final boolean mirrorAlways) {
+        if (arg instanceof ConsString) {
+            return arg.toString();
+        } else if (mirrorAlways && arg instanceof ScriptObject) {
+            return ScriptUtils.wrap((ScriptObject)arg);
+        } else {
+            return arg;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static Object importResult(final Object arg) {
+        return ScriptUtils.unwrap(arg);
     }
 
     private static class NashornBeansLinkerServices implements LinkerServices {
@@ -80,23 +122,50 @@
 
         @Override
         public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
-            final MethodHandle typed = linkerServices.asType(handle, fromType);
-
             final MethodType handleType = handle.type();
             final int paramCount = handleType.parameterCount();
             assert fromType.parameterCount() == handleType.parameterCount();
 
+            MethodType newFromType = fromType;
             MethodHandle[] filters = null;
             for(int i = 0; i < paramCount; ++i) {
-                if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
-                    if(filters == null) {
+                final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
+                if (filter != null) {
+                    if (filters == null) {
                         filters = new MethodHandle[paramCount];
                     }
-                    filters[i] = EXPORT_ARGUMENT;
+                    // "erase" specific type with Object type or else we'll get filter mismatch
+                    newFromType = newFromType.changeParameterType(i, Object.class);
+                    filters[i] = filter;
                 }
             }
 
-            return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
+            final MethodHandle typed = linkerServices.asType(handle, newFromType);
+            MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
+            // Filter Object typed return value for possible ScriptObjectMirror. We convert
+            // ScriptObjectMirror as ScriptObject (if it is mirror from current global).
+            if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
+                result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
+            }
+
+            return result;
+        }
+
+        private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
+            if (handleType == Object.class) {
+                if (fromType == Object.class) {
+                    return EXPORT_ARGUMENT;
+                } else if (fromType == NativeArray.class) {
+                    return EXPORT_NATIVE_ARRAY;
+                } else if (fromType == ScriptObject.class) {
+                    return EXPORT_SCRIPT_OBJECT;
+                }
+            }
+            return null;
+        }
+
+        private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
+            return handleType == Object.class && fromType == Object.class;
         }
 
         @Override
@@ -104,10 +173,6 @@
             return Implementation.asTypeLosslessReturn(this, handle, fromType);
         }
 
-        private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
-            return handleType == Object.class && fromType == Object.class;
-        }
-
         @Override
         public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
             return linkerServices.getTypeConverter(sourceType, targetType);
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Tue Nov 04 17:21:00 2014 +0000
@@ -292,7 +292,7 @@
 
     @SuppressWarnings("unused")
     private static Object createMirror(final Object obj) {
-        return ScriptUtils.wrap(obj);
+        return obj instanceof ScriptObject? ScriptUtils.wrap((ScriptObject)obj) : obj;
     }
 
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
--- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/Messages.properties	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties	Tue Nov 04 17:21:00 2014 +0000
@@ -73,6 +73,7 @@
 type.error.not.an.object={0} is not an Object
 type.error.not.a.boolean={0} is not a Boolean
 type.error.not.a.date={0} is not a Date
+type.error.not.a.java.importer={0} is not a JavaImporter object
 type.error.not.a.number={0} is not a Number
 type.error.not.a.regexp={0} is not a RegExp
 type.error.not.a.string={0} is not a String
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Tue Nov 04 17:21:00 2014 +0000
@@ -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 = {              \
--- a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js	Fri Oct 10 15:53:41 2014 +0100
+++ b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js	Tue Nov 04 17:21:00 2014 +0000
@@ -105,7 +105,7 @@
         if (arguments.length < 1 || arguments.length > 2 ) {
             throw "sync(function [,object]) parameter count mismatch";
         }
-        return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj);
+        return Java.synchronized(func, syncobj);
     }
 });
 
@@ -160,7 +160,7 @@
     configurable: true, enumerable: false, writable: true,
     value: function(state) {
         if (! state) {
-            state = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap());
+            state = java.util.Collections.newSetFromMap(new java.util.HashMap());
         }
         if (state.contains(this)) {
             return "{}";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/examples/charcodeat-benchmark.js	Tue Nov 04 17:21:00 2014 +0000
@@ -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 Nov 04 17:21:00 2014 +0000
@@ -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/JDK-8058610.js	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * JDK-8058610: must not let long operations overflow
+ *
+ * @test
+ * @run
+ */
+
+function mul(x) { 
+    return x.foo * x.bar; 
+} 
+print("=== mul ===")
+print(mul({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(mul({foo: 17179869184, bar: 2147483647})); // 2^34
+
+function self_mul(x) {
+    return x.foo *= x.bar; 
+}
+print("=== self_mul ===")
+print(self_mul({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(self_mul({foo: 17179869184, bar: 2147483647})); // 2^34
+
+// We'll need to use this function to obtain long values larger in 
+// magnitude than those precisely representable in a double (2^53), 
+// as Nashorn's parser will reify such literals as a double. For 
+// overflow on add and sub we need (2^63)-1.
+var parseLong = Java.type("java.lang.Long").parseLong;
+
+function sub(x) {
+    return x.foo - x.bar;
+}
+print("=== sub ===")
+print(sub({foo: 2147483647,  bar: -2147483647})); // 2^31
+print(sub({foo: parseLong("9223372036854775807"), bar: parseLong("-9223372036854775807")})); // 2^63-1
+
+function self_sub(x) {
+    return x.foo -= x.bar;
+}
+print("=== self_sub ===")
+print(self_sub({foo: 2147483647,  bar: -2147483647})); // 2^31
+print(self_sub({foo: parseLong("9223372036854775807"), bar: parseLong("-9223372036854775807")})); // 2^63-1
+
+function add(x) {
+    return x.foo + x.bar;
+}
+print("=== add ===")
+print(add({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(add({foo: parseLong("9223372036854775807"), bar: parseLong("9223372036854775807")})); // 2^63-1
+
+function self_add(x) {
+    return x.foo += x.bar;
+}
+print("=== self_add ===")
+print(self_add({foo: 2147483647,  bar: 2147483647})); // 2^31
+print(self_add({foo: parseLong("9223372036854775807"), bar: parseLong("9223372036854775807")})); // 2^63-1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8058610.js.EXPECTED	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,18 @@
+=== mul ===
+4611686014132420600
+36893488130239234000
+=== self_mul ===
+4611686014132420600
+36893488130239234000
+=== sub ===
+4294967294
+18446744073709552000
+=== self_sub ===
+4294967294
+18446744073709552000
+=== add ===
+4294967294
+18446744073709552000
+=== self_add ===
+4294967294
+18446744073709552000
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8060011.js	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * JDK-8060011: Concatenating an array and converting it to Java gives wrong result
+ *
+ * @test
+ * @run
+ */
+
+
+function compareAsJavaArrays(a1, a2) {
+    var ja1 = Java.to(a1);
+    var ja2 = Java.to(a2);
+    if (ja1.length !== ja2.length) {
+        throw "different length";
+    }
+    for (var i = 0; i < ja1.length; i++) {
+        if (ja1[i] !== ja2[i]) {
+            throw "different element at " + i;
+        }
+    }
+    if (java.util.Arrays.toString(ja1) !== java.util.Arrays.toString(ja2)) {
+        throw "different string representation";
+    }
+}
+
+compareAsJavaArrays([0, 1, 2, 3],
+                    [0].concat([1, 2, 3]));
+compareAsJavaArrays([1000000000, 2000000000, 3000000000, 4000000000],
+                    [1000000000].concat([2000000000, 3000000000, 4000000000]));
+compareAsJavaArrays([0.5, 1.5, 2.5, 3.5],
+                    [0.5].concat([1.5, 2.5, 3.5]));
+compareAsJavaArrays(["0", "1", "2", "3"],
+                    ["0"].concat(["1", "2", "3"]));
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8060101.js	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * JDK-8060101: AssertionError: __noSuchProperty__ placeholder called from NativeJavaImporter
+ *
+ * @test
+ * @run
+ */
+
+var constant = 0.50;
+var ind = 0.0;
+
+// make sure callsites are exercised quite a few times
+// to induce megamorphic callsite for with/JavaImporter
+// combo - which triggered that AssertionError.
+for (var i = 0; i < 50; i++) {
+    var math = new JavaImporter(java.lang.StrictMath);
+    ind += 10.0;
+    with (math) {
+        StrictMath.exp(-constant*ind);
+    }
+}
+
+for (var i = 0; i < 50; i++) {
+    var math = new JavaImporter(java.lang.StrictMath);
+    try {
+        math.Foo();
+    } catch (e) {
+        if (! (e instanceof TypeError)) {
+            throw e;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061113.js	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * JDK-8061113: Boolean used as optimistic call return type
+ *
+ * @test
+ * @run
+ */
+
+function testcase() {
+    var a = {x:0};
+    return (function () {return a.x === 0})();
+}
+print(testcase());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8061113.js.EXPECTED	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,1 @@
+true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/apply_to_call/apply_to_call5.js	Tue Nov 04 17:21:00 2014 +0000
@@ -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 Nov 04 17:21:00 2014 +0000
@@ -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
--- a/test/script/basic/convert.js	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/script/basic/convert.js	Tue Nov 04 17:21:00 2014 +0000
@@ -42,7 +42,7 @@
 
 // object to Map
 obj = { foo: 333, bar: 'hello'};
-var map = ScriptUtils.convert(obj, java.util.Map.class);
+var map = ScriptUtils.wrap(obj);
 print(map instanceof java.util.Map);
 for (m in map) {
    print(m + " " + map[m]);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/fastpushpop.js	Tue Nov 04 17:21:00 2014 +0000
@@ -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 Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/script/basic/octane-payload.js	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/script/basic/run-octane.js	Tue Nov 04 17:21:00 2014 +0000
@@ -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/script/nosecurity/JDK-8044798.js	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/script/nosecurity/JDK-8044798.js	Tue Nov 04 17:21:00 2014 +0000
@@ -25,6 +25,8 @@
  * JDK-8044798: API for debugging Nashorn
  *
  * @test
+ * @option -Dnashorn.mirror.always=false
+ * @fork
  * @run
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/nosecurity/JDK-8060688.js	Tue Nov 04 17:21:00 2014 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * JDK-8060688: Nashorn: Generated script class name fails --verify-code for names with special chars
+ *
+ * @test
+ * @run
+ */
+
+var NashornEngineFactory = Java.type("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
+var ScriptEngine = Java.type("javax.script.ScriptEngine");
+var ScriptContext = Java.type("javax.script.ScriptContext");
+
+var factory = new NashornEngineFactory();
+
+var e = factory.getScriptEngine("--verify-code");
+
+function evalAndCheck(code) {
+    try {
+        e.eval(code);
+    } catch (exp) {
+        exp.printStackTrace();
+    }
+}
+
+// check default name
+evalAndCheck("var a = 3");
+// check few names with special chars
+var scontext = e.context;
+scontext.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
+evalAndCheck("var h = 'hello'");
+scontext.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
+evalAndCheck("var foo = 'world'");
+scontext.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
+evalAndCheck("var foo = 'helloworld'");
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java	Tue Nov 04 17:21:00 2014 +0000
@@ -168,42 +168,6 @@
         }
     }
 
-    @Test
-    /**
-     * Check that script can't implement sensitive package interfaces.
-     */
-    public void checkSensitiveInterfaceImplTest() throws ScriptException {
-        if (System.getSecurityManager() == null) {
-            // pass vacuously
-            return;
-        }
-
-        final ScriptEngineManager m = new ScriptEngineManager();
-        final ScriptEngine e = m.getEngineByName("nashorn");
-        final Object[] holder = new Object[1];
-        e.put("holder", holder);
-        // put an empty script object into array
-        e.eval("holder[0] = {}");
-        // holder[0] is an object of some subclass of ScriptObject
-        final Class<?> ScriptObjectClass = holder[0].getClass().getSuperclass();
-        final Class<?> PropertyAccessClass = ScriptObjectClass.getInterfaces()[0];
-        // implementation methods for PropertyAccess class
-        e.eval("function set() {}; function get() {}; function getInt(){} " +
-               "function getDouble(){}; function getLong() {}; " +
-               "this.delete = function () {}; function has() {}; " +
-               "function hasOwnProperty() {}");
-
-        // get implementation of a restricted package interface
-        try {
-            log(Objects.toString(((Invocable)e).getInterface((Class<?>)PropertyAccessClass)));
-            fail("should have thrown SecurityException");
-        } catch (final Exception exp) {
-            if (! (exp instanceof SecurityException)) {
-                fail("SecurityException expected, got " + exp);
-            }
-        }
-    }
-
     // @bug 8032948: Nashorn linkages awry
     public static class FakeProxy extends Proxy {
         public FakeProxy(final InvocationHandler ih) {
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java	Tue Nov 04 17:21:00 2014 +0000
@@ -38,6 +38,7 @@
 import java.util.concurrent.Callable;
 import javax.script.Compilable;
 import javax.script.CompiledScript;
+import javax.script.Invocable;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
@@ -629,6 +630,40 @@
         assertEquals(enumerable, Boolean.FALSE);
     }
 
+    public static class Context {
+        private Object myobj;
+
+        public void set(Object o) {
+            myobj = o;
+        }
+
+        public Object get() {
+            return myobj;
+        }
+    }
+
+    // @bug 8050977: Java8 Javascript Nashorn exception:
+    // no current Global instance for nashorn
+    @Test
+    public void currentGlobalMissingTest() throws Exception {
+        final ScriptEngineManager manager = new ScriptEngineManager();
+        final ScriptEngine e = manager.getEngineByName("nashorn");
+
+        final Context ctx = new Context();
+        e.put("ctx", ctx);
+        e.eval("var obj = { foo: function(str) { return str.toUpperCase() } }");
+        e.eval("ctx.set(obj)");
+        final Invocable inv = (Invocable)e;
+        assertEquals("HELLO", inv.invokeMethod(ctx.get(), "foo", "hello"));
+        // try object literal
+        e.eval("ctx.set({ bar: function(str) { return str.toLowerCase() } })");
+        assertEquals("hello", inv.invokeMethod(ctx.get(), "bar", "HELLO"));
+        // try array literal
+        e.eval("var arr = [ 'hello', 'world' ]");
+        e.eval("ctx.set(arr)");
+        assertEquals("helloworld", inv.invokeMethod(ctx.get(), "join", ""));
+    }
+
     private static void checkProperty(final ScriptEngine e, final String name)
         throws ScriptException {
         final String value = System.getProperty(name);
--- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Tue Nov 04 17:21:00 2014 +0000
@@ -72,6 +72,7 @@
         options.set("print.parse", true);
         options.set("scripting", true);
         options.set("const.as.var", true);
+        options.set("verify.code", true);
 
         final ErrorManager errors = new ErrorManager() {
             @Override
--- a/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/internal/runtime/ClassFilterTest.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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/runtime/TrustedScriptEngineTest.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java	Tue Nov 04 17:21:00 2014 +0000
@@ -325,4 +325,29 @@
         );
         assertEquals(ret, 10, "Parsed and executed OK");
     }
+
+    @Test
+    public void evalDefaultFileNameTest() throws ScriptException {
+        final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
+        final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
+        // default FILENAME being "<eval>" make sure generated code bytecode verifies.
+        engine.eval("var a = 3;");
+    }
+
+    @Test
+    public void evalFileNameWithSpecialCharsTest() throws ScriptException {
+        final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
+        final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
+        final ScriptContext ctxt = new SimpleScriptContext();
+        // use file name with "dangerous" chars.
+        ctxt.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var a = 3;");
+        ctxt.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var h = 'hello';");
+        ctxt.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var foo = 'world';");
+        // name used by jjs shell tool for the interactive mode
+        ctxt.setAttribute(ScriptEngine.FILENAME, "<shell>", ScriptContext.ENGINE_SCOPE);
+        engine.eval("var foo = 'world';");
+    }
 }
--- a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java	Tue Nov 04 17:21:00 2014 +0000
@@ -78,7 +78,8 @@
     // ParallelTestRunner-specific
     private static final String    TEST_JS_THREADS     = "test.js.threads";
     private static final String    TEST_JS_REPORT_FILE = "test.js.report.file";
-    private static final int       THREADS             = Integer.getInteger(TEST_JS_THREADS, Runtime.getRuntime().availableProcessors());
+    // test262 does a lot of eval's and the JVM hates multithreaded class definition, so lower thread count is usually faster.
+    private static final int       THREADS = Integer.getInteger(TEST_JS_THREADS, Runtime.getRuntime().availableProcessors() > 4 ? 4 : 2);
 
     private final List<ScriptRunnable> tests    = new ArrayList<>();
     private final Set<String>      orphans  = new TreeSet<>();
--- a/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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	Fri Oct 10 15:53:41 2014 +0100
+++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Tue Nov 04 17:21:00 2014 +0000
@@ -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);
     }