changeset 1634:f606c983f7fa

Merge
author asaha
date Tue, 06 Oct 2015 11:04:55 -0700
parents 718b32884775 (current diff) f7c3d65076a0 (diff)
children 75bca5dc1e81
files .hgtags test/src/jdk/nashorn/api/scripting/JSONCompatibleTest.java
diffstat 80 files changed, 2283 insertions(+), 799 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Sep 28 15:36:24 2015 -0700
+++ b/.hgtags	Tue Oct 06 11:04:55 2015 -0700
@@ -473,3 +473,4 @@
 9a3b86240761e602469c41bd720c7791997253e6 jdk8u66-b15
 c0ce5c308f5e2c42ac0d2e7367355663312a3128 jdk8u66-b16
 667e020da337e453eac8ecb9285c9b34a47e25fd jdk8u72-b00
+a105e7b0eff93895b82e3d372a63df4311d79821 jdk8u72-b01
--- a/make/build.xml	Mon Sep 28 15:36:24 2015 -0700
+++ b/make/build.xml	Tue Oct 06 11:04:55 2015 -0700
@@ -280,8 +280,8 @@
     <javac srcdir="${test.src.dir}"
            destdir="${build.test.classes.dir}"
            classpath="${javac.test.classpath}"
-           source="${javac.source}"
-           target="${javac.target}"
+           source="${test.javac.source}"
+           target="${test.javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
            includeantruntime="false" fork="true">
--- a/make/project.properties	Mon Sep 28 15:36:24 2015 -0700
+++ b/make/project.properties	Tue Oct 06 11:04:55 2015 -0700
@@ -30,6 +30,8 @@
 build.compiler=modern
 javac.source=1.7
 javac.target=1.7
+test.javac.source=1.8
+test.javac.target=1.8
 
 # nashorn version information
 nashorn.version=0.1
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Tue Oct 06 11:04:55 2015 -0700
@@ -140,7 +140,7 @@
         this._global_per_engine = nashornContext.getEnv()._global_per_engine;
 
         // create new global object
-        this.global = createNashornGlobal(context);
+        this.global = createNashornGlobal();
         // set the default ENGINE_SCOPE object for the default context
         context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
     }
@@ -167,7 +167,7 @@
             // We use same 'global' for all Bindings.
             return new SimpleBindings();
         }
-        return createGlobalMirror(null);
+        return createGlobalMirror();
     }
 
     // Compilable methods
@@ -317,7 +317,7 @@
 
         // We didn't find associated nashorn global mirror in the Bindings given!
         // Create new global instance mirror and associate with the Bindings.
-        final ScriptObjectMirror mirror = createGlobalMirror(ctxt);
+        final ScriptObjectMirror mirror = createGlobalMirror();
         bindings.put(NASHORN_GLOBAL, mirror);
         return mirror.getHomeGlobal();
     }
@@ -333,13 +333,13 @@
     }
 
     // Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object
-    private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) {
-        final Global newGlobal = createNashornGlobal(ctxt);
+    private ScriptObjectMirror createGlobalMirror() {
+        final Global newGlobal = createNashornGlobal();
         return new ScriptObjectMirror(newGlobal, newGlobal);
     }
 
     // Create a new Nashorn Global object
-    private Global createNashornGlobal(final ScriptContext ctxt) {
+    private Global createNashornGlobal() {
         final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction<Global>() {
             @Override
             public Global run() {
@@ -354,7 +354,7 @@
             }
         }, CREATE_GLOBAL_ACC_CTXT);
 
-        nashornContext.initGlobal(newGlobal, this, ctxt);
+        nashornContext.initGlobal(newGlobal, this);
 
         return newGlobal;
     }
--- a/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/ApplySpecialization.java	Tue Oct 06 11:04:55 2015 -0700
@@ -41,9 +41,8 @@
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -81,7 +80,7 @@
  */
 
 @Logger(name="apply2call")
-public final class ApplySpecialization extends NodeVisitor<LexicalContext> implements Loggable {
+public final class ApplySpecialization extends SimpleNodeVisitor implements Loggable {
 
     private static final boolean USE_APPLY2CALL = Options.getBooleanProperty("nashorn.apply2call", true);
 
@@ -105,7 +104,6 @@
      * @param compiler compiler
      */
     public ApplySpecialization(final Compiler compiler) {
-        super(new LexicalContext());
         this.compiler = compiler;
         this.log = initLogger(compiler.getContext());
     }
@@ -138,7 +136,7 @@
 
     private boolean hasApplies(final FunctionNode functionNode) {
         try {
-            functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            functionNode.accept(new SimpleNodeVisitor() {
                 @Override
                 public boolean enterFunctionNode(final FunctionNode fn) {
                     return fn == functionNode;
@@ -172,7 +170,7 @@
         final Deque<Set<Expression>> stack = new ArrayDeque<>();
 
         //ensure that arguments is only passed as arg to apply
-        functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        functionNode.accept(new SimpleNodeVisitor() {
 
             private boolean isCurrentArg(final Expression expr) {
                 return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call
--- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Tue Oct 06 11:04:55 2015 -0700
@@ -67,14 +67,12 @@
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IndexNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LexicalContextNode;
 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.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
+import jdk.nashorn.internal.ir.Splittable;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -82,7 +80,7 @@
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ECMAErrors;
@@ -103,7 +101,7 @@
  * visitor.
  */
 @Logger(name="symbols")
-final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggable {
+final class AssignSymbols extends SimpleNodeVisitor implements Loggable {
     private final DebugLogger log;
     private final boolean     debug;
 
@@ -151,7 +149,6 @@
     private final boolean isOnDemand;
 
     public AssignSymbols(final Compiler compiler) {
-        super(new LexicalContext());
         this.compiler = compiler;
         this.log   = initLogger(compiler.getContext());
         this.debug = log.isEnabled();
@@ -188,7 +185,7 @@
      */
     private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
         // This visitor will assign symbol to all declared variables.
-        body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        body.accept(new SimpleNodeVisitor() {
             @Override
             protected boolean enterDefault(final Node node) {
                 // Don't bother visiting expressions; var is a statement, it can't be inside an expression.
@@ -984,7 +981,7 @@
         boolean previousWasBlock = false;
         for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
             final LexicalContextNode node = it.next();
-            if (node instanceof FunctionNode || isSplitArray(node)) {
+            if (node instanceof FunctionNode || isSplitLiteral(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;
@@ -1010,12 +1007,8 @@
         throw new AssertionError();
     }
 
-    private static boolean isSplitArray(final LexicalContextNode expr) {
-        if(!(expr instanceof ArrayLiteralNode)) {
-            return false;
-        }
-        final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
-        return !(units == null || units.isEmpty());
+    private static boolean isSplitLiteral(final LexicalContextNode expr) {
+        return expr instanceof Splittable && ((Splittable) expr).getSplitRanges() != null;
     }
 
     private void throwUnprotectedSwitchError(final VarNode varNode) {
--- a/src/jdk/nashorn/internal/codegen/CacheAst.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/CacheAst.java	Tue Oct 06 11:04:55 2015 -0700
@@ -29,19 +29,17 @@
 import java.util.Collections;
 import java.util.Deque;
 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.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 
-class CacheAst extends NodeVisitor<LexicalContext> {
+class CacheAst extends SimpleNodeVisitor {
     private final Deque<RecompilableScriptFunctionData> dataStack = new ArrayDeque<>();
 
     private final Compiler compiler;
 
     CacheAst(final Compiler compiler) {
-        super(new LexicalContext());
         this.compiler = compiler;
         assert !compiler.isOnDemandCompilation();
     }
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -105,7 +105,6 @@
 import jdk.nashorn.internal.ir.LexicalContextNode;
 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.LiteralNode.PrimitiveLiteralNode;
 import jdk.nashorn.internal.ir.LocalVariableConversion;
 import jdk.nashorn.internal.ir.LoopNode;
@@ -118,6 +117,7 @@
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
 import jdk.nashorn.internal.ir.SetSplitState;
 import jdk.nashorn.internal.ir.SplitReturn;
+import jdk.nashorn.internal.ir.Splittable;
 import jdk.nashorn.internal.ir.Statement;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
@@ -129,7 +129,7 @@
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Lexer.RegexToken;
 import jdk.nashorn.internal.parser.TokenType;
@@ -242,7 +242,7 @@
     private final DebugLogger log;
 
     /** From what size should we use spill instead of fields for JavaScript objects? */
-    private static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
+    static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
 
     private final Set<String> emittedMethods = new HashSet<>();
 
@@ -1433,8 +1433,7 @@
         final Block currentBlock = lc.getCurrentBlock();
         final CodeGeneratorLexicalContext codegenLexicalContext = lc;
 
-        function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-
+        function.accept(new SimpleNodeVisitor() {
             private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) {
                 final Symbol symbol = identNode.getSymbol();
                 final boolean isFastScope = isFastScope(symbol);
@@ -1634,7 +1633,7 @@
 
                     @Override
                     void consumeStack() {
-                        dynamicCall(2 + argsCount, getCallSiteFlags(), origCallee.getName());
+                        dynamicCall(2 + argsCount, getCallSiteFlags(), null);
                     }
                 }.emit();
                 return false;
@@ -2234,73 +2233,33 @@
      *
      * @param arrayLiteralNode the array of contents
      * @param arrayType        the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
-     *
-     * @return the method generator that was used
      */
-    private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
+    private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
         assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
 
-        final Expression[]    nodes    = arrayLiteralNode.getValue();
-        final Object          presets  = arrayLiteralNode.getPresets();
-        final int[]           postsets = arrayLiteralNode.getPostsets();
-        final Class<?>        type     = arrayType.getTypeClass();
-        final List<ArrayUnit> units    = arrayLiteralNode.getUnits();
+        final Expression[]     nodes    = arrayLiteralNode.getValue();
+        final Object           presets  = arrayLiteralNode.getPresets();
+        final int[]            postsets = arrayLiteralNode.getPostsets();
+        final List<Splittable.SplitRange> ranges   = arrayLiteralNode.getSplitRanges();
 
         loadConstant(presets);
 
         final Type elementType = arrayType.getElementType();
 
-        if (units != null) {
-            final MethodEmitter savedMethod     = method;
-            final FunctionNode  currentFunction = lc.getCurrentFunction();
-
-            for (final ArrayUnit arrayUnit : units) {
-                unit = lc.pushCompileUnit(arrayUnit.getCompileUnit());
-
-                final String className = unit.getUnitClassName();
-                assert unit != null;
-                final String name      = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
-                final String signature = methodDescriptor(type, ScriptFunction.class, Object.class, ScriptObject.class, type);
-
-                pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
-
-                method.setFunctionNode(currentFunction);
-                method.begin();
-
-                defineCommonSplitMethodParameters();
-                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();
-
-                for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
-                    method.load(arrayType, arraySlot);
-                    storeElement(nodes, elementType, postsets[i]);
+        if (ranges != null) {
+
+            loadSplitLiteral(new SplitLiteralCreator() {
+                @Override
+                public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
+                    for (int i = start; i < end; i++) {
+                        method.load(type, slot);
+                        storeElement(nodes, elementType, postsets[i]);
+                    }
+                    method.load(type, slot);
                 }
-
-                method.load(arrayType, arraySlot);
-                method._return();
-                lc.exitSplitNode();
-                method.end();
-                lc.releaseSlots();
-                popMethodEmitter();
-
-                assert method == savedMethod;
-                method.loadCompilerConstant(CALLEE);
-                method.swap();
-                method.loadCompilerConstant(THIS);
-                method.swap();
-                method.loadCompilerConstant(SCOPE);
-                method.swap();
-                method.invokestatic(className, name, signature);
-
-                unit = lc.popCompileUnit(unit);
-            }
-
-            return method;
+            }, ranges, arrayType);
+
+            return;
         }
 
         if(postsets.length > 0) {
@@ -2312,7 +2271,6 @@
             }
             method.load(arrayType, arraySlot);
         }
-        return method;
     }
 
     private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
@@ -2502,7 +2460,7 @@
 
             @Override
             public Boolean get() {
-                value.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                value.accept(new SimpleNodeVisitor() {
                     @Override
                     public boolean enterFunctionNode(final FunctionNode functionNode) {
                         return false;
@@ -2537,6 +2495,7 @@
         final List<MapTuple<Expression>> tuples = new ArrayList<>();
         final List<PropertyNode> gettersSetters = new ArrayList<>();
         final int ccp = getCurrentContinuationEntryPoint();
+        final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
 
         Expression protoNode = null;
         boolean restOfProperty = false;
@@ -2583,7 +2542,13 @@
                     loadExpressionAsType(node, type);
                 }};
         }
-        oc.makeObject(method);
+
+        if (ranges != null) {
+            oc.createObject(method);
+            loadSplitLiteral(oc, ranges, Type.typeFor(oc.getAllocatorClass()));
+        } else {
+            oc.makeObject(method);
+        }
 
         //if this is a rest of method and our continuation point was found as one of the values
         //in the properties above, we need to reset the map to oc.getMap() in the continuation
@@ -2833,7 +2798,7 @@
             boolean contains;
             @Override
             public Boolean get() {
-                rootExpr.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                rootExpr.accept(new SimpleNodeVisitor() {
                     @Override
                     public boolean enterFunctionNode(final FunctionNode functionNode) {
                         return false;
@@ -2899,6 +2864,54 @@
         method.onLocalStore(type, slot);
     }
 
+    private void loadSplitLiteral(final SplitLiteralCreator creator, final List<Splittable.SplitRange> ranges, final Type literalType) {
+        assert ranges != null;
+
+        // final Type literalType = Type.typeFor(literalClass);
+        final MethodEmitter savedMethod     = method;
+        final FunctionNode  currentFunction = lc.getCurrentFunction();
+
+        for (final Splittable.SplitRange splitRange : ranges) {
+            unit = lc.pushCompileUnit(splitRange.getCompileUnit());
+
+            assert unit != null;
+            final String className = unit.getUnitClassName();
+            final String name      = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
+            final Class<?> clazz   = literalType.getTypeClass();
+            final String signature = methodDescriptor(clazz, ScriptFunction.class, Object.class, ScriptObject.class, clazz);
+
+            pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
+
+            method.setFunctionNode(currentFunction);
+            method.begin();
+
+            defineCommonSplitMethodParameters();
+            defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), literalType);
+
+            // 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 literalSlot = fixScopeSlot(currentFunction, 3);
+
+            lc.enterSplitNode();
+
+            creator.populateRange(method, literalType, literalSlot, splitRange.getLow(), splitRange.getHigh());
+
+            method._return();
+            lc.exitSplitNode();
+            method.end();
+            lc.releaseSlots();
+            popMethodEmitter();
+
+            assert method == savedMethod;
+            method.loadCompilerConstant(CALLEE).swap();
+            method.loadCompilerConstant(THIS).swap();
+            method.loadCompilerConstant(SCOPE).swap();
+            method.invokestatic(className, name, signature);
+
+            unit = lc.popCompileUnit(unit);
+        }
+    }
+
     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);
@@ -4333,7 +4346,7 @@
              * on the stack throughout the store and used at the end to execute it
              */
 
-            target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            target.accept(new SimpleNodeVisitor() {
                 @Override
                 public boolean enterIdentNode(final IdentNode node) {
                     if (node.getSymbol().isScope()) {
@@ -4432,7 +4445,7 @@
              * need to do a conversion on non-equivalent types exists, but is
              * very rare. See for example test/script/basic/access-specializer.js
              */
-            target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            target.accept(new SimpleNodeVisitor() {
                 @Override
                 protected boolean enterDefault(final Node node) {
                     throw new AssertionError("Unexpected node " + node + " in store epilogue");
@@ -5461,4 +5474,21 @@
             method.uncheckedGoto(targetCatchLabel);
         }
     }
+
+    /**
+     * Interface implemented by object creators that support splitting over multiple methods.
+     */
+    interface SplitLiteralCreator {
+        /**
+         * Generate code to populate a range of the literal object. A reference to the object
+         * should be left on the stack when the method terminates.
+         *
+         * @param method the method emitter
+         * @param type the type of the literal object
+         * @param slot the local slot containing the literal object
+         * @param start the start index (inclusive)
+         * @param end the end index (exclusive)
+         */
+        void populateRange(MethodEmitter method, Type type, int slot, int start, int end);
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue Oct 06 11:04:55 2015 -0700
@@ -36,13 +36,13 @@
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.runtime.CodeInstaller;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -118,7 +118,7 @@
             FunctionNode newFunctionNode;
 
             //ensure elementTypes, postsets and presets exist for splitter and arraynodes
-            newFunctionNode = transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            newFunctionNode = transformFunction(fn, new SimpleNodeVisitor() {
                 @Override
                 public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) {
                     return literalNode.initialize(lc);
@@ -217,7 +217,7 @@
             // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
             // is not an on-demand optimistic compilation, so we can skip locals marking then.
             if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
-                fn.getBody().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                fn.getBody().accept(new SimpleNodeVisitor() {
                     @Override
                     public boolean enterFunctionNode(final FunctionNode functionNode) {
                         // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
@@ -483,8 +483,8 @@
             Class<?> rootClass = null;
             long length = 0L;
 
-            final CodeInstaller<ScriptEnvironment> codeInstaller = compiler.getCodeInstaller();
-            final Map<String, byte[]>              bytecode      = compiler.getBytecode();
+            final CodeInstaller       codeInstaller = compiler.getCodeInstaller();
+            final Map<String, byte[]> bytecode      = compiler.getBytecode();
 
             for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
                 final String className = entry.getKey();
--- a/src/jdk/nashorn/internal/codegen/Compiler.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Tue Oct 06 11:04:55 2015 -0700
@@ -101,7 +101,7 @@
 
     private final ConstantData constantData;
 
-    private final CodeInstaller<ScriptEnvironment> installer;
+    private final CodeInstaller installer;
 
     /** logger for compiler, trampolines and related code generation events
      *  that affect classes */
@@ -351,47 +351,83 @@
     private static final AtomicInteger COMPILATION_ID = new AtomicInteger(0);
 
     /**
-     * Constructor
+     * Creates a new compiler instance for initial compilation of a script.
      *
-     * @param context   context
-     * @param env       script environment
      * @param installer code installer
      * @param source    source to compile
      * @param errors    error manager
      * @param isStrict  is this a strict compilation
+     * @return a new compiler
      */
-    public Compiler(
-            final Context context,
-            final ScriptEnvironment env,
-            final CodeInstaller<ScriptEnvironment> installer,
+    public static Compiler forInitialCompilation(
+            final CodeInstaller installer,
             final Source source,
             final ErrorManager errors,
             final boolean isStrict) {
-        this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null);
+        return new Compiler(installer.getContext(), installer, source, errors, isStrict);
     }
 
     /**
-     * Constructor
+     * Creates a compiler without a code installer. It can only be used to compile code, not install the
+     * generated classes and as such it is useful only for implementation of {@code --compile-only} command
+     * line option.
+     * @param context  the current context
+     * @param source   source to compile
+     * @param isStrict is this a strict compilation
+     * @return a new compiler
+     */
+    public static Compiler forNoInstallerCompilation(
+            final Context context,
+            final Source source,
+            final boolean isStrict) {
+        return new Compiler(context, null, source, context.getErrorManager(), isStrict);
+    }
+
+    /**
+     * Creates a compiler for an on-demand compilation job.
      *
-     * @param context                  context
-     * @param env                      script environment
      * @param installer                code installer
      * @param source                   source to compile
-     * @param errors                   error manager
      * @param isStrict                 is this a strict compilation
-     * @param isOnDemand               is this an on demand compilation
      * @param compiledFunction         compiled function, if any
      * @param types                    parameter and return value type information, if any is known
      * @param invalidatedProgramPoints invalidated program points for recompilation
      * @param typeInformationFile      descriptor of the location where type information is persisted
      * @param continuationEntryPoints  continuation entry points for restof method
      * @param runtimeScope             runtime scope for recompilation type lookup in {@code TypeEvaluator}
+     * @return a new compiler
      */
-    @SuppressWarnings("unused")
-    public Compiler(
+    public static Compiler forOnDemandCompilation(
+            final CodeInstaller installer,
+            final Source source,
+            final boolean isStrict,
+            final RecompilableScriptFunctionData compiledFunction,
+            final TypeMap types,
+            final Map<Integer, Type> invalidatedProgramPoints,
+            final Object typeInformationFile,
+            final int[] continuationEntryPoints,
+            final ScriptObject runtimeScope) {
+        final Context context = installer.getContext();
+        return new Compiler(context, installer, source, context.getErrorManager(), isStrict, true,
+                compiledFunction, types, invalidatedProgramPoints, typeInformationFile,
+                continuationEntryPoints, runtimeScope);
+    }
+
+    /**
+     * Convenience constructor for non on-demand compiler instances.
+     */
+    private Compiler(
             final Context context,
-            final ScriptEnvironment env,
-            final CodeInstaller<ScriptEnvironment> installer,
+            final CodeInstaller installer,
+            final Source source,
+            final ErrorManager errors,
+            final boolean isStrict) {
+        this(context, installer, source, errors, isStrict, false, null, null, null, null, null, null);
+    }
+
+    private Compiler(
+            final Context context,
+            final CodeInstaller installer,
             final Source source,
             final ErrorManager errors,
             final boolean isStrict,
@@ -403,7 +439,7 @@
             final int[] continuationEntryPoints,
             final ScriptObject runtimeScope) {
         this.context                  = context;
-        this.env                      = env;
+        this.env                      = context.getEnv();
         this.installer                = installer;
         this.constantData             = new ConstantData();
         this.compileUnits             = CompileUnit.createCompileUnitSet();
@@ -425,7 +461,7 @@
         this.optimistic = env._optimistic_types;
     }
 
-    private static String safeSourceName(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final Source source) {
+    private String safeSourceName() {
         String baseName = new File(source.getName()).getName();
 
         final int index = baseName.lastIndexOf(".js");
@@ -484,7 +520,7 @@
             sb.append('$');
         }
 
-        sb.append(Compiler.safeSourceName(env, installer, source));
+        sb.append(safeSourceName());
 
         return sb.toString();
     }
@@ -683,7 +719,7 @@
         return constantData;
     }
 
-    CodeInstaller<ScriptEnvironment> getCodeInstaller() {
+    CodeInstaller getCodeInstaller() {
         return installer;
     }
 
--- a/src/jdk/nashorn/internal/codegen/ConstantData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/ConstantData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -30,6 +30,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+
 import jdk.nashorn.internal.runtime.PropertyMap;
 
 /**
@@ -120,7 +122,7 @@
         private final int hashCode;
 
         public PropertyMapWrapper(final PropertyMap map) {
-            this.hashCode = Arrays.hashCode(map.getProperties());
+            this.hashCode = Arrays.hashCode(map.getProperties()) + 31 * Objects.hashCode(map.getClassName());
             this.propertyMap = map;
         }
 
@@ -131,8 +133,13 @@
 
         @Override
         public boolean equals(final Object other) {
-            return other instanceof PropertyMapWrapper &&
-                    Arrays.equals(propertyMap.getProperties(), ((PropertyMapWrapper) other).propertyMap.getProperties());
+            if (!(other instanceof PropertyMapWrapper)) {
+                return false;
+            }
+            final PropertyMap otherMap = ((PropertyMapWrapper) other).propertyMap;
+            return propertyMap == otherMap
+                    || (Arrays.equals(propertyMap.getProperties(), otherMap.getProperties())
+                        && Objects.equals(propertyMap.getClassName(), otherMap.getClassName()));
         }
     }
 
--- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -34,7 +34,6 @@
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
 
-import java.util.Iterator;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.Symbol;
@@ -91,27 +90,20 @@
         findClass();
     }
 
-    /**
-     * Construct an object.
-     *
-     * @param method the method emitter
-     */
     @Override
-    protected void makeObject(final MethodEmitter method) {
+    public void createObject(final MethodEmitter method) {
         makeMap();
         final String className = getClassName();
-        try {
-            // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
-            // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
-            // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
-            // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
-            // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
-            // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
-            // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
-            method._new(Context.forStructureClass(className.replace('/', '.'))).dup();
-        } catch (final ClassNotFoundException e) {
-            throw new AssertionError(e);
-        }
+        // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
+        // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
+        // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
+        // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
+        // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
+        // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
+        // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
+        assert fieldObjectClass != null;
+        method._new(fieldObjectClass).dup();
+
         loadMap(method); //load the map
 
         if (isScope()) {
@@ -126,14 +118,14 @@
         } else {
             method.invoke(constructorNoLookup(className, PropertyMap.class));
         }
+    }
 
-        helpOptimisticRecognizeDuplicateIdentity(method);
-
+    @Override
+    public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
+        method.load(objectType, objectSlot);
         // Set values.
-        final Iterator<MapTuple<T>> iter = tuples.iterator();
-
-        while (iter.hasNext()) {
-            final MapTuple<T> tuple = iter.next();
+        for (int i = start; i < end; i++) {
+            final MapTuple<T> tuple = tuples.get(i);
             //we only load when we have both symbols and values (which can be == the symbol)
             //if we didn't load, we need an array property
             if (tuple.symbol != null && tuple.value != null) {
@@ -212,6 +204,11 @@
         }
     }
 
+    @Override
+    protected Class<? extends ScriptObject> getAllocatorClass() {
+        return fieldObjectClass;
+    }
+
     /**
      * Get the class name for the object class,
      * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
--- a/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Tue Oct 06 11:04:55 2015 -0700
@@ -39,7 +39,7 @@
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -53,7 +53,7 @@
  * FunctionNode being compiled
  */
 @Logger(name="scopedepths")
-final class FindScopeDepths extends NodeVisitor<LexicalContext> implements Loggable {
+final class FindScopeDepths extends SimpleNodeVisitor implements Loggable {
 
     private final Compiler compiler;
     private final Map<Integer, Map<Integer, RecompilableScriptFunctionData>> fnIdToNestedFunctions = new HashMap<>();
@@ -66,7 +66,6 @@
     private int dynamicScopeCount;
 
     FindScopeDepths(final Compiler compiler) {
-        super(new LexicalContext());
         this.compiler = compiler;
         this.log      = initLogger(compiler.getContext());
     }
@@ -275,17 +274,13 @@
 
         //get all symbols that are referenced inside this function body
         final Set<Symbol> symbols = new HashSet<>();
-        block.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        block.accept(new SimpleNodeVisitor() {
             @Override
-            public final boolean enterDefault(final Node node) {
-                if (!compiler.isOnDemandCompilation()) {
-                    if (node instanceof IdentNode) {
-                        final Symbol symbol = ((IdentNode)node).getSymbol();
-                        if (symbol != null && symbol.isScope()) {
-                            //if this is an internal symbol, skip it.
-                            symbols.add(symbol);
-                        }
-                    }
+            public boolean enterIdentNode(final IdentNode identNode) {
+                final Symbol symbol = identNode.getSymbol();
+                if (symbol != null && symbol.isScope()) {
+                    //if this is an internal symbol, skip it.
+                    symbols.add(symbol);
                 }
                 return true;
             }
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java	Tue Oct 06 11:04:55 2015 -0700
@@ -38,7 +38,6 @@
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IfNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.Node;
@@ -47,7 +46,7 @@
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -59,12 +58,11 @@
  * Simple constant folding pass, executed before IR is starting to be lowered.
  */
 @Logger(name="fold")
-final class FoldConstants extends NodeVisitor<LexicalContext> implements Loggable {
+final class FoldConstants extends SimpleNodeVisitor implements Loggable {
 
     private final DebugLogger log;
 
     FoldConstants(final Compiler compiler) {
-        super(new LexicalContext());
         this.log = initLogger(compiler.getContext());
     }
 
@@ -116,7 +114,7 @@
                 statements.addAll(executed.getStatements()); // Get statements form executed branch
             }
             if (dropped != null) {
-                extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
+                extractVarNodesFromDeadCode(dropped, statements); // Get var-nodes from non-executed branch
             }
             if (statements.isEmpty()) {
                 return new EmptyNode(ifNode);
@@ -185,14 +183,27 @@
         protected abstract LiteralNode<?> eval();
     }
 
-    private static void extractVarNodes(final Block block, final List<Statement> statements) {
-        final LexicalContext lc = new LexicalContext();
-        block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
+    /**
+     * When we eliminate dead code, we must preserve var declarations as they are scoped to the whole
+     * function. This method gathers var nodes from code passed to it, removing their initializers.
+     *
+     * @param deadCodeRoot the root node of eliminated dead code
+     * @param statements a list that will be receiving the var nodes from the dead code, with their
+     * initializers removed.
+     */
+    static void extractVarNodesFromDeadCode(final Node deadCodeRoot, final List<Statement> statements) {
+        deadCodeRoot.accept(new SimpleNodeVisitor() {
             @Override
             public boolean enterVarNode(final VarNode varNode) {
                 statements.add(varNode.setInit(null));
                 return false;
             }
+
+            @Override
+            public boolean enterFunctionNode(final FunctionNode functionNode) {
+                // Don't descend into nested functions
+                return false;
+            }
         });
     }
 
--- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -87,6 +87,7 @@
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
 
 /**
@@ -105,7 +106,7 @@
  * instances of the calculator to be run on nested functions (when not lazy compiling).
  *
  */
-final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
+final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
 
     private static class JumpOrigin {
         final JoinPredecessor node;
@@ -425,7 +426,6 @@
     private final Deque<Label> catchLabels = new ArrayDeque<>();
 
     LocalVariableTypesCalculator(final Compiler compiler) {
-        super(new LexicalContext());
         this.compiler = compiler;
     }
 
@@ -1330,7 +1330,7 @@
         // Sets the return type of the function and also performs the bottom-up pass of applying type and conversion
         // information to nodes as well as doing the calculation on nested functions as required.
         FunctionNode newFunction = functionNode;
-        final NodeVisitor<LexicalContext> applyChangesVisitor = new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        final SimpleNodeVisitor applyChangesVisitor = new SimpleNodeVisitor() {
             private boolean inOuterFunction = true;
             private final Deque<JoinPredecessor> joinPredecessors = new ArrayDeque<>();
 
--- a/src/jdk/nashorn/internal/codegen/Lower.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/Lower.java	Tue Oct 06 11:04:55 2015 -0700
@@ -73,7 +73,7 @@
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
@@ -120,13 +120,7 @@
                             terminated = true;
                         }
                     } else {
-                        statement.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-                            @Override
-                            public boolean enterVarNode(final VarNode varNode) {
-                                newStatements.add(varNode.setInit(null));
-                                return false;
-                            }
-                        });
+                        FoldConstants.extractVarNodesFromDeadCode(statement, newStatements);
                     }
                 }
                 return newStatements;
@@ -327,7 +321,7 @@
 
     @SuppressWarnings("unchecked")
     private static <T extends Node> T ensureUniqueNamesIn(final T node) {
-        return (T)node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        return (T)node.accept(new SimpleNodeVisitor() {
             @Override
             public Node leaveFunctionNode(final FunctionNode functionNode) {
                 final String name = functionNode.getName();
@@ -392,7 +386,7 @@
         final Block finallyBlock = createFinallyBlock(finallyBody);
         final ArrayList<Block> inlinedFinallies = new ArrayList<>();
         final FunctionNode fn = lc.getCurrentFunction();
-        final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        final TryNode newTryNode = (TryNode)tryNode.accept(new SimpleNodeVisitor() {
 
             @Override
             public boolean enterFunctionNode(final FunctionNode functionNode) {
@@ -535,7 +529,7 @@
         final Block catchAll = catchAllBlock(tryNode);
 
         final List<ThrowNode> rethrows = new ArrayList<>(1);
-        catchAll.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        catchAll.accept(new SimpleNodeVisitor() {
             @Override
             public boolean enterThrowNode(final ThrowNode throwNode) {
                 rethrows.add(throwNode);
@@ -680,7 +674,7 @@
     private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) {
         final List<Node> escapes = new ArrayList<>();
 
-        loopBody.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        loopBody.accept(new SimpleNodeVisitor() {
             @Override
             public Node leaveBreakNode(final BreakNode node) {
                 escapes.add(node);
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Oct 06 11:04:55 2015 -0700
@@ -258,8 +258,7 @@
      */
     private Type popType(final Type expected) {
         final Type type = popType();
-        assert type.isObject() && expected.isObject() ||
-            type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
+        assert type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
         return type;
     }
 
--- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -36,7 +36,7 @@
  * Base class for object creation code generation.
  * @param <T> value type
  */
-public abstract class ObjectCreator<T> {
+public abstract class ObjectCreator<T> implements CodeGenerator.SplitLiteralCreator {
 
     /** List of keys & symbols to initiate in this ObjectCreator */
     final List<MapTuple<T>> tuples;
@@ -69,7 +69,23 @@
      * Generate code for making the object.
      * @param method Script method.
      */
-    protected abstract void makeObject(final MethodEmitter method);
+    public void makeObject(final MethodEmitter method) {
+        createObject(method);
+        // We need to store the object in a temporary slot as populateRange expects to load the
+        // object from a slot (as it is also invoked within split methods). Note that this also
+        // helps optimistic continuations to handle the stack in case an optimistic assumption
+        // fails during initialization (see JDK-8079269).
+        final int objectSlot = method.getUsedSlotsWithLiveTemporaries();
+        final Type objectType = method.peekType();
+        method.storeTemp(objectType, objectSlot);
+        populateRange(method, objectType, objectSlot, 0, tuples.size());
+    }
+
+    /**
+     * Generate code for creating and initializing the object.
+     * @param method the method emitter
+     */
+    protected abstract void createObject(final MethodEmitter method);
 
     /**
      * Construct the property map appropriate for the object.
@@ -125,6 +141,12 @@
     }
 
     /**
+     * Get the class of objects created by this ObjectCreator
+     * @return class of created object
+     */
+    abstract protected Class<? extends ScriptObject> getAllocatorClass();
+
+    /**
      * Technique for loading an initial value. Defined by anonymous subclasses in code gen.
      *
      * @param value Value to load.
@@ -145,29 +167,4 @@
     MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple) {
         return loadTuple(method, tuple, true);
     }
-
-    /**
-     * If using optimistic typing, let the code generator realize that the newly created object on the stack
-     * when DUP-ed will be the same value. Basically: {NEW, DUP, INVOKESPECIAL init, DUP} will leave a stack
-     * load specification {unknown, unknown} on stack (that is "there's two values on the stack, but neither
-     * comes from a known local load"). If there's an optimistic operation in the literal initializer,
-     * OptimisticOperation.storeStack will allocate two temporary locals for it and store them as
-     * {ASTORE 4, ASTORE 3}. If we instead do {NEW, DUP, INVOKESPECIAL init, ASTORE 3, ALOAD 3, DUP} we end up
-     * with stack load specification {ALOAD 3, ALOAD 3} (as DUP can track that the value it duplicated came
-     * from a local load), so if/when a continuation needs to be recreated from it, it'll be
-     * able to emit ALOAD 3, ALOAD 3 to recreate the stack. If we didn't do this, deoptimization within an
-     * object literal initialization could in rare cases cause an incompatible change in the shape of the
-     * local variable table for the temporaries, e.g. in the following snippet where a variable is reassigned
-     * to a wider type in an object initializer:
-     * <code>var m = 1; var obj = {p0: m, p1: m = "foo", p2: m}</code>
-     * @param method the current method emitter.
-     */
-    void helpOptimisticRecognizeDuplicateIdentity(final MethodEmitter method) {
-        if (codegen.useOptimisticTypes()) {
-            final Type objectType = method.peekType();
-            final int tempSlot = method.defineTemporaryLocalVariable(objectType.getSlots());
-            method.storeHidden(objectType, tempSlot);
-            method.load(objectType, tempSlot);
-        }
-    }
 }
--- a/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -42,7 +42,6 @@
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Optimistic;
@@ -52,7 +51,7 @@
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.ScriptObject;
 
@@ -61,7 +60,7 @@
  * must not ever be marked as optimistic, assigning narrowest non-invalidated types to program points from the
  * compilation environment, as well as initializing optimistic types of global properties for scripts.
  */
-final class OptimisticTypesCalculator extends NodeVisitor<LexicalContext> {
+final class OptimisticTypesCalculator extends SimpleNodeVisitor {
 
     final Compiler compiler;
 
@@ -69,7 +68,6 @@
     final Deque<BitSet> neverOptimistic = new ArrayDeque<>();
 
     OptimisticTypesCalculator(final Compiler compiler) {
-        super(new LexicalContext());
         this.compiler = compiler;
     }
 
--- a/src/jdk/nashorn/internal/codegen/ProgramPoints.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/ProgramPoints.java	Tue Oct 06 11:04:55 2015 -0700
@@ -37,25 +37,20 @@
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IndexNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.Optimistic;
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 
 /**
  * Find program points in the code that are needed for optimistic assumptions
  */
-class ProgramPoints extends NodeVisitor<LexicalContext> {
+class ProgramPoints extends SimpleNodeVisitor {
 
     private final IntDeque nextProgramPoint = new IntDeque();
     private final Set<Node> noProgramPoint = new HashSet<>();
 
-    ProgramPoints() {
-        super(new LexicalContext());
-    }
-
     private int next() {
         final int next = nextProgramPoint.getAndIncrement();
         if(next > MAX_PROGRAM_POINT_VALUE) {
--- a/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Tue Oct 06 11:04:55 2015 -0700
@@ -29,20 +29,17 @@
 import java.util.List;
 import jdk.nashorn.internal.ir.CompileUnitHolder;
 import jdk.nashorn.internal.ir.FunctionNode;
-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;
+import jdk.nashorn.internal.ir.ObjectNode;
+import jdk.nashorn.internal.ir.Splittable;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 
 /**
  * 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());
-    }
+abstract class ReplaceCompileUnits extends SimpleNodeVisitor {
 
     /**
      * Override to provide a replacement for an old compile unit.
@@ -70,15 +67,28 @@
     public Node leaveLiteralNode(final LiteralNode<?> node) {
         if (node instanceof ArrayLiteralNode) {
             final ArrayLiteralNode aln = (ArrayLiteralNode)node;
-            if (aln.getUnits() == null) {
+            if (aln.getSplitRanges() == 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()));
+            final List<Splittable.SplitRange> newArrayUnits = new ArrayList<>();
+            for (final Splittable.SplitRange au : aln.getSplitRanges()) {
+                newArrayUnits.add(new Splittable.SplitRange(getExistingReplacement(au), au.getLow(), au.getHigh()));
             }
-            return aln.setUnits(lc, newArrayUnits);
+            return aln.setSplitRanges(lc, newArrayUnits);
         }
         return node;
     }
+
+    @Override
+    public Node leaveObjectNode(final ObjectNode objectNode) {
+        final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
+        if (ranges != null) {
+            final List<Splittable.SplitRange> newRanges = new ArrayList<>();
+            for (final Splittable.SplitRange range : ranges) {
+                newRanges.add(new Splittable.SplitRange(getExistingReplacement(range), range.getLow(), range.getHigh()));
+            }
+            return objectNode.setSplitRanges(lc, newRanges);
+        }
+        return super.leaveObjectNode(objectNode);
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -61,7 +61,7 @@
     }
 
     @Override
-    protected void makeObject(final MethodEmitter method) {
+    public void createObject(final MethodEmitter method) {
         assert !isScope() : "spill scope objects are not currently supported";
 
         final int          length        = tuples.size();
@@ -69,9 +69,7 @@
         final int          spillLength   = ScriptObject.spillAllocationLength(length);
         final long[]       jpresetValues = dualFields ? new long[spillLength] : null;
         final Object[]     opresetValues = new Object[spillLength];
-        final Set<Integer> postsetValues = new LinkedHashSet<>();
-        final int          callSiteFlags = codegen.getCallSiteFlags();
-        final Class<?>     objectClass   = dualFields ? JD.class : JO.class;
+        final Class<?>     objectClass   = getAllocatorClass();
         ArrayData          arrayData     = ArrayData.allocate(ScriptRuntime.EMPTY_ARRAY);
 
         // Compute constant property values
@@ -85,9 +83,7 @@
 
             if (value != null) {
                 final Object constantValue = LiteralNode.objectAsConstant(value);
-                if (constantValue == LiteralNode.POSTSET_MARKER) {
-                    postsetValues.add(pos);
-                } else {
+                if (constantValue != LiteralNode.POSTSET_MARKER) {
                     final Property property = propertyMap.findProperty(key);
                     if (property != null) {
                         // normal property key
@@ -146,25 +142,34 @@
         // instantiate the script object with spill objects
         method.invoke(constructorNoLookup(objectClass, PropertyMap.class, long[].class, Object[].class));
 
-        helpOptimisticRecognizeDuplicateIdentity(method);
-
         // Set prefix array data if any
         if (arrayData.length() > 0) {
             method.dup();
             codegen.loadConstant(arrayData);
             method.invoke(virtualCallNoLookup(ScriptObject.class, "setArray", void.class, ArrayData.class));
         }
+    }
+
+    @Override
+    public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
+        final int  callSiteFlags = codegen.getCallSiteFlags();
+        method.load(objectType, objectSlot);
 
         // set postfix values
-        for (final int i : postsetValues) {
+        for (int i = start; i < end; i++) {
             final MapTuple<Expression> tuple = tuples.get(i);
+
+            if (LiteralNode.isConstant(tuple.value)) {
+                continue;
+            }
+
             final Property property = propertyMap.findProperty(tuple.key);
+
             if (property == null) {
                 final int index = ArrayIndex.getArrayIndex(tuple.key);
                 assert ArrayIndex.isValidArrayIndex(index);
                 method.dup();
                 method.load(ArrayIndex.toLongIndex(index));
-                //method.println("putting " + tuple + " into arraydata");
                 loadTuple(method, tuple);
                 method.dynamicSetIndex(callSiteFlags);
             } else {
@@ -178,8 +183,7 @@
     @Override
     protected PropertyMap makeMap() {
         assert propertyMap == null : "property map already initialized";
-        final boolean dualFields = codegen.useDualFields();
-        final Class<? extends ScriptObject> clazz = dualFields ? JD.class : JO.class;
+        final Class<? extends ScriptObject> clazz = getAllocatorClass();
         propertyMap = new MapCreator<>(clazz, tuples).makeSpillMap(false, codegen.useDualFields());
         return propertyMap;
     }
@@ -188,4 +192,9 @@
     protected void loadValue(final Expression expr, final Type type) {
         codegen.loadExpressionAsType(expr, type);
     }
+
+    @Override
+    protected Class<? extends ScriptObject> getAllocatorClass() {
+        return codegen.useDualFields() ? JD.class : JO.class;
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/Splitter.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java	Tue Oct 06 11:04:55 2015 -0700
@@ -33,14 +33,15 @@
 import java.util.Map;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
-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.ObjectNode;
+import jdk.nashorn.internal.ir.PropertyNode;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Splittable;
 import jdk.nashorn.internal.ir.Statement;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.logging.Loggable;
@@ -51,7 +52,7 @@
  * Split the IR into smaller compile units.
  */
 @Logger(name="splitter")
-final class Splitter extends NodeVisitor<LexicalContext> implements Loggable {
+final class Splitter extends SimpleNodeVisitor implements Loggable {
     /** Current compiler. */
     private final Compiler compiler;
 
@@ -77,7 +78,6 @@
      * @param outermostCompileUnit  compile unit for outermost function, if non-lazy this is the script's compile unit
      */
     public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
-        super(new LexicalContext());
         this.compiler             = compiler;
         this.outermost            = functionNode;
         this.outermostCompileUnit = outermostCompileUnit;
@@ -140,7 +140,7 @@
         final Block body = functionNode.getBody();
         final List<FunctionNode> dc = directChildren(functionNode);
 
-        final Block newBody = (Block)body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        final Block newBody = (Block)body.accept(new SimpleNodeVisitor() {
             @Override
             public boolean enterFunctionNode(final FunctionNode nestedFunction) {
                 return dc.contains(nestedFunction);
@@ -162,7 +162,7 @@
 
     private static List<FunctionNode> directChildren(final FunctionNode functionNode) {
         final List<FunctionNode> dc = new ArrayList<>();
-        functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        functionNode.accept(new SimpleNodeVisitor() {
             @Override
             public boolean enterFunctionNode(final FunctionNode child) {
                 if (child == functionNode) {
@@ -295,7 +295,7 @@
             final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
             final Node[]           value            = arrayLiteralNode.getValue();
             final int[]            postsets         = arrayLiteralNode.getPostsets();
-            final List<ArrayUnit>  units            = new ArrayList<>();
+            final List<Splittable.SplitRange> ranges = new ArrayList<>();
 
             long totalWeight = 0;
             int  lo          = 0;
@@ -309,7 +309,7 @@
 
                 if (totalWeight >= SPLIT_THRESHOLD) {
                     final CompileUnit unit = compiler.findUnit(totalWeight - weight);
-                    units.add(new ArrayUnit(unit, lo, i));
+                    ranges.add(new Splittable.SplitRange(unit, lo, i));
                     lo = i;
                     totalWeight = weight;
                 }
@@ -317,16 +317,59 @@
 
             if (lo != postsets.length) {
                 final CompileUnit unit = compiler.findUnit(totalWeight);
-                units.add(new ArrayUnit(unit, lo, postsets.length));
+                ranges.add(new Splittable.SplitRange(unit, lo, postsets.length));
             }
 
-            return arrayLiteralNode.setUnits(lc, units);
+            return arrayLiteralNode.setSplitRanges(lc, ranges);
         }
 
         return literal;
     }
 
     @Override
+    public Node leaveObjectNode(final ObjectNode objectNode) {
+        long weight = WeighNodes.weigh(objectNode);
+
+        if (weight < SPLIT_THRESHOLD) {
+            return objectNode;
+        }
+
+        final FunctionNode functionNode = lc.getCurrentFunction();
+        lc.setFlag(functionNode, FunctionNode.IS_SPLIT);
+
+        final List<Splittable.SplitRange> ranges        = new ArrayList<>();
+        final List<PropertyNode>          properties    = objectNode.getElements();
+        final boolean                     isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
+        long totalWeight = 0;
+        int  lo          = 0;
+
+        for (int i = 0; i < properties.size(); i++) {
+
+            final PropertyNode property = properties.get(i);
+            final boolean isConstant = LiteralNode.isConstant(property.getValue());
+
+            if (!isConstant || !isSpillObject) {
+                weight = isConstant ? 0 : WeighNodes.weigh(property.getValue());
+                totalWeight += WeighNodes.AASTORE_WEIGHT + weight;
+
+                if (totalWeight >= SPLIT_THRESHOLD) {
+                    final CompileUnit unit = compiler.findUnit(totalWeight - weight);
+                    ranges.add(new Splittable.SplitRange(unit, lo, i));
+                    lo = i;
+                    totalWeight = weight;
+                }
+            }
+        }
+
+        if (lo != properties.size()) {
+            final CompileUnit unit = compiler.findUnit(totalWeight);
+            ranges.add(new Splittable.SplitRange(unit, lo, properties.size()));
+        }
+
+        return objectNode.setSplitRanges(lc, ranges);
+    }
+
+    @Override
     public boolean enterFunctionNode(final FunctionNode node) {
         //only go into the function node for this splitter. any subfunctions are rejected
         return node == outermost;
--- a/src/jdk/nashorn/internal/codegen/WeighNodes.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java	Tue Oct 06 11:04:55 2015 -0700
@@ -44,12 +44,13 @@
 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.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Splittable;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.ThrowNode;
 import jdk.nashorn.internal.ir.TryNode;
@@ -88,6 +89,8 @@
     static final long THROW_WEIGHT     =  2;
     static final long VAR_WEIGHT       = 40;
     static final long WITH_WEIGHT      =  8;
+    static final long OBJECT_WEIGHT    = 16;
+    static final long SETPROP_WEIGHT   =  5;
 
     /** Accumulated weight. */
     private long weight;
@@ -213,7 +216,7 @@
             final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
             final Node[]           value            = arrayLiteralNode.getValue();
             final int[]            postsets         = arrayLiteralNode.getPostsets();
-            final List<ArrayUnit>  units            = arrayLiteralNode.getUnits();
+            final List<Splittable.SplitRange>  units            = arrayLiteralNode.getSplitRanges();
 
             if (units == null) {
                 for (final int postset : postsets) {
@@ -233,6 +236,27 @@
     }
 
     @Override
+    public boolean enterObjectNode(final ObjectNode objectNode) {
+        weight += OBJECT_WEIGHT;
+        final List<PropertyNode> properties = objectNode.getElements();
+        final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
+
+        for (final PropertyNode property : properties) {
+            if (!LiteralNode.isConstant(property.getValue())) {
+                weight += SETPROP_WEIGHT;
+                property.getValue().accept(this);
+            } else if (!isSpillObject) {
+                // constants in spill object are set via preset spill array,
+                // but fields objects need to set constants.
+                weight += SETPROP_WEIGHT;
+            }
+
+        }
+
+        return false;
+    }
+
+    @Override
     public Node leavePropertyNode(final PropertyNode propertyNode) {
         weight += LITERAL_WEIGHT;
         return propertyNode;
--- a/src/jdk/nashorn/internal/codegen/types/Type.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java	Tue Oct 06 11:04:55 2015 -0700
@@ -65,6 +65,7 @@
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.Undefined;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -256,6 +257,9 @@
         case jdk.internal.org.objectweb.asm.Type.DOUBLE:
             return NUMBER;
         case jdk.internal.org.objectweb.asm.Type.OBJECT:
+            if (Context.isStructureClass(itype.getClassName())) {
+                return SCRIPT_OBJECT;
+            }
             try {
                 return Type.typeFor(Class.forName(itype.getClassName()));
             } catch(final ClassNotFoundException e) {
@@ -949,7 +953,7 @@
     /**
      * This is the singleton for integer arrays
      */
-    public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
+    public static final ArrayType INT_ARRAY = putInCache(new ArrayType(int[].class) {
         private static final long serialVersionUID = 1L;
 
         @Override
@@ -973,12 +977,12 @@
         public Type getElementType() {
             return INT;
         }
-    };
+    });
 
     /**
      * This is the singleton for long arrays
      */
-    public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
+    public static final ArrayType LONG_ARRAY = putInCache(new ArrayType(long[].class) {
         private static final long serialVersionUID = 1L;
 
         @Override
@@ -1002,12 +1006,12 @@
         public Type getElementType() {
             return LONG;
         }
-    };
+    });
 
     /**
      * This is the singleton for numeric arrays
      */
-    public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
+    public static final ArrayType NUMBER_ARRAY = putInCache(new ArrayType(double[].class) {
         private static final long serialVersionUID = 1L;
 
         @Override
@@ -1031,13 +1035,7 @@
         public Type getElementType() {
             return NUMBER;
         }
-    };
-
-    /** Singleton for method handle arrays used for properties etc. */
-    public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
-
-    /** This is the singleton for string arrays */
-    public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
+    });
 
     /** This is the singleton for object arrays */
     public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Tue Oct 06 11:04:55 2015 -0700
@@ -25,11 +25,9 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.io.Serializable;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.codegen.types.ArrayType;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -561,6 +559,15 @@
         return POSTSET_MARKER;
     }
 
+    /**
+     * Test whether {@code object} represents a constant value.
+     * @param object a node or value object
+     * @return true if object is a constant value
+     */
+    public static boolean isConstant(final Object object) {
+        return objectAsConstant(object) != POSTSET_MARKER;
+    }
+
     private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
         private static final long serialVersionUID = 1L;
 
@@ -592,7 +599,7 @@
      * Array literal node class.
      */
     @Immutable
-    public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode {
+    public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode, Splittable {
         private static final long serialVersionUID = 1L;
 
         /** Array element type. */
@@ -604,59 +611,8 @@
         /** Indices of array elements requiring computed post sets. */
         private final int[] postsets;
 
-        /** Sub units with indexes ranges, in which to split up code generation, for large literals */
-        private final List<ArrayUnit> units;
-
-        /**
-         * 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, Serializable {
-            private static final long serialVersionUID = 1L;
-
-            /** Compile unit associated with the postsets range. */
-            private final CompileUnit compileUnit;
-
-            /** postsets range associated with the unit (hi not inclusive). */
-            private final int lo, hi;
-
-            /**
-             * Constructor
-             * @param compileUnit compile unit
-             * @param lo lowest array index in unit
-             * @param hi highest array index in unit + 1
-             */
-            public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) {
-                this.compileUnit = compileUnit;
-                this.lo   = lo;
-                this.hi   = hi;
-            }
-
-            /**
-             * Get the high index position of the ArrayUnit (non inclusive)
-             * @return high index position
-             */
-            public int getHi() {
-                return hi;
-            }
-
-            /**
-             * Get the low index position of the ArrayUnit (inclusive)
-             * @return low index position
-             */
-            public int getLo() {
-                return lo;
-            }
-
-            /**
-             * The array compile unit
-             * @return array compile unit
-             */
-            @Override
-            public CompileUnit getCompileUnit() {
-                return compileUnit;
-            }
-        }
+        /** Ranges for splitting up large literals in code generation */
+        private final List<Splittable.SplitRange> splitRanges;
 
         private static final class ArrayLiteralInitializer {
 
@@ -664,7 +620,7 @@
                 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);
+                return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.splitRanges);
             }
 
             private static Type computeElementType(final Expression[] value) {
@@ -697,7 +653,7 @@
 
                 for (int i = 0; i < value.length; i++) {
                     final Expression element = value[i];
-                    if (element == null || objectAsConstant(element) == POSTSET_MARKER) {
+                    if (element == null || !isConstant(element)) {
                         computed[nComputed++] = i;
                     }
                 }
@@ -814,19 +770,19 @@
             this.elementType = Type.UNKNOWN;
             this.presets     = null;
             this.postsets    = null;
-            this.units       = null;
+            this.splitRanges = null;
         }
 
         /**
          * Copy constructor
          * @param node source array literal node
          */
-        private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<ArrayUnit> units) {
+        private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<Splittable.SplitRange> splitRanges) {
             super(node, value);
             this.elementType = elementType;
             this.postsets    = postsets;
             this.presets     = presets;
-            this.units       = units;
+            this.splitRanges = splitRanges;
         }
 
         /**
@@ -917,26 +873,27 @@
         }
 
         /**
-         * Get the array units that make up this ArrayLiteral
-         * @see ArrayUnit
-         * @return list of array units
+         * Get the split ranges for this ArrayLiteral, or null if this array does not have to be split.
+         * @see Splittable.SplitRange
+         * @return list of split ranges
          */
-        public List<ArrayUnit> getUnits() {
-            return units == null ? null : Collections.unmodifiableList(units);
+        @Override
+        public List<Splittable.SplitRange> getSplitRanges() {
+            return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
         }
 
         /**
-         * Set the ArrayUnits that make up this ArrayLiteral
+         * Set the SplitRanges that make up this ArrayLiteral
          * @param lc lexical context
-         * @see ArrayUnit
-         * @param units list of array units
-         * @return new or changed arrayliteralnode
+         * @see Splittable.SplitRange
+         * @param splitRanges list of split ranges
+         * @return new or changed node
          */
-        public ArrayLiteralNode setUnits(final LexicalContext lc, final List<ArrayUnit> units) {
-            if (this.units == units) {
+        public ArrayLiteralNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
+            if (this.splitRanges == splitRanges) {
                 return this;
             }
-            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
+            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
         }
 
         @Override
@@ -958,7 +915,7 @@
             if (this.value == value) {
                 return this;
             }
-            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
+            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
         }
 
         private ArrayLiteralNode setValue(final LexicalContext lc, final List<Expression> value) {
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java	Tue Oct 06 11:04:55 2015 -0700
@@ -27,6 +27,7 @@
 
 import java.util.Collections;
 import java.util.List;
+import java.util.RandomAccess;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -35,12 +36,15 @@
  * IR representation of an object literal.
  */
 @Immutable
-public final class ObjectNode extends Expression {
+public final class ObjectNode extends Expression implements LexicalContextNode, Splittable {
     private static final long serialVersionUID = 1L;
 
     /** Literal elements. */
     private final List<PropertyNode> elements;
 
+    /** Ranges for splitting large literals over multiple compile units in codegen. */
+    private final List<Splittable.SplitRange> splitRanges;
+
     /**
      * Constructor
      *
@@ -51,19 +55,27 @@
     public ObjectNode(final long token, final int finish, final List<PropertyNode> elements) {
         super(token, finish);
         this.elements = elements;
+        this.splitRanges = null;
+        assert elements instanceof RandomAccess : "Splitting requires random access lists";
     }
 
-    private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements) {
+    private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements,
+                       final List<Splittable.SplitRange> splitRanges ) {
         super(objectNode);
         this.elements = elements;
+        this.splitRanges = splitRanges;
     }
 
     @Override
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        return Acceptor.accept(this, visitor);
+    }
+
+    @Override
+    public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterObjectNode(this)) {
-            return visitor.leaveObjectNode(setElements(Node.accept(visitor, elements)));
+            return visitor.leaveObjectNode(setElements(lc, Node.accept(visitor, elements)));
         }
-
         return this;
     }
 
@@ -102,10 +114,35 @@
         return Collections.unmodifiableList(elements);
     }
 
-    private ObjectNode setElements(final List<PropertyNode> elements) {
+    private ObjectNode setElements(final LexicalContext lc, final List<PropertyNode> elements) {
         if (this.elements == elements) {
             return this;
         }
-        return new ObjectNode(this, elements);
+        return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, this.splitRanges));
     }
+
+    /**
+     * Set the split ranges for this ObjectNode
+     * @see Splittable.SplitRange
+     * @param lc the lexical context
+     * @param splitRanges list of split ranges
+     * @return new or changed object node
+     */
+    public ObjectNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
+        if (this.splitRanges == splitRanges) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, splitRanges));
+    }
+
+    /**
+     * Get the split ranges for this ObjectNode, or null if the object is not split.
+     * @see Splittable.SplitRange
+     * @return list of split ranges
+     */
+    @Override
+    public List<Splittable.SplitRange> getSplitRanges() {
+        return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/Splittable.java	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, 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.io.Serializable;
+import java.util.List;
+import jdk.nashorn.internal.codegen.CompileUnit;
+
+/**
+ * An interface for splittable expressions.
+ */
+public interface Splittable {
+
+    /**
+     * Get a list of split ranges for this splittable expression, or null
+     * if the expression should not be split.
+     *
+     * @return a list of split ranges
+     */
+    List<SplitRange> getSplitRanges();
+
+    /**
+     * A SplitRange is a range in a splittable expression. It defines the
+     * boundaries of the split range and provides a compile unit for code generation.
+     */
+    final class SplitRange implements CompileUnitHolder, Serializable {
+        private static final long serialVersionUID = 1L;
+
+        /** Compile unit associated with the postsets range. */
+        private final CompileUnit compileUnit;
+
+        /** postsets range associated with the unit (hi not inclusive). */
+        private final int low, high;
+
+        /**
+         * Constructor
+         * @param compileUnit compile unit
+         * @param low lowest array index in unit
+         * @param high highest array index in unit + 1
+         */
+        public SplitRange(final CompileUnit compileUnit, final int low, final int high) {
+            this.compileUnit = compileUnit;
+            this.low   = low;
+            this.high   = high;
+        }
+
+        /**
+         * Get the high index position of the ArrayUnit (exclusive)
+         * @return high index position
+         */
+        public int getHigh() {
+            return high;
+        }
+
+        /**
+         * Get the low index position of the ArrayUnit (inclusive)
+         * @return low index position
+         */
+        public int getLow() {
+            return low;
+        }
+
+        /**
+         * The array compile unit
+         * @return array compile unit
+         */
+        @Override
+        public CompileUnit getCompileUnit() {
+            return compileUnit;
+        }
+    }
+}
--- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Tue Oct 06 11:04:55 2015 -0700
@@ -48,7 +48,6 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
@@ -65,7 +64,7 @@
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.parser.JSONParser;
 import jdk.nashorn.internal.parser.Lexer.RegexToken;
 import jdk.nashorn.internal.parser.Parser;
@@ -77,7 +76,7 @@
 /**
  * This IR writer produces a JSON string that represents AST as a JSON string.
  */
-public final class JSONWriter extends NodeVisitor<LexicalContext> {
+public final class JSONWriter extends SimpleNodeVisitor {
 
     /**
      * Returns AST as JSON compatible string.
@@ -939,7 +938,6 @@
     // Internals below
 
     private JSONWriter(final boolean includeLocation) {
-        super(new LexicalContext());
         this.buf             = new StringBuilder();
         this.includeLocation = includeLocation;
     }
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Tue Oct 06 11:04:55 2015 -0700
@@ -41,7 +41,6 @@
 import jdk.nashorn.internal.ir.JoinPredecessor;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LocalVariableConversion;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.SplitNode;
@@ -53,7 +52,7 @@
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 
 /**
  * Print out the AST as human readable source code.
@@ -61,7 +60,7 @@
  *
  * see the flags --print-parse and --print-lower-parse
  */
-public final class PrintVisitor extends NodeVisitor<LexicalContext> {
+public final class PrintVisitor extends SimpleNodeVisitor {
     /** Tab width */
     private static final int TABWIDTH = 4;
 
@@ -96,7 +95,6 @@
      * @param printTypes        should we print optimistic and inferred types?
      */
     public PrintVisitor(final boolean printLineNumbers, final boolean printTypes) {
-        super(new LexicalContext());
         this.EOLN             = System.lineSeparator();
         this.sb               = new StringBuilder();
         this.printLineNumbers = printLineNumbers;
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue Oct 06 11:04:55 2015 -0700
@@ -34,7 +34,7 @@
  * Like NodeVisitor but navigating further into operators.
  * @param <T> Lexical context class for this NodeOperatorVisitor
  */
-public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T> {
+public abstract class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T> {
     /**
      * Constructor
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/ir/visitor/SimpleNodeVisitor.java	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 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.visitor;
+
+import jdk.nashorn.internal.ir.LexicalContext;
+
+/**
+ * Convenience base class for a {@link NodeVisitor} with a plain {@link LexicalContext}.
+ */
+public abstract class SimpleNodeVisitor extends NodeVisitor<LexicalContext> {
+
+    /**
+     * Creates a new simple node visitor.
+     */
+    public SimpleNodeVisitor() {
+        super(new LexicalContext());
+    }
+}
--- a/src/jdk/nashorn/internal/objects/Global.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/Global.java	Tue Oct 06 11:04:55 2015 -0700
@@ -928,8 +928,6 @@
     private ThreadLocal<ScriptContext> scontext;
     // current ScriptEngine associated - can be null.
     private ScriptEngine engine;
-    // initial ScriptContext - can be null
-    private volatile ScriptContext initscontext;
 
     // ES6 global lexical scope.
     private final LexicalScope lexicalScope;
@@ -957,7 +955,7 @@
 
     private ScriptContext currentContext() {
         final ScriptContext sc = scontext != null? scontext.get() : null;
-        return sc == null? initscontext : sc;
+        return (sc != null)? sc : (engine != null? engine.getContext() : null);
     }
 
     @Override
@@ -1067,16 +1065,14 @@
      * of the global scope object.
      *
      * @param eng ScriptEngine to initialize
-     * @param ctxt ScriptContext to initialize
      */
-    public void initBuiltinObjects(final ScriptEngine eng, final ScriptContext ctxt) {
+    public void initBuiltinObjects(final ScriptEngine eng) {
         if (this.builtinObject != null) {
             // already initialized, just return
             return;
         }
 
         this.engine = eng;
-        this.initscontext = ctxt;
         if (this.engine != null) {
             this.scontext = new ThreadLocal<>();
         }
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Tue Oct 06 11:04:55 2015 -0700
@@ -627,7 +627,7 @@
                     return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
                             func.createBound(this, new Object[] { name })), 0, Object.class),
                             testJSAdaptor(adaptee, null, null, null),
-                            adaptee.getProtoSwitchPoint(__call__, find.getOwner()));
+                            adaptee.getProtoSwitchPoints(__call__, find.getOwner()), null);
                 }
             }
             throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
@@ -698,7 +698,7 @@
                     return new GuardedInvocation(
                             methodHandle,
                             testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func),
-                            adaptee.getProtoSwitchPoint(hook, findData.getOwner()));
+                            adaptee.getProtoSwitchPoints(hook, findData.getOwner()), null);
                 }
              }
         }
@@ -710,7 +710,7 @@
             final MethodHandle methodHandle = hook.equals(__put__) ?
             MH.asType(Lookup.EMPTY_SETTER, type) :
             Lookup.emptyGetter(type.returnType());
-            return new GuardedInvocation(methodHandle, testJSAdaptor(adaptee, null, null, null), adaptee.getProtoSwitchPoint(hook, null));
+            return new GuardedInvocation(methodHandle, testJSAdaptor(adaptee, null, null, null), adaptee.getProtoSwitchPoints(hook, null), null);
         }
     }
 
--- a/src/jdk/nashorn/internal/objects/NativeNumber.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeNumber.java	Tue Oct 06 11:04:55 2015 -0700
@@ -33,6 +33,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.math.RoundingMode;
 import java.text.NumberFormat;
 import java.util.Locale;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -187,6 +188,7 @@
         format.setMinimumFractionDigits(fractionDigits);
         format.setMaximumFractionDigits(fractionDigits);
         format.setGroupingUsed(false);
+        format.setRoundingMode(RoundingMode.HALF_UP);
 
         return format.format(x);
     }
--- a/src/jdk/nashorn/internal/runtime/AllocationStrategy.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/AllocationStrategy.java	Tue Oct 06 11:04:55 2015 -0700
@@ -29,6 +29,7 @@
 import java.io.Serializable;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.ref.WeakReference;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
@@ -53,6 +54,9 @@
     /** lazily generated allocator */
     private transient MethodHandle allocator;
 
+    /** Last used allocator map */
+    private transient AllocatorMap lastMap;
+
     /**
      * Construct an allocation strategy with the given map and class name.
      * @param fieldCount number of fields in the allocated object
@@ -71,11 +75,49 @@
         return allocatorClassName;
     }
 
-    PropertyMap getAllocatorMap() {
-        // Create a new map for each function instance
-        return PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
+    /**
+     * Get the property map for the allocated object.
+     * @param prototype the prototype object
+     * @return the property map
+     */
+    synchronized PropertyMap getAllocatorMap(final ScriptObject prototype) {
+        assert prototype != null;
+        final PropertyMap protoMap = prototype.getMap();
+
+        if (lastMap != null) {
+            if (!lastMap.hasSharedProtoMap()) {
+                if (lastMap.hasSamePrototype(prototype)) {
+                    return lastMap.allocatorMap;
+                }
+                if (lastMap.hasSameProtoMap(protoMap) && lastMap.hasUnchangedProtoMap()) {
+                    // Convert to shared prototype map. Allocated objects will use the same property map
+                    // that can be used as long as none of the prototypes modify the shared proto map.
+                    final PropertyMap allocatorMap = PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
+                    final SharedPropertyMap sharedProtoMap = new SharedPropertyMap(protoMap);
+                    allocatorMap.setSharedProtoMap(sharedProtoMap);
+                    prototype.setMap(sharedProtoMap);
+                    lastMap = new AllocatorMap(prototype, protoMap, allocatorMap);
+                    return allocatorMap;
+                }
+            }
+
+            if (lastMap.hasValidSharedProtoMap() && lastMap.hasSameProtoMap(protoMap)) {
+                prototype.setMap(lastMap.getSharedProtoMap());
+                return lastMap.allocatorMap;
+            }
+        }
+
+        final PropertyMap allocatorMap = PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
+        lastMap = new AllocatorMap(prototype, protoMap, allocatorMap);
+
+        return allocatorMap;
     }
 
+    /**
+     * Allocate an object with the given property map
+     * @param map the property map
+     * @return the allocated object
+     */
     ScriptObject allocate(final PropertyMap map) {
         try {
             if (allocator == null) {
@@ -94,4 +136,43 @@
     public String toString() {
         return "AllocationStrategy[fieldCount=" + fieldCount + "]";
     }
+
+    static class AllocatorMap {
+        final private WeakReference<ScriptObject> prototype;
+        final private WeakReference<PropertyMap> prototypeMap;
+
+        private PropertyMap allocatorMap;
+
+        AllocatorMap(final ScriptObject prototype, final PropertyMap protoMap, final PropertyMap allocMap) {
+            this.prototype = new WeakReference<>(prototype);
+            this.prototypeMap = new WeakReference<>(protoMap);
+            this.allocatorMap = allocMap;
+        }
+
+        boolean hasSamePrototype(final ScriptObject proto) {
+            return prototype.get() == proto;
+        }
+
+        boolean hasSameProtoMap(final PropertyMap protoMap) {
+            return prototypeMap.get() == protoMap || allocatorMap.getSharedProtoMap() == protoMap;
+        }
+
+        boolean hasUnchangedProtoMap() {
+            final ScriptObject proto = prototype.get();
+            return proto != null && proto.getMap() == prototypeMap.get();
+        }
+
+        boolean hasSharedProtoMap() {
+            return getSharedProtoMap() != null;
+        }
+
+        boolean hasValidSharedProtoMap() {
+            return hasSharedProtoMap() && getSharedProtoMap().isValidSharedProtoMap();
+        }
+
+        PropertyMap getSharedProtoMap() {
+            return allocatorMap.getSharedProtoMap();
+        }
+
+    }
 }
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java	Tue Oct 06 11:04:55 2015 -0700
@@ -38,15 +38,14 @@
  * The compiler still retains most of the state around code emission
  * and management internally, so this is to avoid passing around any
  * logic that isn't directly related to installing a class
- * @param <T> owner class type for this code installer
  *
  */
-public interface CodeInstaller<T> {
+public interface CodeInstaller {
     /**
-     * Return the owner for the CodeInstaller, e.g. a {@link Context}
-     * @return owner
+     * Return the {@link Context} associated with this code installer.
+     * @return the context.
      */
-    public T getOwner();
+    public Context getContext();
 
     /**
      * Install a class.
@@ -106,7 +105,7 @@
      * new, independent class loader.
      * @return a new code installer with a new independent class loader.
      */
-    public CodeInstaller<T> withNewLoader();
+    public CodeInstaller withNewLoader();
 
     /**
      * Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
@@ -115,6 +114,6 @@
      * @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);
+    public boolean isCompatibleWith(CodeInstaller other);
 
 }
--- a/src/jdk/nashorn/internal/runtime/Context.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/Context.java	Tue Oct 06 11:04:55 2015 -0700
@@ -167,7 +167,7 @@
      * ContextCodeInstaller that has the privilege of installing classes in the Context.
      * Can only be instantiated from inside the context and is opaque to other classes
      */
-    public static class ContextCodeInstaller implements CodeInstaller<ScriptEnvironment> {
+    public static class ContextCodeInstaller implements CodeInstaller {
         private final Context      context;
         private final ScriptLoader loader;
         private final CodeSource   codeSource;
@@ -185,13 +185,9 @@
             this.codeSource = codeSource;
         }
 
-        /**
-         * Return the script environment for this installer
-         * @return ScriptEnvironment
-         */
         @Override
-        public ScriptEnvironment getOwner() {
-            return context.env;
+        public Context getContext() {
+            return context;
         }
 
         @Override
@@ -254,7 +250,7 @@
         }
 
         @Override
-        public CodeInstaller<ScriptEnvironment> withNewLoader() {
+        public CodeInstaller withNewLoader() {
             // Reuse this installer if we're within our limits.
             if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
                 return this;
@@ -263,7 +259,7 @@
         }
 
         @Override
-        public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) {
+        public boolean isCompatibleWith(final CodeInstaller other) {
             if (other instanceof ContextCodeInstaller) {
                 final ContextCodeInstaller cci = (ContextCodeInstaller)other;
                 return cci.context == context && cci.codeSource == codeSource;
@@ -987,6 +983,16 @@
     }
 
     /**
+     * Is {@code className} the name of a structure class?
+     *
+     * @param className a class name
+     * @return true if className is a structure class name
+     */
+    public static boolean isStructureClass(final String className) {
+        return StructureLoader.isStructureClass(className);
+    }
+
+    /**
      * Checks that the given Class can be accessed from no permissions context.
      *
      * @param clazz Class object
@@ -1129,17 +1135,16 @@
      *
      * @param global the global
      * @param engine the associated ScriptEngine instance, can be null
-     * @param ctxt the initial ScriptContext, can be null
      * @return the initialized global scope object.
      */
-    public Global initGlobal(final Global global, final ScriptEngine engine, final ScriptContext ctxt) {
+    public Global initGlobal(final Global global, final ScriptEngine engine) {
         // Need only minimal global object, if we are just compiling.
         if (!env._compile_only) {
             final Global oldGlobal = Context.getGlobal();
             try {
                 Context.setGlobal(global);
                 // initialize global scope with builtin global objects
-                global.initBuiltinObjects(engine, ctxt);
+                global.initBuiltinObjects(engine);
             } finally {
                 Context.setGlobal(oldGlobal);
             }
@@ -1155,7 +1160,7 @@
      * @return the initialized global scope object.
      */
     public Global initGlobal(final Global global) {
-        return initGlobal(global, null, null);
+        return initGlobal(global, null);
     }
 
     /**
@@ -1300,14 +1305,12 @@
         final URL          url    = source.getURL();
         final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
-        final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
+        final CodeInstaller installer = new ContextCodeInstaller(this, loader, cs);
 
         if (storedScript == null) {
             final CompilationPhases phases = Compiler.CompilationPhases.COMPILE_ALL;
 
-            final Compiler compiler = new Compiler(
-                    this,
-                    env,
+            final Compiler compiler = Compiler.forInitialCompilation(
                     installer,
                     source,
                     errMan,
--- a/src/jdk/nashorn/internal/runtime/Debug.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/Debug.java	Tue Oct 06 11:04:55 2015 -0700
@@ -26,6 +26,8 @@
 package jdk.nashorn.internal.runtime;
 
 import static jdk.nashorn.internal.parser.TokenType.EOF;
+
+import jdk.nashorn.api.scripting.NashornException;
 import jdk.nashorn.internal.parser.Lexer;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenStream;
@@ -63,6 +65,15 @@
     }
 
     /**
+     * Return a formatted script stack trace string with frames information separated by '\n'.
+     * This is a shortcut for {@code NashornException.getScriptStackString(new Throwable())}.
+     * @return formatted stack trace string
+     */
+    public static String scriptStack() {
+        return NashornException.getScriptStackString(new Throwable());
+    }
+
+    /**
      * Return the system identity hashcode for an object as a human readable
      * string
      *
--- a/src/jdk/nashorn/internal/runtime/PropertyListeners.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/PropertyListeners.java	Tue Oct 06 11:04:55 2015 -0700
@@ -75,16 +75,20 @@
     }
 
     /**
-     * Return listeners added to this ScriptObject.
+     * Return number of listeners added to a ScriptObject.
      * @param obj the object
      * @return the listener count
      */
     public static int getListenerCount(final ScriptObject obj) {
-        final PropertyListeners propertyListeners = obj.getMap().getListeners();
-        if (propertyListeners != null) {
-            return propertyListeners.listeners == null ? 0 : propertyListeners.listeners.size();
-        }
-        return 0;
+        return obj.getMap().getListenerCount();
+    }
+
+    /**
+     * Return the number of listeners added to this PropertyListeners instance.
+     * @return the listener count;
+     */
+    public int getListenerCount() {
+        return listeners == null ? 0 : listeners.size();
     }
 
     // Property listener management methods
@@ -156,7 +160,7 @@
             final WeakPropertyMapSet set = listeners.get(prop.getKey());
             if (set != null) {
                 for (final PropertyMap propertyMap : set.elements()) {
-                    propertyMap.propertyAdded(prop);
+                    propertyMap.propertyAdded(prop, false);
                 }
                 listeners.remove(prop.getKey());
                 if (Context.DEBUG) {
@@ -176,7 +180,7 @@
             final WeakPropertyMapSet set = listeners.get(prop.getKey());
             if (set != null) {
                 for (final PropertyMap propertyMap : set.elements()) {
-                    propertyMap.propertyDeleted(prop);
+                    propertyMap.propertyDeleted(prop, false);
                 }
                 listeners.remove(prop.getKey());
                 if (Context.DEBUG) {
@@ -198,7 +202,7 @@
             final WeakPropertyMapSet set = listeners.get(oldProp.getKey());
             if (set != null) {
                 for (final PropertyMap propertyMap : set.elements()) {
-                    propertyMap.propertyModified(oldProp, newProp);
+                    propertyMap.propertyModified(oldProp, newProp, false);
                 }
                 listeners.remove(oldProp.getKey());
                 if (Context.DEBUG) {
@@ -215,7 +219,7 @@
         if (listeners != null) {
             for (final WeakPropertyMapSet set : listeners.values()) {
                 for (final PropertyMap propertyMap : set.elements()) {
-                    propertyMap.protoChanged();
+                    propertyMap.protoChanged(false);
                 }
             }
             listeners.clear();
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Tue Oct 06 11:04:55 2015 -0700
@@ -34,7 +34,9 @@
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.lang.invoke.SwitchPoint;
+import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collection;
@@ -43,6 +45,7 @@
 import java.util.NoSuchElementException;
 import java.util.WeakHashMap;
 import java.util.concurrent.atomic.LongAdder;
+import jdk.nashorn.internal.runtime.options.Options;
 import jdk.nashorn.internal.scripts.JO;
 
 /**
@@ -54,35 +57,49 @@
  * All property maps are immutable. If a property is added, modified or removed, the mutator
  * will return a new map.
  */
-public final class PropertyMap implements Iterable<Object>, Serializable {
+public class PropertyMap implements Iterable<Object>, Serializable {
+    private static final int INITIAL_SOFT_REFERENCE_DERIVATION_LIMIT =
+            Math.max(0, Options.getIntProperty("nashorn.propertyMap.softReferenceDerivationLimit", 32));
+
     /** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
-    public static final int NOT_EXTENSIBLE        = 0b0000_0001;
+    private static final int NOT_EXTENSIBLE         = 0b0000_0001;
     /** Does this map contain valid array keys? */
-    public static final int CONTAINS_ARRAY_KEYS   = 0b0000_0010;
+    private static final int CONTAINS_ARRAY_KEYS    = 0b0000_0010;
 
     /** Map status flags. */
-    private int flags;
+    private final int flags;
 
     /** Map of properties. */
     private transient PropertyHashMap properties;
 
     /** Number of fields in use. */
-    private int fieldCount;
+    private final int fieldCount;
 
     /** Number of fields available. */
     private final int fieldMaximum;
 
     /** Length of spill in use. */
-    private int spillLength;
+    private final int spillLength;
 
     /** Structure class name */
-    private String className;
+    private final String className;
+
+    /**
+     * Countdown of number of times this property map has been derived from another property map. When it
+     * reaches zero, the property map will start using weak references instead of soft references to hold on
+     * to its history elements.
+     */
+    private final int softReferenceDerivationLimit;
+
+    /** A reference to the expected shared prototype property map. If this is set this
+     * property map should only be used if it the same as the actual prototype map. */
+    private transient SharedPropertyMap sharedProtoMap;
 
     /** {@link SwitchPoint}s for gets on inherited properties. */
-    private transient HashMap<String, SwitchPoint> protoGetSwitches;
+    private transient HashMap<String, SwitchPoint> protoSwitches;
 
     /** History of maps, used to limit map duplication. */
-    private transient WeakHashMap<Property, SoftReference<PropertyMap>> history;
+    private transient WeakHashMap<Property, Reference<PropertyMap>> history;
 
     /** History of prototypes, used to limit map duplication. */
     private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory;
@@ -95,24 +112,22 @@
     private static final long serialVersionUID = -7041836752008732533L;
 
     /**
-     * Constructor.
+     * Constructs a new property map.
      *
      * @param properties   A {@link PropertyHashMap} with initial contents.
      * @param fieldCount   Number of fields in use.
      * @param fieldMaximum Number of fields available.
      * @param spillLength  Number of spill slots used.
-     * @param containsArrayKeys True if properties contain numeric keys
      */
-    private PropertyMap(final PropertyHashMap properties, final String className, final int fieldCount,
-                        final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) {
+    private PropertyMap(final PropertyHashMap properties, final int flags, final String className,
+                        final int fieldCount, final int fieldMaximum, final int spillLength) {
         this.properties   = properties;
         this.className    = className;
         this.fieldCount   = fieldCount;
         this.fieldMaximum = fieldMaximum;
         this.spillLength  = spillLength;
-        if (containsArrayKeys) {
-            setContainsArrayKeys();
-        }
+        this.flags        = flags;
+        this.softReferenceDerivationLimit = INITIAL_SOFT_REFERENCE_DERIVATION_LIMIT;
 
         if (Context.DEBUG) {
             count.increment();
@@ -120,20 +135,23 @@
     }
 
     /**
-     * Cloning constructor.
+     * Constructs a clone of {@code propertyMap} with changed properties, flags, or boundaries.
      *
      * @param propertyMap Existing property map.
      * @param properties  A {@link PropertyHashMap} with a new set of properties.
      */
-    private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) {
+    private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties, final int flags, final int fieldCount, final int spillLength, final int softReferenceDerivationLimit) {
         this.properties   = properties;
-        this.flags        = propertyMap.flags;
-        this.spillLength  = propertyMap.spillLength;
-        this.fieldCount   = propertyMap.fieldCount;
+        this.flags        = flags;
+        this.spillLength  = spillLength;
+        this.fieldCount   = fieldCount;
         this.fieldMaximum = propertyMap.fieldMaximum;
+        this.className    = propertyMap.className;
         // We inherit the parent property listeners instance. It will be cloned when a new listener is added.
         this.listeners    = propertyMap.listeners;
         this.freeSlots    = propertyMap.freeSlots;
+        this.sharedProtoMap = propertyMap.sharedProtoMap;
+        this.softReferenceDerivationLimit = softReferenceDerivationLimit;
 
         if (Context.DEBUG) {
             count.increment();
@@ -142,12 +160,12 @@
     }
 
     /**
-     * Cloning constructor.
+     * Constructs an exact clone of {@code propertyMap}.
      *
      * @param propertyMap Existing property map.
       */
-    private PropertyMap(final PropertyMap propertyMap) {
-        this(propertyMap, propertyMap.properties);
+    protected PropertyMap(final PropertyMap propertyMap) {
+        this(propertyMap, propertyMap.properties, propertyMap.flags, propertyMap.fieldCount, propertyMap.spillLength, propertyMap.softReferenceDerivationLimit);
     }
 
     private void writeObject(final ObjectOutputStream out) throws IOException {
@@ -183,7 +201,7 @@
      */
     public static PropertyMap newMap(final Collection<Property> properties, final String className, final int fieldCount, final int fieldMaximum,  final int spillLength) {
         final PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
-        return new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength, false);
+        return new PropertyMap(newProperties, 0, className, fieldCount, fieldMaximum, spillLength);
     }
 
     /**
@@ -205,7 +223,7 @@
      * @return New empty {@link PropertyMap}.
      */
     public static PropertyMap newMap(final Class<? extends ScriptObject> clazz) {
-        return new PropertyMap(EMPTY_HASHMAP, clazz.getName(), 0, 0, 0, false);
+        return new PropertyMap(EMPTY_HASHMAP, 0, clazz.getName(), 0, 0, 0);
     }
 
     /**
@@ -227,12 +245,12 @@
     }
 
     /**
-     * Get the listeners of this map, or null if none exists
+     * Get the number of listeners of this map
      *
-     * @return the listeners
+     * @return the number of listeners
      */
-    public PropertyListeners getListeners() {
-        return listeners;
+    public int getListenerCount() {
+        return listeners == null ? 0 : listeners.getListenerCount();
     }
 
     /**
@@ -253,9 +271,12 @@
      * A new property is being added.
      *
      * @param property The new Property added.
+     * @param isSelf was the property added to this map?
      */
-    public void propertyAdded(final Property property) {
-        invalidateProtoGetSwitchPoint(property);
+    public void propertyAdded(final Property property, final boolean isSelf) {
+        if (!isSelf) {
+            invalidateProtoSwitchPoint(property.getKey());
+        }
         if (listeners != null) {
             listeners.propertyAdded(property);
         }
@@ -265,9 +286,12 @@
      * An existing property is being deleted.
      *
      * @param property The property being deleted.
+     * @param isSelf was the property deleted from this map?
      */
-    public void propertyDeleted(final Property property) {
-        invalidateProtoGetSwitchPoint(property);
+    public void propertyDeleted(final Property property, final boolean isSelf) {
+        if (!isSelf) {
+            invalidateProtoSwitchPoint(property.getKey());
+        }
         if (listeners != null) {
             listeners.propertyDeleted(property);
         }
@@ -278,9 +302,12 @@
      *
      * @param oldProperty The old property
      * @param newProperty The new property
+     * @param isSelf was the property modified on this map?
      */
-    public void propertyModified(final Property oldProperty, final Property newProperty) {
-        invalidateProtoGetSwitchPoint(oldProperty);
+    public void propertyModified(final Property oldProperty, final Property newProperty, final boolean isSelf) {
+        if (!isSelf) {
+            invalidateProtoSwitchPoint(oldProperty.getKey());
+        }
         if (listeners != null) {
             listeners.propertyModified(oldProperty, newProperty);
         }
@@ -288,9 +315,15 @@
 
     /**
      * The prototype of an object associated with this {@link PropertyMap} is changed.
+     *
+     * @param isSelf was the prototype changed on the object using this map?
      */
-    public void protoChanged() {
-        invalidateAllProtoGetSwitchPoints();
+    public void protoChanged(final boolean isSelf) {
+        if (!isSelf) {
+            invalidateAllProtoSwitchPoints();
+        } else if (sharedProtoMap != null) {
+            sharedProtoMap.invalidateSwitchPoint();
+        }
         if (listeners != null) {
             listeners.protoChanged();
         }
@@ -303,14 +336,14 @@
      * @return A shared {@link SwitchPoint} for the property.
      */
     public synchronized SwitchPoint getSwitchPoint(final String key) {
-        if (protoGetSwitches == null) {
-            protoGetSwitches = new HashMap<>();
+        if (protoSwitches == null) {
+            protoSwitches = new HashMap<>();
         }
 
-        SwitchPoint switchPoint = protoGetSwitches.get(key);
+        SwitchPoint switchPoint = protoSwitches.get(key);
         if (switchPoint == null) {
             switchPoint = new SwitchPoint();
-            protoGetSwitches.put(key, switchPoint);
+            protoSwitches.put(key, switchPoint);
         }
 
         return switchPoint;
@@ -319,19 +352,17 @@
     /**
      * Indicate that a prototype property has changed.
      *
-     * @param property {@link Property} to invalidate.
+     * @param key {@link Property} key to invalidate.
      */
-    synchronized void invalidateProtoGetSwitchPoint(final Property property) {
-        if (protoGetSwitches != null) {
-
-            final String key = property.getKey();
-            final SwitchPoint sp = protoGetSwitches.get(key);
+    synchronized void invalidateProtoSwitchPoint(final String key) {
+        if (protoSwitches != null) {
+            final SwitchPoint sp = protoSwitches.get(key);
             if (sp != null) {
-                protoGetSwitches.remove(key);
+                protoSwitches.remove(key);
                 if (Context.DEBUG) {
                     protoInvalidations.increment();
                 }
-                SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+                SwitchPoint.invalidateAll(new SwitchPoint[]{sp});
             }
         }
     }
@@ -339,15 +370,15 @@
     /**
      * Indicate that proto itself has changed in hierarchy somewhere.
      */
-    synchronized void invalidateAllProtoGetSwitchPoints() {
-        if (protoGetSwitches != null) {
-            final int size = protoGetSwitches.size();
+    synchronized void invalidateAllProtoSwitchPoints() {
+        if (protoSwitches != null) {
+            final int size = protoSwitches.size();
             if (size > 0) {
                 if (Context.DEBUG) {
                     protoInvalidations.add(size);
                 }
-                SwitchPoint.invalidateAll(protoGetSwitches.values().toArray(new SwitchPoint[size]));
-                protoGetSwitches.clear();
+                SwitchPoint.invalidateAll(protoSwitches.values().toArray(new SwitchPoint[size]));
+                protoSwitches.clear();
             }
         }
     }
@@ -363,7 +394,7 @@
      * @return New {@link PropertyMap} with {@link Property} added.
      */
     PropertyMap addPropertyBind(final AccessorProperty property, final Object bindTo) {
-        // No need to store bound property in the history as bound properties can't be reused.
+        // We must not store bound property in the history as bound properties can't be reused.
         return addPropertyNoHistory(new AccessorProperty(property, bindTo));
     }
 
@@ -376,16 +407,16 @@
         return property.isSpill() ? slot + fieldMaximum : slot;
     }
 
-    // Update boundaries and flags after a property has been added
-    private void updateFlagsAndBoundaries(final Property newProperty) {
-        if(newProperty.isSpill()) {
-            spillLength = Math.max(spillLength, newProperty.getSlot() + 1);
-        } else {
-            fieldCount = Math.max(fieldCount, newProperty.getSlot() + 1);
-        }
-        if (isValidArrayIndex(getArrayIndex(newProperty.getKey()))) {
-            setContainsArrayKeys();
-        }
+    private int newSpillLength(final Property newProperty) {
+        return newProperty.isSpill() ? Math.max(spillLength, newProperty.getSlot() + 1) : spillLength;
+    }
+
+    private int newFieldCount(final Property newProperty) {
+        return !newProperty.isSpill() ? Math.max(fieldCount, newProperty.getSlot() + 1) : fieldCount;
+    }
+
+    private int newFlags(final Property newProperty) {
+        return isValidArrayIndex(getArrayIndex(newProperty.getKey())) ? flags | CONTAINS_ARRAY_KEYS : flags;
     }
 
     // Update the free slots bitmap for a property that has been deleted and/or added. This method is not synchronized
@@ -420,16 +451,9 @@
      * @param property {@link Property} being added.
      * @return New {@link PropertyMap} with {@link Property} added.
      */
-    public PropertyMap addPropertyNoHistory(final Property property) {
-        if (listeners != null) {
-            listeners.propertyAdded(property);
-        }
-        final PropertyHashMap newProperties = properties.immutableAdd(property);
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
-        newMap.updateFlagsAndBoundaries(property);
-        newMap.updateFreeSlots(null, property);
-
-        return newMap;
+    public final PropertyMap addPropertyNoHistory(final Property property) {
+        propertyAdded(property, true);
+        return addPropertyInternal(property);
     }
 
     /**
@@ -439,23 +463,29 @@
      *
      * @return New {@link PropertyMap} with {@link Property} added.
      */
-    public synchronized PropertyMap addProperty(final Property property) {
-        if (listeners != null) {
-            listeners.propertyAdded(property);
-        }
+    public final synchronized PropertyMap addProperty(final Property property) {
+        propertyAdded(property, true);
         PropertyMap newMap = checkHistory(property);
 
         if (newMap == null) {
-            final PropertyHashMap newProperties = properties.immutableAdd(property);
-            newMap = new PropertyMap(this, newProperties);
-            newMap.updateFlagsAndBoundaries(property);
-            newMap.updateFreeSlots(null, property);
+            newMap = addPropertyInternal(property);
             addToHistory(property, newMap);
         }
 
         return newMap;
     }
 
+    private PropertyMap deriveMap(final PropertyHashMap newProperties, final int newFlags, final int newFieldCount, final int newSpillLength) {
+        return new PropertyMap(this, newProperties, newFlags, newFieldCount, newSpillLength, softReferenceDerivationLimit == 0 ? 0 : softReferenceDerivationLimit - 1);
+    }
+
+    private PropertyMap addPropertyInternal(final Property property) {
+        final PropertyHashMap newProperties = properties.immutableAdd(property);
+        final PropertyMap newMap = deriveMap(newProperties, newFlags(property), newFieldCount(property), newSpillLength(property));
+        newMap.updateFreeSlots(null, property);
+        return newMap;
+    }
+
     /**
      * Remove a property from a map. Cloning or using an existing map if available.
      *
@@ -463,10 +493,8 @@
      *
      * @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found.
      */
-    public synchronized PropertyMap deleteProperty(final Property property) {
-        if (listeners != null) {
-            listeners.propertyDeleted(property);
-        }
+    public final synchronized PropertyMap deleteProperty(final Property property) {
+        propertyDeleted(property, true);
         PropertyMap newMap = checkHistory(property);
         final String key = property.getKey();
 
@@ -477,13 +505,13 @@
             // If deleted property was last field or spill slot we can make it reusable by reducing field/slot count.
             // Otherwise mark it as free in free slots bitset.
             if (isSpill && slot >= 0 && slot == spillLength - 1) {
-                newMap = new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength - 1, containsArrayKeys());
+                newMap = deriveMap(newProperties, flags, fieldCount, spillLength - 1);
                 newMap.freeSlots = freeSlots;
             } else if (!isSpill && slot >= 0 && slot == fieldCount - 1) {
-                newMap = new PropertyMap(newProperties, className, fieldCount - 1, fieldMaximum, spillLength, containsArrayKeys());
+                newMap = deriveMap(newProperties, flags, fieldCount - 1, spillLength);
                 newMap.freeSlots = freeSlots;
             } else {
-                newMap = new PropertyMap(this, newProperties);
+                newMap = deriveMap(newProperties, flags, fieldCount, spillLength);
                 newMap.updateFreeSlots(property, null);
             }
             addToHistory(property, newMap);
@@ -500,13 +528,8 @@
      *
      * @return New {@link PropertyMap} with {@link Property} replaced.
      */
-    public PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) {
-        if (listeners != null) {
-            listeners.propertyModified(oldProperty, newProperty);
-        }
-        // Add replaces existing property.
-        final PropertyHashMap newProperties = properties.immutableReplace(oldProperty, newProperty);
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
+    public final PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) {
+        propertyModified(oldProperty, newProperty, true);
         /*
          * See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods.
          *
@@ -528,14 +551,17 @@
                 newProperty instanceof UserAccessorProperty :
             "arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getLocalType() + " => " + newProperty.getLocalType() + "]";
 
-        newMap.flags = flags;
-
         /*
          * spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need
          * to add spill count of the newly added UserAccessorProperty property.
          */
+        final int newSpillLength = sameType ? spillLength : Math.max(spillLength, newProperty.getSlot() + 1);
+
+        // Add replaces existing property.
+        final PropertyHashMap newProperties = properties.immutableReplace(oldProperty, newProperty);
+        final PropertyMap newMap = deriveMap(newProperties, flags, fieldCount, newSpillLength);
+
         if (!sameType) {
-            newMap.spillLength = Math.max(spillLength, newProperty.getSlot() + 1);
             newMap.updateFreeSlots(oldProperty, newProperty);
         }
         return newMap;
@@ -551,7 +577,7 @@
      * @param propertyFlags attribute flags of the property
      * @return the newly created UserAccessorProperty
      */
-    public UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
+    public final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
         return new UserAccessorProperty(key, propertyFlags, getFreeSpillSlot());
     }
 
@@ -562,7 +588,7 @@
      *
      * @return {@link Property} matching key.
      */
-    public Property findProperty(final String key) {
+    public final Property findProperty(final String key) {
         return properties.find(key);
     }
 
@@ -573,12 +599,12 @@
      *
      * @return New {@link PropertyMap} with added properties.
      */
-    public PropertyMap addAll(final PropertyMap other) {
+    public final PropertyMap addAll(final PropertyMap other) {
         assert this != other : "adding property map to itself";
         final Property[] otherProperties = other.properties.getProperties();
         final PropertyHashMap newProperties = properties.immutableAdd(otherProperties);
 
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
+        final PropertyMap newMap = deriveMap(newProperties, flags, fieldCount, spillLength);
         for (final Property property : otherProperties) {
             // This method is only safe to use with non-slotted, native getter/setter properties
             assert property.getSlot() == -1;
@@ -593,19 +619,26 @@
      *
      * @return Properties as an array.
      */
-    public Property[] getProperties() {
+    public final Property[] getProperties() {
         return properties.getProperties();
     }
 
     /**
+     * Return the name of the class of objects using this property map.
+     *
+     * @return class name of owner objects.
+     */
+    public final String getClassName() {
+        return className;
+    }
+
+    /**
      * Prevents the map from having additional properties.
      *
      * @return New map with {@link #NOT_EXTENSIBLE} flag set.
      */
     PropertyMap preventExtensions() {
-        final PropertyMap newMap = new PropertyMap(this);
-        newMap.flags |= NOT_EXTENSIBLE;
-        return newMap;
+        return deriveMap(properties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
     }
 
     /**
@@ -621,10 +654,7 @@
             newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE));
         }
 
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
-        newMap.flags |= NOT_EXTENSIBLE;
-
-        return newMap;
+        return deriveMap(newProperties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
     }
 
     /**
@@ -646,10 +676,7 @@
             newProperties = newProperties.immutableAdd(oldProperty.addFlags(propertyFlags));
         }
 
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
-        newMap.flags |= NOT_EXTENSIBLE;
-
-        return newMap;
+        return deriveMap(newProperties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
     }
 
     /**
@@ -736,7 +763,7 @@
             history = new WeakHashMap<>();
         }
 
-        history.put(property, new SoftReference<>(newMap));
+        history.put(property, softReferenceDerivationLimit == 0 ? new WeakReference<>(newMap) : new SoftReference<>(newMap));
     }
 
     /**
@@ -749,7 +776,7 @@
     private PropertyMap checkHistory(final Property property) {
 
         if (history != null) {
-            final SoftReference<PropertyMap> ref = history.get(property);
+            final Reference<PropertyMap> ref = history.get(property);
             final PropertyMap historicMap = ref == null ? null : ref.get();
 
             if (historicMap != null) {
@@ -821,13 +848,6 @@
     }
 
     /**
-     * Flag this object as having array keys in defined properties
-     */
-    private void setContainsArrayKeys() {
-        flags |= CONTAINS_ARRAY_KEYS;
-    }
-
-    /**
      * Test to see if {@link PropertyMap} is extensible.
      *
      * @return {@code true} if {@link PropertyMap} can be added to.
@@ -905,12 +925,72 @@
             setProtoNewMapCount.increment();
         }
 
-        final PropertyMap newMap = new PropertyMap(this);
+        final PropertyMap newMap = makeUnsharedCopy();
         addToProtoHistory(newProto, newMap);
 
         return newMap;
     }
 
+    /**
+     * Make a copy of this property map with the shared prototype field set to null. Note that this is
+     * only necessary for shared maps of top-level objects. Shared prototype maps represented by
+     * {@link SharedPropertyMap} are automatically converted to plain property maps when they evolve.
+     *
+     * @return a copy with the shared proto map unset
+     */
+    PropertyMap makeUnsharedCopy() {
+        final PropertyMap newMap = new PropertyMap(this);
+        newMap.sharedProtoMap = null;
+        return newMap;
+    }
+
+    /**
+     * Set a reference to the expected parent prototype map. This is used for class-like
+     * structures where we only want to use a top-level property map if all of the
+     * prototype property maps have not been modified.
+     *
+     * @param protoMap weak reference to the prototype property map
+     */
+    void setSharedProtoMap(final SharedPropertyMap protoMap) {
+        sharedProtoMap = protoMap;
+    }
+
+    /**
+     * Get the expected prototype property map if it is known, or null.
+     *
+     * @return parent map or null
+     */
+    public PropertyMap getSharedProtoMap() {
+        return sharedProtoMap;
+    }
+
+    /**
+     * Returns {@code true} if this map has been used as a shared prototype map (i.e. as a prototype
+     * for a JavaScript constructor function) and has not had properties added, deleted or replaced since then.
+     * @return true if this is a valid shared prototype map
+     */
+    boolean isValidSharedProtoMap() {
+        return false;
+    }
+
+    /**
+     * Returns the shared prototype switch point, or null if this is not a shared prototype map.
+     * @return the shared prototype switch point, or null
+     */
+    SwitchPoint getSharedProtoSwitchPoint() {
+        return null;
+    }
+
+    /**
+     * Return true if this map has a shared prototype map which has either been invalidated or does
+     * not match the map of {@code proto}.
+     * @param prototype the prototype object
+     * @return true if this is an invalid shared map for {@code prototype}
+     */
+    boolean isInvalidSharedMapFor(final ScriptObject prototype) {
+        return sharedProtoMap != null
+                && (!sharedProtoMap.isValidSharedProtoMap() || prototype == null || sharedProtoMap != prototype.getMap());
+    }
 
     /**
      * {@link PropertyMap} iterator.
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -63,7 +63,7 @@
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TryNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.parser.Token;
@@ -120,7 +120,7 @@
     private final Object endParserState;
 
     /** Code installer used for all further recompilation/specialization of this ScriptFunction */
-    private transient CodeInstaller<ScriptEnvironment> installer;
+    private transient CodeInstaller installer;
 
     private final Map<Integer, RecompilableScriptFunctionData> nestedFunctions;
 
@@ -154,7 +154,7 @@
      */
     public RecompilableScriptFunctionData(
         final FunctionNode functionNode,
-        final CodeInstaller<ScriptEnvironment> installer,
+        final CodeInstaller installer,
         final AllocationStrategy allocationStrategy,
         final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
         final Map<String, Integer> externalScopeDepths,
@@ -286,7 +286,7 @@
      * @param src source
      * @param inst code installer
      */
-    public void initTransients(final Source src, final CodeInstaller<ScriptEnvironment> inst) {
+    public void initTransients(final Source src, final CodeInstaller inst) {
         if (this.source == null && this.installer == null) {
             this.source    = src;
             this.installer = inst;
@@ -369,8 +369,8 @@
     }
 
     @Override
-    PropertyMap getAllocatorMap() {
-        return allocationStrategy.getAllocatorMap();
+    PropertyMap getAllocatorMap(final ScriptObject prototype) {
+        return allocationStrategy.getAllocatorMap(prototype);
     }
 
     @Override
@@ -507,7 +507,7 @@
     }
 
     private FunctionNode deserialize(final byte[] serializedAst) {
-        final ScriptEnvironment env = installer.getOwner();
+        final ScriptEnvironment env = installer.getContext().getEnv();
         final Timing timing = env._timing;
         final long t1 = System.nanoTime();
         try {
@@ -525,7 +525,7 @@
         // don't cache non-split functions from the eager pass); those already cached, or those not split
         // don't need this step.
         final Set<Symbol> blockDefinedSymbols = fn.isSplit() && !cached ? Collections.newSetFromMap(new IdentityHashMap<Symbol, Boolean>()) : null;
-        FunctionNode newFn = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        FunctionNode newFn = (FunctionNode)fn.accept(new SimpleNodeVisitor() {
 
             private Symbol getReplacement(final Symbol original) {
                 if (original == null) {
@@ -654,8 +654,8 @@
      * 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();
+    private CodeInstaller getInstallerForNewCode() {
+        final ScriptEnvironment env = installer.getContext().getEnv();
         return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
     }
 
@@ -665,15 +665,10 @@
         final TypeMap typeMap = typeMap(actualCallSiteType);
         final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
         final Object typeInformationFile = OptimisticTypesPersistence.getLocationDescriptor(source, functionNodeId, paramTypes);
-        final Context context = Context.getContextTrusted();
-        return new Compiler(
-                context,
-                context.getEnv(),
+        return Compiler.forOnDemandCompilation(
                 getInstallerForNewCode(),
                 functionNode.getSource(),  // source
-                context.getErrorManager(),
                 isStrict() | functionNode.isStrict(), // is strict
-                true,       // is on demand
                 this,       // compiledFunction, i.e. this RecompilableScriptFunctionData
                 typeMap,    // type map
                 getEffectiveInvalidatedProgramPoints(invalidatedProgramPoints, typeInformationFile), // invalidated program points
@@ -716,7 +711,7 @@
             final TypeMap typeMap = typeMap(actualCallSiteType);
             final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
             cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
-            final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode();
+            final CodeInstaller newInstaller = getInstallerForNewCode();
             final StoredScript script = newInstaller.loadScript(source, cacheKey);
 
             if (script != null) {
@@ -737,7 +732,7 @@
     }
 
     boolean usePersistentCodeCache() {
-        return installer != null && installer.getOwner()._persistent_cache;
+        return installer != null && installer.getContext().getEnv()._persistent_cache;
     }
 
     private MethodType explicitParams(final MethodType callSiteType) {
@@ -769,7 +764,7 @@
 
     private FunctionNode extractFunctionFromScript(final FunctionNode script) {
         final Set<FunctionNode> fns = new HashSet<>();
-        script.getBody().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+        script.getBody().accept(new SimpleNodeVisitor() {
             @Override
             public boolean enterFunctionNode(final FunctionNode fn) {
                 fns.add(fn);
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Tue Oct 06 11:04:55 2015 -0700
@@ -521,35 +521,39 @@
 
         assert !isBoundFunction(); // allocate never invoked on bound functions
 
-        final ScriptObject object = data.allocate(getAllocatorMap());
+        final ScriptObject prototype = getAllocatorPrototype();
+        final ScriptObject object = data.allocate(getAllocatorMap(prototype));
 
         if (object != null) {
-            final Object prototype = getPrototype();
-            if (prototype instanceof ScriptObject) {
-                object.setInitialProto((ScriptObject) prototype);
-            }
-
-            if (object.getProto() == null) {
-                object.setInitialProto(getObjectPrototype());
-            }
+            object.setInitialProto(prototype);
         }
 
         return object;
     }
 
-    private PropertyMap getAllocatorMap() {
-        if (allocatorMap == null) {
-            allocatorMap = data.getAllocatorMap();
+    /**
+     * Get the property map used by "allocate"
+     * @param prototype actual prototype object
+     * @return property map
+     */
+    private synchronized PropertyMap getAllocatorMap(final ScriptObject prototype) {
+        if (allocatorMap == null || allocatorMap.isInvalidSharedMapFor(prototype)) {
+            // The prototype map has changed since this function was last used as constructor.
+            // Get a new allocator map.
+            allocatorMap = data.getAllocatorMap(prototype);
         }
         return allocatorMap;
     }
 
     /**
-     * Return Object.prototype - used by "allocate"
-     *
-     * @return Object.prototype
+     * Return the actual prototype used by "allocate"
+     * @return allocator prototype
      */
-    protected final ScriptObject getObjectPrototype() {
+    private ScriptObject getAllocatorPrototype() {
+        final Object prototype = getPrototype();
+        if (prototype instanceof ScriptObject) {
+            return (ScriptObject) prototype;
+        }
         return Global.objectPrototype();
     }
 
@@ -591,10 +595,10 @@
      *
      * @param newPrototype new prototype object
      */
-    public final void setPrototype(final Object newPrototype) {
+    public synchronized final void setPrototype(final Object newPrototype) {
         if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
-            // Replace our current allocator map with one that is associated with the new prototype.
-            allocatorMap = allocatorMap.changeProto((ScriptObject) newPrototype);
+            // Unset allocator map to be replaced with one matching the new prototype.
+            allocatorMap = null;
         }
         this.prototype = newPrototype;
     }
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -389,9 +389,10 @@
     /**
      * Get the property map to use for objects allocated by this function.
      *
+     * @param prototype the prototype of the allocated object
      * @return the property map for allocated objects.
      */
-    PropertyMap getAllocatorMap() {
+    PropertyMap getAllocatorMap(final ScriptObject prototype) {
         return null;
     }
 
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Oct 06 11:04:55 2015 -0700
@@ -710,8 +710,7 @@
         final long longIndex = ArrayIndex.toLongIndex(index);
         final long oldLength = getArray().length();
         if (longIndex >= oldLength) {
-            setArray(getArray().ensure(longIndex));
-            doesNotHaveEnsureDelete(longIndex, oldLength, false);
+            setArray(getArray().ensure(longIndex).safeDelete(oldLength, longIndex - 1, false));
         }
         setArray(getArray().set(index, value, false));
     }
@@ -809,9 +808,11 @@
 
         if (deep) {
             final ScriptObject myProto = getProto();
-            if (myProto != null) {
-                return myProto.findProperty(key, deep, start);
-            }
+            final FindProperty find = myProto == null ? null : myProto.findProperty(key, true, start);
+            // checkSharedProtoMap must be invoked after myProto.checkSharedProtoMap to propagate
+            // shared proto invalidation up the prototype chain. It also must be invoked when prototype is null.
+            checkSharedProtoMap();
+            return find;
         }
 
         return null;
@@ -832,7 +833,7 @@
         if (deep) {
             final ScriptObject myProto = getProto();
             if (myProto != null) {
-                return myProto.hasProperty(key, deep);
+                return myProto.hasProperty(key, true);
             }
         }
 
@@ -1258,11 +1259,8 @@
         if (oldProto != newProto) {
             proto = newProto;
 
-            // Let current listeners know that the prototype has changed and set our map
-            final PropertyListeners listeners = getMap().getListeners();
-            if (listeners != null) {
-                listeners.protoChanged();
-            }
+            // Let current listeners know that the prototype has changed
+            getMap().protoChanged(true);
             // Replace our current allocator map with one that is associated with the new prototype.
             setMap(getMap().changeProto(newProto));
         }
@@ -1314,7 +1312,7 @@
                 }
                 p = p.getProto();
             }
-            setProto((ScriptObject)newProto);
+            setProto((ScriptObject) newProto);
         } else {
             throw typeError("cant.set.proto.to.non.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(newProto));
         }
@@ -1997,11 +1995,11 @@
         final ScriptObject owner = find.getOwner();
         final Class<ClassCastException> exception = explicitInstanceOfCheck ? null : ClassCastException.class;
 
-        final SwitchPoint protoSwitchPoint;
+        final SwitchPoint[] protoSwitchPoints;
 
         if (mh == null) {
             mh = Lookup.emptyGetter(returnType);
-            protoSwitchPoint = getProtoSwitchPoint(name, owner);
+            protoSwitchPoints = getProtoSwitchPoints(name, owner);
         } else if (!find.isSelf()) {
             assert mh.type().returnType().equals(returnType) :
                     "return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
@@ -2009,12 +2007,12 @@
                 // Add a filter that replaces the self object with the prototype owning the property.
                 mh = addProtoFilter(mh, find.getProtoChainLength());
             }
-            protoSwitchPoint = getProtoSwitchPoint(name, owner);
+            protoSwitchPoints = getProtoSwitchPoints(name, owner);
         } else {
-            protoSwitchPoint = null;
+            protoSwitchPoints = null;
         }
 
-        final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
+        final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoints, exception);
         return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
     }
 
@@ -2113,17 +2111,32 @@
      * @param owner the property owner, null if property is not defined
      * @return a SwitchPoint or null
      */
-    public final SwitchPoint getProtoSwitchPoint(final String name, final ScriptObject owner) {
+    public final SwitchPoint[] getProtoSwitchPoints(final String name, final ScriptObject owner) {
         if (owner == this || getProto() == null) {
             return null;
         }
 
+        final List<SwitchPoint> switchPoints = new ArrayList<>();
         for (ScriptObject obj = this; obj != owner && obj.getProto() != null; obj = obj.getProto()) {
             final ScriptObject parent = obj.getProto();
             parent.getMap().addListener(name, obj.getMap());
+            final SwitchPoint sp = parent.getMap().getSharedProtoSwitchPoint();
+            if (sp != null && !sp.hasBeenInvalidated()) {
+                switchPoints.add(sp);
+            }
         }
 
-        return getMap().getSwitchPoint(name);
+        switchPoints.add(getMap().getSwitchPoint(name));
+        return switchPoints.toArray(new SwitchPoint[switchPoints.size()]);
+    }
+
+    private void checkSharedProtoMap() {
+        // Check if our map has an expected shared prototype property map. If it has, make sure that
+        // the prototype map has not been invalidated, and that it does match the actual map of the prototype.
+        if (getMap().isInvalidSharedMapFor(getProto())) {
+            // Change our own map to one that does not assume a shared prototype map.
+            setMap(getMap().makeUnsharedCopy());
+        }
     }
 
     /**
@@ -2205,7 +2218,7 @@
         return new GuardedInvocation(
                 Lookup.EMPTY_SETTER,
                 NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
-                getProtoSwitchPoint(name, null),
+                getProtoSwitchPoints(name, null),
                 explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
@@ -2351,7 +2364,7 @@
                                 find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
                                 find.getProtoChainLength(),
                                 func),
-                        getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
+                        getProtoSwitchPoints(NO_SUCH_PROPERTY_NAME, find.getOwner()),
                         //TODO this doesn't need a ClassCastException as guard always checks script object
                         null);
             }
@@ -2424,7 +2437,7 @@
         }
 
         return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()),
-                NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), getProtoSwitchPoint(name, null),
+                NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), getProtoSwitchPoints(name, null),
                 explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
@@ -2664,11 +2677,7 @@
         }
 
         if (newLength > arrayLength) {
-            data = data.ensure(newLength - 1);
-            if (data.canDelete(arrayLength, newLength - 1, false)) {
-               data = data.delete(arrayLength, newLength - 1);
-            }
-            setArray(data);
+            setArray(data.ensure(newLength - 1).safeDelete(arrayLength, newLength - 1, false));
             return;
         }
 
@@ -3089,23 +3098,12 @@
         return false;
     }
 
-    private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) {
-        if (longIndex > oldLength) {
-            ArrayData array = getArray();
-            if (array.canDelete(oldLength, longIndex - 1, strict)) {
-                array = array.delete(oldLength, longIndex - 1);
-            }
-            setArray(array);
-        }
-    }
-
     private void doesNotHave(final int index, final int value, final int callSiteFlags) {
         final long oldLength = getArray().length();
         final long longIndex = ArrayIndex.toLongIndex(index);
         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
             final boolean strict = isStrictFlag(callSiteFlags);
-            setArray(getArray().set(index, value, strict));
-            doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+            setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
         }
     }
 
@@ -3114,8 +3112,7 @@
         final long longIndex = ArrayIndex.toLongIndex(index);
         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
             final boolean strict = isStrictFlag(callSiteFlags);
-            setArray(getArray().set(index, value, strict));
-            doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+            setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
         }
     }
 
@@ -3124,8 +3121,7 @@
         final long longIndex = ArrayIndex.toLongIndex(index);
         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
             final boolean strict = isStrictFlag(callSiteFlags);
-            setArray(getArray().set(index, value, strict));
-            doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+            setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
         }
     }
 
@@ -3134,8 +3130,7 @@
         final long longIndex = ArrayIndex.toLongIndex(index);
         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
             final boolean strict = isStrictFlag(callSiteFlags);
-            setArray(getArray().set(index, value, strict));
-            doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+            setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -186,10 +186,7 @@
 
     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);
-        }
+        map.propertyAdded(sm.property, true);
         return sm;
     }
 
@@ -204,7 +201,7 @@
         //fast type specific setter
         final MethodHandle fastSetter = property.getSetter(type, newMap); //0 sobj, 1 value, slot folded for spill property already
 
-        //slow setter, that calls ScriptObject.set with appropraite type and key name
+        //slow setter, that calls ScriptObject.set with appropriate type and key name
         MethodHandle slowSetter = ScriptObject.SET_SLOW[getAccessorTypeIndex(type)];
         slowSetter = MH.insertArguments(slowSetter, 3, NashornCallSiteDescriptor.getFlags(desc));
         slowSetter = MH.insertArguments(slowSetter, 1, name);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/SharedPropertyMap.java	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, 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.SwitchPoint;
+
+/**
+ * This class represents a property map that can be shared among multiple prototype objects, allowing all inheriting
+ * top-level objects to also share one property map. This is class is only used for prototype objects, the
+ * top-level objects use ordinary {@link PropertyMap}s with the {@link PropertyMap#sharedProtoMap} field
+ * set to the expected shared prototype map.
+ *
+ * <p>When an instance of this class is evolved because a property is added, removed, or modified in an object
+ * using it, the {@link #invalidateSwitchPoint()} method is invoked to signal to all callsites and inheriting
+ * objects that the assumption of a single shared prototype map is no longer valid. The property map resulting
+ * from the modification will no longer be an instance of this class.</p>
+ */
+public final class SharedPropertyMap extends PropertyMap {
+
+    private SwitchPoint switchPoint;
+
+    private static final long serialVersionUID = 2166297719721778876L;
+
+    /**
+     * Create a new shared property map from the given {@code map}.
+     * @param map property map to copy
+     */
+    public SharedPropertyMap(final PropertyMap map) {
+        super(map);
+        this.switchPoint = new SwitchPoint();
+    }
+
+    @Override
+    public void propertyAdded(final Property property, final boolean isSelf) {
+        if (isSelf) {
+            invalidateSwitchPoint();
+        }
+        super.propertyAdded(property, isSelf);
+    }
+
+    @Override
+    public void propertyDeleted(final Property property, final boolean isSelf) {
+        if (isSelf) {
+            invalidateSwitchPoint();
+        }
+        super.propertyDeleted(property, isSelf);
+    }
+
+    @Override
+    public void propertyModified(final Property oldProperty, final Property newProperty, final boolean isSelf) {
+        if (isSelf) {
+            invalidateSwitchPoint();
+        }
+        super.propertyModified(oldProperty, newProperty, isSelf);
+    }
+
+    @Override
+    synchronized boolean isValidSharedProtoMap() {
+        return switchPoint != null;
+    }
+
+    @Override
+    synchronized SwitchPoint getSharedProtoSwitchPoint() {
+        return switchPoint;
+    }
+
+    /**
+     * Invalidate the shared prototype switch point if this is a shared prototype map.
+     */
+    synchronized void invalidateSwitchPoint() {
+        if (switchPoint != null) {
+            assert !switchPoint.hasBeenInvalidated();
+            SwitchPoint.invalidateAll(new SwitchPoint[]{ switchPoint });
+            switchPoint = null;
+        }
+    }
+}
--- a/src/jdk/nashorn/internal/runtime/StoredScript.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/StoredScript.java	Tue Oct 06 11:04:55 2015 -0700
@@ -77,7 +77,7 @@
         return compilationId;
     }
 
-    private Map<String, Class<?>> installClasses(final Source source, final CodeInstaller<ScriptEnvironment> installer) {
+    private Map<String, Class<?>> installClasses(final Source source, final CodeInstaller installer) {
         final Map<String, Class<?>> installedClasses = new HashMap<>();
         final byte[]   mainClassBytes = classBytes.get(mainClassName);
         final Class<?> mainClass      = installer.install(mainClassName, mainClassBytes);
@@ -96,7 +96,7 @@
         return installedClasses;
     }
 
-    FunctionInitializer installFunction(final RecompilableScriptFunctionData data, final CodeInstaller<ScriptEnvironment> installer) {
+    FunctionInitializer installFunction(final RecompilableScriptFunctionData data, final CodeInstaller installer) {
         final Map<String, Class<?>> installedClasses = installClasses(data.getSource(), installer);
 
         assert initializers != null;
@@ -124,7 +124,7 @@
      * @param installer the installer
      * @return main script class
      */
-    Class<?> installScript(final Source source, final CodeInstaller<ScriptEnvironment> installer) {
+    Class<?> installScript(final Source source, final CodeInstaller installer) {
 
         final Map<String, Class<?>> installedClasses = installClasses(source, installer);
 
--- a/src/jdk/nashorn/internal/runtime/WithObject.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/WithObject.java	Tue Oct 06 11:04:55 2015 -0700
@@ -46,7 +46,7 @@
  *
  */
 public final class WithObject extends Scope {
-    private static final MethodHandle WITHEXPRESSIONGUARD    = findOwnMH("withExpressionGuard",  boolean.class, Object.class, PropertyMap.class, SwitchPoint.class);
+    private static final MethodHandle WITHEXPRESSIONGUARD    = findOwnMH("withExpressionGuard",  boolean.class, Object.class, PropertyMap.class, SwitchPoint[].class);
     private static final MethodHandle WITHEXPRESSIONFILTER   = findOwnMH("withFilterExpression", Object.class, Object.class);
     private static final MethodHandle WITHSCOPEFILTER        = findOwnMH("withFilterScope",      Object.class, Object.class);
     private static final MethodHandle BIND_TO_EXPRESSION_OBJ = findOwnMH("bindToExpression",     Object.class, Object.class, Object.class);
@@ -360,13 +360,24 @@
 
     private MethodHandle expressionGuard(final String name, final ScriptObject owner) {
         final PropertyMap map = expression.getMap();
-        final SwitchPoint sp = expression.getProtoSwitchPoint(name, owner);
+        final SwitchPoint[] sp = expression.getProtoSwitchPoints(name, owner);
         return MH.insertArguments(WITHEXPRESSIONGUARD, 1, map, sp);
     }
 
     @SuppressWarnings("unused")
-    private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint sp) {
-        return ((WithObject)receiver).expression.getMap() == map && (sp == null || !sp.hasBeenInvalidated());
+    private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint[] sp) {
+        return ((WithObject)receiver).expression.getMap() == map && !hasBeenInvalidated(sp);
+    }
+
+    private static boolean hasBeenInvalidated(final SwitchPoint[] switchPoints) {
+        if (switchPoints != null) {
+            for (final SwitchPoint switchPoint : switchPoints) {
+                if (switchPoint.hasBeenInvalidated()) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -258,7 +258,7 @@
      * Factory method for unspecified array - start as int
      * @return ArrayData
      */
-    public final static ArrayData initialArray() {
+    public static ArrayData initialArray() {
         return new IntArrayData();
     }
 
@@ -278,7 +278,7 @@
      * @param size size required
      * @return size given, always &gt;= size
      */
-    protected final static int alignUp(final int size) {
+    protected static int alignUp(final int size) {
         return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
     }
 
@@ -288,7 +288,7 @@
      * @param length the initial length
      * @return ArrayData
      */
-    public static final ArrayData allocate(final int length) {
+    public static ArrayData allocate(final int length) {
         if (length == 0) {
             return new IntArrayData();
         } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
@@ -304,7 +304,7 @@
      * @param  array the array
      * @return ArrayData wrapping this array
      */
-    public static final ArrayData allocate(final Object array) {
+    public static ArrayData allocate(final Object array) {
         final Class<?> clazz = array.getClass();
 
         if (clazz == int[].class) {
@@ -324,7 +324,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static final ArrayData allocate(final int[] array) {
+    public static ArrayData allocate(final int[] array) {
          return new IntArrayData(array, array.length);
     }
 
@@ -334,7 +334,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static final ArrayData allocate(final long[] array) {
+    public static ArrayData allocate(final long[] array) {
         return new LongArrayData(array, array.length);
     }
 
@@ -344,7 +344,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static final ArrayData allocate(final double[] array) {
+    public static ArrayData allocate(final double[] array) {
         return new NumberArrayData(array, array.length);
     }
 
@@ -354,7 +354,7 @@
      * @param array the array to use for initial elements
      * @return the ArrayData
      */
-    public static final ArrayData allocate(final Object[] array) {
+    public static ArrayData allocate(final Object[] array) {
         return new ObjectArrayData(array, array.length);
     }
 
@@ -364,7 +364,7 @@
      * @param buf the nio ByteBuffer to wrap
      * @return the ArrayData
      */
-    public static final ArrayData allocate(final ByteBuffer buf) {
+    public static ArrayData allocate(final ByteBuffer buf) {
         return new ByteBufferArrayData(buf);
     }
 
@@ -374,7 +374,7 @@
      * @param underlying  the underlying ArrayData to wrap in the freeze filter
      * @return the frozen ArrayData
      */
-    public static final ArrayData freeze(final ArrayData underlying) {
+    public static ArrayData freeze(final ArrayData underlying) {
         return new FrozenArrayFilter(underlying);
     }
 
@@ -384,7 +384,7 @@
      * @param underlying  the underlying ArrayData to wrap in the seal filter
      * @return the sealed ArrayData
      */
-    public static final ArrayData seal(final ArrayData underlying) {
+    public static ArrayData seal(final ArrayData underlying) {
         return new SealedArrayFilter(underlying);
     }
 
@@ -394,7 +394,7 @@
      * @param  underlying the underlying ArrayData to wrap in the non extensible filter
      * @return new array data, filtered
      */
-    public static final ArrayData preventExtension(final ArrayData underlying) {
+    public static ArrayData preventExtension(final ArrayData underlying) {
         return new NonExtensibleArrayFilter(underlying);
     }
 
@@ -404,7 +404,7 @@
      * @param underlying the underlying ArrayDAta to wrap in the non extensible filter
      * @return new array data, filtered
      */
-    public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) {
+    public static ArrayData setIsLengthNotWritable(final ArrayData underlying) {
         return new LengthNotWritableFilter(underlying);
     }
 
@@ -676,19 +676,34 @@
     }
 
     /**
-     * Returns if element at specific index range can be deleted or not.
+     * Returns if element at specific index can be deleted or not.
      *
-     * @param fromIndex  the start index
-     * @param toIndex    the end index
+     * @param longIndex  the index
      * @param strict     are we in strict mode
      *
      * @return true if range can be deleted
      */
-    public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+    public boolean canDelete(final long longIndex, final boolean strict) {
         return true;
     }
 
     /**
+     * Delete a range from the array if {@code fromIndex} is less than or equal to {@code toIndex}
+     * and the array supports deletion.
+     *
+     * @param fromIndex  the start index (inclusive)
+     * @param toIndex    the end index (inclusive)
+     * @param strict     are we in strict mode
+     * @return an array with the range deleted, or this array if no deletion took place
+     */
+    public final ArrayData safeDelete(final long fromIndex, final long toIndex, final boolean strict) {
+        if (fromIndex <= toIndex && canDelete(fromIndex, strict)) {
+            return delete(fromIndex, toIndex);
+        }
+        return this;
+    }
+
+    /**
      * Returns property descriptor for element at a given index
      *
      * @param global the global object
--- a/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -164,7 +164,7 @@
     }
 
     @Override
-    public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+    public boolean canDelete(final long longIndex, final boolean strict) {
         return false;
     }
 
--- a/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java	Tue Oct 06 11:04:55 2015 -0700
@@ -50,15 +50,15 @@
 
     @Override
     public boolean canDelete(final int index, final boolean strict) {
-        if (strict) {
-            throw typeError("cant.delete.property", Integer.toString(index), "sealed array");
-        }
-        return false;
+        return canDelete(ArrayIndex.toLongIndex(index), strict);
     }
 
     @Override
-    public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
-        return canDelete((int) fromIndex, strict);
+    public boolean canDelete(final long longIndex, final boolean strict) {
+        if (strict) {
+            throw typeError("cant.delete.property", Long.toString(longIndex), "sealed array");
+        }
+        return false;
     }
 
     @Override
--- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -36,7 +36,7 @@
  * Handle arrays where the index is very large.
  */
 class SparseArrayData extends ArrayData {
-    static final int MAX_DENSE_LENGTH = 8 * 1024 * 1024;
+    static final int MAX_DENSE_LENGTH = 1024 * 1024;
 
     /** Underlying array. */
     private ArrayData underlying;
@@ -166,8 +166,9 @@
     @Override
     public ArrayData set(final int index, final Object value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
+            final long oldLength = underlying.length();
             ensure(index);
-            underlying = underlying.set(index, value, strict);
+            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -181,8 +182,9 @@
     @Override
     public ArrayData set(final int index, final int value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
+            final long oldLength = underlying.length();
             ensure(index);
-            underlying = underlying.set(index, value, strict);
+            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -195,8 +197,9 @@
     @Override
     public ArrayData set(final int index, final long value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
+            final long oldLength = underlying.length();
             ensure(index);
-            underlying = underlying.set(index, value, strict);
+            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
@@ -209,8 +212,9 @@
     @Override
     public ArrayData set(final int index, final double value, final boolean strict) {
         if (index >= 0 && index < maxDenseLength) {
+            final long oldLength = underlying.length();
             ensure(index);
-            underlying = underlying.set(index, value, strict);
+            underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
             setLength(Math.max(underlying.length(), length()));
         } else {
             final Long longIndex = indexToKey(index);
--- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java	Tue Oct 06 11:04:55 2015 -0700
@@ -83,7 +83,7 @@
     }
 
     @Override
-    public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+    public boolean canDelete(final long longIndex, final boolean strict) {
         return false;
     }
 
--- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Tue Oct 06 11:04:55 2015 -0700
@@ -99,9 +99,10 @@
             return null;
         }
 
-        final GuardedInvocation inv;
+        GuardedInvocation inv;
         if (jsObjectClass.isInstance(self)) {
             inv = lookup(desc, request, linkerServices);
+            inv = inv.replaceMethods(linkerServices.filterInternalObjects(inv.getInvocation()), inv.getGuard());
         } else {
             throw new AssertionError(); // Should never reach here.
         }
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Tue Oct 06 11:04:55 2015 -0700
@@ -77,9 +77,10 @@
             return null;
         }
 
-        final GuardedInvocation inv;
+        GuardedInvocation inv;
         if (self instanceof JSObject) {
             inv = lookup(desc, request, linkerServices);
+            inv = inv.replaceMethods(linkerServices.filterInternalObjects(inv.getInvocation()), inv.getGuard());
         } else if (self instanceof Map || self instanceof Bindings) {
             // guard to make sure the Map or Bindings does not turn into JSObject later!
             final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices);
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Tue Oct 06 11:04:55 2015 -0700
@@ -203,6 +203,8 @@
 
     // This is the superclass for our generated adapter.
     private final Class<?> superClass;
+    // Interfaces implemented by our generated adapter.
+    private final List<Class<?>> interfaces;
     // Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
     // loader that has the visibility of all original types (class to extend and interfaces to implement) and of the
     // Nashorn classes.
@@ -254,6 +256,7 @@
         assert interfaces != null;
 
         this.superClass = superClass;
+        this.interfaces = interfaces;
         this.classOverride = classOverride;
         this.commonLoader = commonLoader;
         cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
@@ -1031,6 +1034,24 @@
         endMethod(mv);
     }
 
+    // find the appropriate super type to use for invokespecial on the given interface
+    private Class<?> findInvokespecialOwnerFor(final Class<?> cl) {
+        assert Modifier.isInterface(cl.getModifiers()) : cl + " is not an interface";
+
+        if (cl.isAssignableFrom(superClass)) {
+            return superClass;
+        }
+
+        for (final Class<?> iface : interfaces) {
+             if (cl.isAssignableFrom(iface)) {
+                 return iface;
+             }
+        }
+
+        // we better that interface that extends the given interface!
+        throw new AssertionError("can't find the class/interface that extends " + cl);
+    }
+
     private void emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) {
         mv.visitVarInsn(ALOAD, 0);
         int nextParam = 1;
@@ -1042,7 +1063,9 @@
 
         // default method - non-abstract, interface method
         if (Modifier.isInterface(owner.getModifiers())) {
-            mv.invokespecial(Type.getInternalName(owner), name, methodDesc, false);
+            // we should call default method on the immediate "super" type - not on (possibly)
+            // the indirectly inherited interface class!
+            mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false);
         } else {
             mv.invokespecial(superClassName, name, methodDesc, false);
         }
--- a/src/jdk/nashorn/tools/Shell.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/src/jdk/nashorn/tools/Shell.java	Tue Oct 06 11:04:55 2015 -0700
@@ -54,7 +54,6 @@
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -255,12 +254,9 @@
                     return COMPILATION_ERROR;
                 }
 
-                new Compiler(
+                Compiler.forNoInstallerCompilation(
                        context,
-                       env,
-                       null, //null - pass no code installer - this is compile only
                        functionNode.getSource(),
-                       context.getErrorManager(),
                        env._strict | functionNode.isStrict()).
                        compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8087312.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 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-8087312: PropertyMapWrapper.equals should compare className
+ *
+ * @test
+ * @run
+ * @fork
+ * @option -Dnashorn.debug=true
+ */
+
+function createObject(type) {
+    // we want to make sure two different object literals with the same keys and types share the same property map.
+    if (type) {
+        return {
+            a: "a",
+            b: 1,
+            c: 0.1
+        }
+    } else {
+        return {
+            a: "x",
+            b: 10,
+            c: 3.4
+        }
+    }
+}
+
+var o1 = createObject(false);
+var o2 = createObject(true);
+Assert.assertTrue(Debug.map(o1) === Debug.map(o2));
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8134488.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 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-8134488: var statement in if(false) block incorrectly evacuated into enclosing function
+ *
+ * @test
+ * @run
+ */
+
+var x = "string"; 
+print(x); 
+
+(function f1() { 
+    (function f2() { 
+        // If it finds both 'print' and 'x', it'll print 'string'.
+        print(x); 
+    })(); 
+
+    if (false) { 
+        (function f3() { 
+            var x; 
+        })(); 
+    } 
+
+})(); 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8134488.js.EXPECTED	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,2 @@
+string
+string
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8134490.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 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-8134490: Dead var statement evacuation incorrectly descends into nested functions
+ *
+ * @test
+ * @run
+ */
+
+var v1; 
+
+function f1() 
+{ 
+v1 = 1; 
+return true; 
+(function () { var v1; })(); 
+} 
+
+f1(); 
+// If it executes without throwing an exception in code generator, it's working.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8134569.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015, 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-8134569: Add tests for prototype callsites
+ *
+ * @test
+ * @run
+ */
+
+function create() {
+    function C() {
+        this.i1 = 1;
+        this.i2 = 2;
+        this.i3 = 3;
+        return this;
+    }
+    return new C();
+}
+
+function createEmpty() {
+    function C() {
+        return this;
+    }
+    return new C();
+}
+
+function createDeep() {
+    function C() {
+        this.i1 = 1;
+        this.i2 = 2;
+        this.i3 = 3;
+        return this;
+    }
+    function D() {
+        this.p1 = 1;
+        this.p2 = 2;
+        this.p3 = 3;
+        return this;
+    }
+    C.prototype = new D();
+    return new C();
+}
+
+function createDeeper() {
+    function C() {
+        this.i1 = 1;
+        this.i2 = 2;
+        this.i3 = 3;
+        return this;
+    }
+    function D() {
+        this.p1 = 1;
+        this.p2 = 2;
+        this.p3 = 3;
+        return this;
+    }
+    function E() {
+        this.e1 = 1;
+        this.e2 = 2;
+        this.e3 = 3;
+        return this;
+    }
+    D.prototype = new E();
+    C.prototype = new D();
+    return new C();
+}
+
+function createEval() {
+    return eval("Object.create({})");
+}
+
+function p(o) { print(o.x) }
+
+function e(o) { print(o.e1) }
+
+var a, b, c;
+
+create();
+a = create();
+b = create();
+c = create();
+a.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = create();
+b = create();
+c = create();
+b.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createEmpty();
+b = createEmpty();
+c = createEmpty();
+a.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createEmpty();
+b = createEmpty();
+c = createEmpty();
+b.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeep();
+b = createDeep();
+c = createDeep();
+a.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeep();
+b = createDeep();
+c = createDeep();
+b.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+a.__proto__.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+b.__proto__.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+a.__proto__.__proto__ = null;
+
+e(a);
+e(b);
+e(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+b.__proto__.__proto__ = null;
+
+e(a);
+e(b);
+e(c);
+
+
+a = createEval();
+b = createEval();
+c = createEval();
+a.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createEval();
+b = createEval();
+c = createEval();
+b.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8134569.js.EXPECTED	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,36 @@
+123
+undefined
+undefined
+undefined
+123
+undefined
+123
+undefined
+undefined
+undefined
+123
+undefined
+123
+undefined
+undefined
+undefined
+123
+undefined
+123
+undefined
+undefined
+undefined
+123
+undefined
+undefined
+1
+1
+1
+undefined
+1
+123
+undefined
+undefined
+undefined
+123
+undefined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8134609.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, 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-8134609: Allow constructors with same prototoype map to share the allocator map
+ *
+ * @test
+ * @run
+ * @fork
+ * @option -Dnashorn.debug
+ */
+
+function createProto(members) {
+    function P() {
+        for (var id in members) {
+            if (members.hasOwnProperty(id)) {
+                this[id] = members[id];
+            }
+        }
+        return this;
+    }
+    return new P();
+}
+
+function createSubclass(prototype, members) {
+    function C() {
+        for (var id in members) {
+            if (members.hasOwnProperty(id)) {
+                this[id] = members[id];
+            }
+        }
+        return this;
+    }
+
+    C.prototype = prototype;
+
+    return new C();
+}
+
+function assertP1(object, value) {
+    Assert.assertTrue(object.p1 === value);
+}
+
+// First prototype will have non-shared proto-map. Second and third will be shared.
+var proto0 = createProto({p1: 0, p2: 1});
+var proto1 = createProto({p1: 1, p2: 2});
+var proto2 = createProto({p1: 2, p2: 3});
+
+Assert.assertTrue(Debug.map(proto1) === Debug.map(proto2));
+
+assertP1(proto1, 1);
+assertP1(proto2, 2);
+
+// First instantiation will have a non-shared prototype map, from the second one
+// maps will be shared until a different proto map comes along.
+var child0 = createSubclass(proto1, {c1: 1, c2: 2});
+var child1 = createSubclass(proto2, {c1: 2, c2: 3});
+var child2 = createSubclass(proto1, {c1: 3, c2: 4});
+var child3 = createSubclass(proto2, {c1: 1, c2: 2});
+var child4 = createSubclass(proto0, {c1: 3, c2: 2});
+
+Assert.assertTrue(Debug.map(child1) === Debug.map(child2));
+Assert.assertTrue(Debug.map(child1) === Debug.map(child3));
+Assert.assertTrue(Debug.map(child3) !== Debug.map(child4));
+
+assertP1(child1, 2);
+assertP1(child2, 1);
+assertP1(child3, 2);
+assertP1(child4, 0);
+
+Assert.assertTrue(delete proto2.p1);
+
+assertP1(child3, undefined);
+assertP1(child2, 1);
+Assert.assertTrue(Debug.map(child1) !== Debug.map(child3));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8135000.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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-8135000: Number.prototype.toFixed returns wrong string for 0.5 and -0.5
+ *
+ * @test
+ * @run
+ */
+
+print(-2.6.toFixed());
+print(-2.5.toFixed());
+print(-2.4.toFixed());
+print(-1.6.toFixed());
+print(-1.5.toFixed());
+print(-1.4.toFixed());
+print(-0.6.toFixed());
+print(-0.5.toFixed());
+print(-0.4.toFixed());
+print(0.4.toFixed());
+print(0.5.toFixed());
+print(0.6.toFixed());
+print(1.4.toFixed());
+print(1.5.toFixed());
+print(1.6.toFixed());
+print(2.4.toFixed());
+print(2.5.toFixed());
+print(2.6.toFixed());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8135000.js.EXPECTED	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,18 @@
+-3
+-3
+-2
+-2
+-2
+-1
+-1
+-1
+0
+0
+1
+1
+1
+2
+2
+2
+3
+3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8135190.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 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-8135190: Method code too large in Babel browser.js script
+ *
+ * @test
+ * @run
+ */
+
+// Make sure huge object literals are parsed correctly and don't throw
+// (using buildObject -> JSON.stringify -> eval -> testObject)
+
+function buildObject(n, d) {
+    if (n < 2) {
+        return {name: "property", type: "identifier"};
+    }
+    var obj = {};
+    for (var i = 0; i < n; i++) {
+        obj["expr" + i] = buildObject(Math.floor(n / d), d);
+    }
+    return obj;
+}
+
+function testObject(obj, n, d) {
+    var keys = Object.keys(obj);
+    if (n < 2) {
+        Assert.assertTrue(keys.length === 2);
+        Assert.assertTrue(keys[0] === "name");
+        Assert.assertTrue(keys[1] === "type");
+    } else {
+        Assert.assertTrue(keys.length === n);
+        for (var i = 0; i < n; i++) {
+            Assert.assertTrue(keys[i] === "expr" + i);
+        }
+    }
+    if (n >= 2) {
+        for (var k in keys) {
+            testObject(obj[keys[k]], Math.floor(n / d), d)
+        }
+    }
+}
+
+var fieldObject = (eval("(" + JSON.stringify(buildObject(25, 2)) + ")"));
+testObject(fieldObject, 25, 2);
+var spillObject = (eval("(" + JSON.stringify(buildObject(1000, 100)) + ")"));
+testObject(spillObject, 1000, 100);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8137134.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, 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-8137134: invokespecial on indirect super interface is generated by Java adapter generator
+ *
+ * @test
+ * @run
+ */
+
+var B = Java.type("jdk.nashorn.test.models.B");
+var b1 = new B() {}
+print(b1.a());
+print(b1.b());
+
+var b2 = new B() {
+    b: function() {
+        return "from B.b in script";
+    }
+};
+
+print(b2.a());
+print(b2.b());
+
+var b3 = new B() {
+    a: function() {
+        return "from A.a in script";
+    },
+    b: function() {
+        return "from B.b in script";
+    }
+};
+
+print(b3.a());
+print(b3.b());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8137134.js.EXPECTED	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,6 @@
+from A.a
+from B.b
+from A.a
+from B.b in script
+from A.a in script
+from B.b in script
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8137281.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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-8137281: OutOfMemoryError with large numeric keys in JSON.parse
+ *
+ * @test
+ * @run
+ */
+
+function createObject(startKey, level1, level2) {
+    var root = {};
+    var key = startKey;
+    for (var i = 0; i < level1; i++) {
+        var child = {};
+        for (var j = 0; j < level2; j++) {
+            child[key++] = {};
+        }
+        root[key++] = child;
+    }
+    return root;
+}
+
+JSON.parse(JSON.stringify(createObject(500000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(1000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(2000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(4000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(8000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(16000000, 20, 20)));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8138632.js	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 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-8138632: Sparse array does not handle growth of underlying dense array
+ *
+ * @test
+ * @run
+ */
+
+var x = [];
+x[10000000] = 1;
+x[10] = 1;
+x[20] = 1;
+print(Object.keys(x));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8138632.js.EXPECTED	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,1 @@
+10,20,10000000
--- a/test/script/trusted/JDK-8006529.js	Mon Sep 28 15:36:24 2015 -0700
+++ b/test/script/trusted/JDK-8006529.js	Tue Oct 06 11:04:55 2015 -0700
@@ -120,7 +120,7 @@
 
 var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
 var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
-var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, ErrorManager.class, boolean.class);
+var CompilerConstructor = Compiler.class.getMethod("forNoInstallerCompilation", Context.class, Source.class, boolean.class);
 
 // compile(script) -- compiles a script specified as a string with its
 // source code, returns a jdk.nashorn.internal.ir.FunctionNode object
@@ -134,7 +134,7 @@
     var parser   = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance());
     var func     = parseMethod.invoke(parser);
 
-    var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, null, false);
+    var compiler = CompilerConstructor.invoke(null, ctxt, source, false);
 
     return compileMethod.invoke(compiler, func, phases);
 };
--- a/test/src/jdk/nashorn/api/scripting/JSONCompatibleTest.java	Mon Sep 28 15:36:24 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2015, 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.api.scripting;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-public class JSONCompatibleTest {
-
-    /**
-     * Wrap a top-level array as a list.
-     */
-    @Test
-    public void testWrapArray() throws ScriptException {
-        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
-        final Object val = engine.eval("Java.asJSONCompatible([1, 2, 3])");
-        assertEquals(asList(val), Arrays.asList(1, 2, 3));
-    }
-
-    /**
-     * Wrap an embedded array as a list.
-     */
-    @Test
-    public void testWrapObjectWithArray() throws ScriptException {
-        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
-        final Object val = engine.eval("Java.asJSONCompatible({x: [1, 2, 3]})");
-        assertEquals(asList(asMap(val).get("x")), Arrays.asList(1, 2, 3));
-    }
-
-    /**
-     * Check it all works transitively several more levels down.
-     */
-    @Test
-    public void testDeepWrapping() throws ScriptException {
-        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
-        final Object val = engine.eval("Java.asJSONCompatible({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
-        final Map<String, Object> root = asMap(val);
-        final List<Object> x = asList(root.get("x"));
-        assertEquals(x.get(0), 1);
-        final Map<String, Object> x1 = asMap(x.get(1));
-        final List<Object> y = asList(x1.get("y"));
-        assertEquals(y.get(0), 2);
-        final Map<String, Object> y1 = asMap(y.get(1));
-        assertEquals(asList(y1.get("z")), Arrays.asList(3));
-        assertEquals(asList(x.get(2)), Arrays.asList(4, 5));
-    }
-
-    /**
-     * Ensure that the old behaviour (every object is a Map) is unchanged.
-     */
-    @Test
-    public void testNonWrapping() throws ScriptException {
-        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
-        final Object val = engine.eval("({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
-        final Map<String, Object> root = asMap(val);
-        final Map<String, Object> x = asMap(root.get("x"));
-        assertEquals(x.get("0"), 1);
-        final Map<String, Object> x1 = asMap(x.get("1"));
-        final Map<String, Object> y = asMap(x1.get("y"));
-        assertEquals(y.get("0"), 2);
-        final Map<String, Object> y1 = asMap(y.get("1"));
-        final Map<String, Object> z = asMap(y1.get("z"));
-        assertEquals(z.get("0"), 3);
-        final Map<String, Object> x2 = asMap(x.get("2"));
-        assertEquals(x2.get("0"), 4);
-        assertEquals(x2.get("1"), 5);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static List<Object> asList(final Object obj) {
-        assertJSObject(obj);
-        Assert.assertTrue(obj instanceof List);
-        return (List)obj;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static Map<String, Object> asMap(final Object obj) {
-        assertJSObject(obj);
-        Assert.assertTrue(obj instanceof Map);
-        return (Map)obj;
-    }
-
-    private static void assertJSObject(final Object obj) {
-        assertTrue(obj instanceof JSObject);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/api/scripting/test/JSONCompatibleTest.java	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, 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.api.scripting.test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.NashornScriptEngine;
+import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class JSONCompatibleTest {
+
+    /**
+     * Wrap a top-level array as a list.
+     */
+    @Test
+    public void testWrapArray() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("Java.asJSONCompatible([1, 2, 3])");
+        assertEquals(asList(val), Arrays.asList(1, 2, 3));
+    }
+
+    /**
+     * Wrap an embedded array as a list.
+     */
+    @Test
+    public void testWrapObjectWithArray() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("Java.asJSONCompatible({x: [1, 2, 3]})");
+        assertEquals(asList(asMap(val).get("x")), Arrays.asList(1, 2, 3));
+    }
+
+    /**
+     * Check it all works transitively several more levels down.
+     */
+    @Test
+    public void testDeepWrapping() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("Java.asJSONCompatible({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
+        final Map<String, Object> root = asMap(val);
+        final List<Object> x = asList(root.get("x"));
+        assertEquals(x.get(0), 1);
+        final Map<String, Object> x1 = asMap(x.get(1));
+        final List<Object> y = asList(x1.get("y"));
+        assertEquals(y.get(0), 2);
+        final Map<String, Object> y1 = asMap(y.get(1));
+        assertEquals(asList(y1.get("z")), Arrays.asList(3));
+        assertEquals(asList(x.get(2)), Arrays.asList(4, 5));
+    }
+
+    /**
+     * Ensure that the old behaviour (every object is a Map) is unchanged.
+     */
+    @Test
+    public void testNonWrapping() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
+        final Map<String, Object> root = asMap(val);
+        final Map<String, Object> x = asMap(root.get("x"));
+        assertEquals(x.get("0"), 1);
+        final Map<String, Object> x1 = asMap(x.get("1"));
+        final Map<String, Object> y = asMap(x1.get("y"));
+        assertEquals(y.get("0"), 2);
+        final Map<String, Object> y1 = asMap(y.get("1"));
+        final Map<String, Object> z = asMap(y1.get("z"));
+        assertEquals(z.get("0"), 3);
+        final Map<String, Object> x2 = asMap(x.get("2"));
+        assertEquals(x2.get("0"), 4);
+        assertEquals(x2.get("1"), 5);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static List<Object> asList(final Object obj) {
+        assertJSObject(obj);
+        Assert.assertTrue(obj instanceof List);
+        return (List)obj;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Map<String, Object> asMap(final Object obj) {
+        assertJSObject(obj);
+        Assert.assertTrue(obj instanceof Map);
+        return (Map)obj;
+    }
+
+    private static void assertJSObject(final Object obj) {
+        assertTrue(obj instanceof JSObject);
+    }
+}
--- a/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java	Tue Oct 06 11:04:55 2015 -0700
@@ -27,6 +27,7 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 import java.nio.IntBuffer;
@@ -34,9 +35,11 @@
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Set;
+import javax.script.Invocable;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import jdk.nashorn.api.scripting.AbstractJSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import org.testng.annotations.Test;
 
 /**
@@ -286,4 +289,23 @@
             fail(exp.getMessage());
         }
     }
+
+    // @bug 8137258: JSObjectLinker and BrowserJSObjectLinker should not expose internal JS objects
+    @Test
+    public void hidingInternalObjectsForJSObjectTest() throws Exception {
+        final ScriptEngineManager engineManager = new ScriptEngineManager();
+        final ScriptEngine e = engineManager.getEngineByName("nashorn");
+
+        final String code = "function func(obj) { obj.foo = [5, 5]; obj.bar = {} }";
+        e.eval(code);
+
+        // call the exposed function but pass user defined JSObject impl as argument
+        ((Invocable)e).invokeFunction("func", new AbstractJSObject() {
+            @Override
+            public void setMember(final String name, final Object value) {
+                // make sure that wrapped objects are passed (and not internal impl. objects)
+                assertTrue(value.getClass() == ScriptObjectMirror.class);
+            }
+        });
+    }
 }
--- a/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Mon Sep 28 15:36:24 2015 -0700
+++ b/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Tue Oct 06 11:04:55 2015 -0700
@@ -30,6 +30,7 @@
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 import javax.script.Bindings;
+import javax.script.Invocable;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineFactory;
@@ -855,4 +856,59 @@
             assertTrue(ret, "Expected true in iteration " + i);
         }
     }
+
+    // @bug 8138616: invokeFunction fails if function calls a function defined in GLOBAL_SCOPE
+    @Test
+    public void invokeFunctionInGlobalScopeTest() throws Exception {
+         final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
+         final ScriptContext ctxt = engine.getContext();
+
+         // define a function called "func"
+         engine.eval("func = function() { return 42 }");
+
+         // move ENGINE_SCOPE Bindings to GLOBAL_SCOPE
+         ctxt.setBindings(ctxt.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.GLOBAL_SCOPE);
+
+         // create a new Bindings and set as ENGINE_SCOPE
+         ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+         // define new function that calls "func" now in GLOBAL_SCOPE
+         engine.eval("newfunc = function() { return func() }");
+
+         // call "newfunc" and check the return value
+         Object value = ((Invocable)engine).invokeFunction("newfunc");
+         assertTrue(((Number)value).intValue() == 42);
+    }
+
+
+    // @bug 8138616: invokeFunction fails if function calls a function defined in GLOBAL_SCOPE
+    // variant of above that replaces default ScriptContext of the engine with a fresh instance!
+    @Test
+    public void invokeFunctionInGlobalScopeTest2() throws Exception {
+         final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
+
+         // create a new ScriptContext instance
+         final ScriptContext ctxt = new SimpleScriptContext();
+         // set it as 'default' ScriptContext
+         engine.setContext(ctxt);
+
+         // create a new Bindings and set as ENGINE_SCOPE
+         ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+         // define a function called "func"
+         engine.eval("func = function() { return 42 }");
+
+         // move ENGINE_SCOPE Bindings to GLOBAL_SCOPE
+         ctxt.setBindings(ctxt.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.GLOBAL_SCOPE);
+
+         // create a new Bindings and set as ENGINE_SCOPE
+         ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+         // define new function that calls "func" now in GLOBAL_SCOPE
+         engine.eval("newfunc = function() { return func() }");
+
+         // call "newfunc" and check the return value
+         Object value = ((Invocable)engine).invokeFunction("newfunc");
+         assertTrue(((Number)value).intValue() == 42);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/test/models/A.java	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, 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.test.models;
+
+public interface A {
+    default String a() {
+        return "from A.a";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/src/jdk/nashorn/test/models/B.java	Tue Oct 06 11:04:55 2015 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, 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.test.models;
+
+public interface B extends A {
+    default String b() {
+        return "from B.b";
+    }
+}