changeset 1433:21b86b980a5f jdk9-b83

Merge
author lana
date Fri, 18 Sep 2015 14:21:22 -0700
parents 285f2316315c (current diff) 67bab332bcb3 (diff)
children 4d320336c48c
files samples/EvalWithArbitraryThis.java.orig
diffstat 50 files changed, 1505 insertions(+), 729 deletions(-) [+]
line wrap: on
line diff
--- a/samples/EvalWithArbitraryThis.java.orig	Fri Sep 18 10:46:55 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   - Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *
- *   - Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- *   - Neither the name of Oracle nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-import javax.script.*;
-import jdk.nashorn.api.scripting.*;
-
-// Simple nashorn demo that evals a script with arbitrary script
-// object bound as "this" for the evaluated script.
-
-public class EvalWithArbitraryThis {
-    public static void main(String[] args) throws Exception {
-        ScriptEngineManager m = new ScriptEngineManager();
-        ScriptEngine e = m.getEngineByName("nashorn");
-        Object sobj = e.eval("( { foo: 343, bar: 'hello' } )");
-
-        // "this" bound to sobj in this eval.
-        // so it prints sobj.foo and sobj.bar.
-        ((ScriptObjectMirror)sobj).eval("print(this.foo); print(this.bar)");
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/exceptionswallow.js	Fri Sep 18 14:21:22 2015 -0700
@@ -0,0 +1,136 @@
+#// Usage: jjs exceptionswallow.js -- <directory>
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This example demonstrates Java subclassing by Java.extend
+// and javac Compiler and Tree API. This example looks for
+// empty catch blocks ("exception swallow") and reports those.
+
+if (arguments.length == 0) {
+    print("Usage: jjs exceptionswallow.js -- <directory>");
+    exit(1);
+}
+ 
+// Java types used
+var File = Java.type("java.io.File");
+var Files = Java.type("java.nio.file.Files");
+var StringArray = Java.type("java.lang.String[]");
+var ToolProvider = Java.type("javax.tools.ToolProvider");
+var Tree = Java.type("com.sun.source.tree.Tree");
+var EmptyStatementTree = Java.type("com.sun.source.tree.EmptyStatementTree");
+var Trees = Java.type("com.sun.source.util.Trees");
+var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
+
+// printEmptyCatch
+
+function printEmptyCatch() {
+    // get the system compiler tool
+    var compiler = ToolProvider.systemJavaCompiler;
+    // get standard file manager
+    var fileMgr = compiler.getStandardFileManager(null, null, null);
+    // Using Java.to convert script array (arguments) to a Java String[]
+    var compUnits = fileMgr.getJavaFileObjects(
+        Java.to(arguments, StringArray));
+    // create a new compilation task
+    var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
+
+    // SourcePositions object to get positions of AST nodes
+    var sourcePositions = Trees.instance(task).sourcePositions;
+
+    // subclass SimpleTreeVisitor - to print empty catch
+    var EmptyCatchFinder = Java.extend(TreeScanner);
+   
+    function hasOnlyEmptyStats(stats) {
+        var itr = stats.iterator();
+        while (itr.hasNext()) {
+            if (! (itr.next() instanceof EmptyStatementTree)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+ 
+    var visitor = new EmptyCatchFinder() {
+        // current CompilationUnitTree
+        compUnit: null,
+        // current LineMap (pos -> line, column)
+        lineMap: null,
+        // current compilation unit's file name
+        fileName: null,
+
+        // overrides of TreeScanner methods
+
+        visitCompilationUnit: function(node, p) {
+            // capture info about current Compilation unit
+            this.compUnit = node;
+            this.lineMap = node.lineMap;
+            this.fileName = node.sourceFile.name;
+
+            // Using Java.super API to call super class method here
+            return Java.super(visitor).visitCompilationUnit(node, p);
+        },
+
+        visitCatch: function (node, p) {
+            var stats = node.block.statements;
+            if (stats.empty || hasOnlyEmptyStats(stats)) {
+                // print information on this empty catch
+                var pos = sourcePositions.getStartPosition(this.compUnit, node);
+                var line = this.lineMap.getLineNumber(pos);
+                var col = this.lineMap.getColumnNumber(pos);
+                print("Exception swallow" + " @ " + this.fileName + ":" + line + ":" + col);
+                // print(node);
+            }
+        }
+    }
+ 
+    for each (var cu in task.parse()) {
+        cu.accept(visitor, null);
+    }
+}
+ 
+// for each ".java" file in directory (recursively) and check it!
+function main(dir) {
+    Files.walk(dir.toPath()).
+      forEach(function(p) {
+        var name = p.toFile().absolutePath;
+        if (name.endsWith(".java")) {
+            try {
+                printEmptyCatch(p.toFile().getAbsolutePath());
+            } catch (e) {
+                print(e);
+            }
+        }
+      });
+}
+ 
+main(new File(arguments[0]));
--- a/samples/find_nonfinals2.js	Fri Sep 18 10:46:55 2015 -0700
+++ b/samples/find_nonfinals2.js	Fri Sep 18 14:21:22 2015 -0700
@@ -43,7 +43,6 @@
 // Java types used
 var File = Java.type("java.io.File");
 var Files = Java.type("java.nio.file.Files");
-var FileVisitOption = Java.type("java.nio.file.FileVisitOption");
 var StringArray = Java.type("java.lang.String[]");
 var ToolProvider = Java.type("javax.tools.ToolProvider");
 var Tree = Java.type("com.sun.source.tree.Tree");
@@ -106,7 +105,7 @@
 // for each ".java" file in directory (recursively).
 function main(dir) {
     var totalCount = 0;
-    Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS).
+    Files.walk(dir.toPath()).
       forEach(function(p) {
         var name = p.toFile().absolutePath;
         if (name.endsWith(".java")) {
--- a/samples/javafoovars.js	Fri Sep 18 10:46:55 2015 -0700
+++ b/samples/javafoovars.js	Fri Sep 18 14:21:22 2015 -0700
@@ -42,7 +42,6 @@
 // Java types used
 var File = Java.type("java.io.File");
 var Files = Java.type("java.nio.file.Files");
-var FileVisitOption = Java.type("java.nio.file.FileVisitOption");
 var StringArray = Java.type("java.lang.String[]");
 var ToolProvider = Java.type("javax.tools.ToolProvider");
 var Tree = Java.type("com.sun.source.tree.Tree");
@@ -81,7 +80,7 @@
 // for each ".java" file in directory (recursively) count "foo".
 function main(dir) {
     var totalCount = 0;
-    Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS).
+    Files.walk(dir.toPath()).
       forEach(function(p) {
         var name = p.toFile().absolutePath;
         if (name.endsWith(".java")) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/resourcetrysuggester.js	Fri Sep 18 14:21:22 2015 -0700
@@ -0,0 +1,156 @@
+#// Usage: jjs resourcetrysuggester.js -- <directory>
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This example demonstrates Java subclassing by Java.extend
+// and javac Compiler and Tree API. This example looks for
+// finally clauses with "close" call and suggests "resource try"!
+
+if (arguments.length == 0) {
+    print("Usage: jjs resourcetrysuggester.js -- <directory>");
+    exit(1);
+}
+ 
+// Java types used
+var ExpressionStatementTree = Java.type("com.sun.source.tree.ExpressionStatementTree");
+var File = Java.type("java.io.File");
+var Files = Java.type("java.nio.file.Files");
+var MemberSelectTree = Java.type("com.sun.source.tree.MemberSelectTree");
+var MethodInvocationTree = Java.type("com.sun.source.tree.MethodInvocationTree");
+var StringArray = Java.type("java.lang.String[]");
+var ToolProvider = Java.type("javax.tools.ToolProvider");
+var Tree = Java.type("com.sun.source.tree.Tree");
+var Trees = Java.type("com.sun.source.util.Trees");
+var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
+
+// resourceTrySuggestions
+
+function resourceTrySuggestions() {
+    // get the system compiler tool
+    var compiler = ToolProvider.systemJavaCompiler;
+    // get standard file manager
+    var fileMgr = compiler.getStandardFileManager(null, null, null);
+    // Using Java.to convert script array (arguments) to a Java String[]
+    var compUnits = fileMgr.getJavaFileObjects(
+        Java.to(arguments, StringArray));
+    // create a new compilation task
+    var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
+
+    // SourcePositions object to get positions of AST nodes
+    var sourcePositions = Trees.instance(task).sourcePositions;
+
+    // subclass SimpleTreeVisitor - to print resource try suggestions
+    var ResourceTrySuggester = Java.extend(TreeScanner);
+   
+    function hasOnlyEmptyStats(stats) {
+        var itr = stats.iterator();
+        while (itr.hasNext()) {
+            if (! (itr.next() instanceof EmptyStatementTree)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    // does the given statement list has an expression statement which
+    // calls "close" method (don't worry about types - just crude one will do)
+    function hasCloseCall(stats) {
+        var itr = stats.iterator();
+        while (itr.hasNext()) {
+            var stat = itr.next();
+            if (stat instanceof ExpressionStatementTree) {
+                var expr = stat.expression;
+                if (expr instanceof MethodInvocationTree) {
+                    var method = expr.methodSelect;
+                    if (method instanceof MemberSelectTree) {
+                        return method.identifier.toString().equals("close");
+                    }
+                }
+            }
+        }
+        return false;
+    }
+ 
+    var visitor = new ResourceTrySuggester() {
+        // current CompilationUnitTree
+        compUnit: null,
+        // current LineMap (pos -> line, column)
+        lineMap: null,
+        // current compilation unit's file name
+        fileName: null,
+
+        // overrides of TreeScanner methods
+
+        visitCompilationUnit: function(node, p) {
+            // capture info about current Compilation unit
+            this.compUnit = node;
+            this.lineMap = node.lineMap;
+            this.fileName = node.sourceFile.name;
+
+            // Using Java.super API to call super class method here
+            return Java.super(visitor).visitCompilationUnit(node, p);
+        },
+
+        visitTry: function (node, p) {
+            var finallyBlk = node.finallyBlock;
+            if (finallyBlk != null && hasCloseCall(finallyBlk.statements)) {
+                var pos = sourcePositions.getStartPosition(this.compUnit, node);
+                var line = this.lineMap.getLineNumber(pos);
+                var col = this.lineMap.getColumnNumber(pos);
+                print("Consider resource try statement " + " @ " + this.fileName + ":" + line + ":" + col);
+                // print(node);
+            }
+        }
+    }
+ 
+    for each (var cu in task.parse()) {
+        cu.accept(visitor, null);
+    }
+}
+ 
+// for each ".java" file in directory (recursively) and check it!
+function main(dir) {
+    Files.walk(dir.toPath()).
+      forEach(function(p) {
+        var name = p.toFile().absolutePath;
+        if (name.endsWith(".java")) {
+            try {
+                resourceTrySuggestions(p.toFile().getAbsolutePath());
+            } catch (e) {
+                print(e);
+            }
+        }
+      });
+}
+ 
+main(new File(arguments[0]));
--- a/samples/zipfs.js	Fri Sep 18 10:46:55 2015 -0700
+++ b/samples/zipfs.js	Fri Sep 18 14:21:22 2015 -0700
@@ -36,13 +36,12 @@
 
 var Files = Java.type("java.nio.file.Files")
 var FileSystems = Java.type("java.nio.file.FileSystems")
-var FileVisitOption = Java.type("java.nio.file.FileVisitOption")
 var Paths = Java.type("java.nio.file.Paths")
 
 var zipfile = Paths.get(arguments[0])
 var fs = FileSystems.newFileSystem(zipfile, null)
 var root = fs.rootDirectories[0]
-Files.walk(root, FileVisitOption.FOLLOW_LINKS).forEach(
+Files.walk(root).forEach(
    function(p) (print(p), print(Files.readAttributes(p, "zip:*")))
 )
 fs.close()
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/EditPad.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/EditPad.java	Fri Sep 18 14:21:22 2015 -0700
@@ -49,8 +49,8 @@
     private final boolean[] closeLock;
     private final Consumer<String> saveHandler;
 
-    EditPad(Consumer<String> errorHandler, String initialText,
-            boolean[] closeLock, Consumer<String> saveHandler) {
+    EditPad(final Consumer<String> errorHandler, final String initialText,
+            final boolean[] closeLock, final Consumer<String> saveHandler) {
         super("Edit Pad (Experimental)");
         this.errorHandler = errorHandler;
         this.initialText = initialText;
@@ -62,7 +62,7 @@
     public void run() {
         addWindowListener(new WindowAdapter() {
             @Override
-            public void windowClosing(WindowEvent e) {
+            public void windowClosing(final WindowEvent e) {
                 EditPad.this.dispose();
                 notifyClose();
             }
@@ -77,7 +77,7 @@
         setVisible(true);
     }
 
-    private JPanel buttons(JTextArea textArea) {
+    private JPanel buttons(final JTextArea textArea) {
         FlowLayout flow = new FlowLayout();
         flow.setHgap(35);
         JPanel buttons = new JPanel(flow);
@@ -118,8 +118,8 @@
         }
     }
 
-    static void edit(Consumer<String> errorHandler, String initialText,
-            Consumer<String> saveHandler) {
+    static void edit(final Consumer<String> errorHandler, final String initialText,
+            final Consumer<String> saveHandler) {
         boolean[] closeLock = new boolean[1];
         SwingUtilities.invokeLater(
                 new EditPad(errorHandler, initialText, closeLock, saveHandler));
@@ -127,7 +127,7 @@
             while (!closeLock[0]) {
                 try {
                     closeLock.wait();
-                } catch (InterruptedException ex) {
+                } catch (final InterruptedException ex) {
                     // ignore and loop
                 }
             }
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/ExternalEditor.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/ExternalEditor.java	Fri Sep 18 14:21:22 2015 -0700
@@ -49,13 +49,13 @@
     private Path dir;
     private Path tmpfile;
 
-    ExternalEditor(Consumer<String> errorHandler, Consumer<String> saveHandler, Console input) {
+    ExternalEditor(final Consumer<String> errorHandler, final Consumer<String> saveHandler, final Console input) {
         this.errorHandler = errorHandler;
         this.saveHandler = saveHandler;
         this.input = input;
     }
 
-    private void edit(String cmd, String initialText) {
+    private void edit(final String cmd, final String initialText) {
         try {
             setupWatch(initialText);
             launch(cmd);
@@ -67,7 +67,7 @@
     /**
      * Creates a WatchService and registers the given directory
      */
-    private void setupWatch(String initialText) throws IOException {
+    private void setupWatch(final String initialText) throws IOException {
         this.watcher = FileSystems.getDefault().newWatchService();
         this.dir = Files.createTempDirectory("REPL");
         this.tmpfile = Files.createTempFile(dir, null, ".js");
@@ -81,9 +81,9 @@
                 WatchKey key;
                 try {
                     key = watcher.take();
-                } catch (ClosedWatchServiceException ex) {
+                } catch (final ClosedWatchServiceException ex) {
                     break;
-                } catch (InterruptedException ex) {
+                } catch (final InterruptedException ex) {
                     continue; // tolerate an intrupt
                 }
 
@@ -103,7 +103,7 @@
         watchedThread.start();
     }
 
-    private void launch(String cmd) throws IOException {
+    private void launch(final String cmd) throws IOException {
         ProcessBuilder pb = new ProcessBuilder(cmd, tmpfile.toString());
         pb = pb.inheritIO();
 
@@ -111,9 +111,9 @@
             input.suspend();
             Process process = pb.start();
             process.waitFor();
-        } catch (IOException ex) {
+        } catch (final IOException ex) {
             errorHandler.accept("process IO failure: " + ex.getMessage());
-        } catch (InterruptedException ex) {
+        } catch (final InterruptedException ex) {
             errorHandler.accept("process interrupt: " + ex.getMessage());
         } finally {
             try {
@@ -132,7 +132,7 @@
         List<String> lines;
         try {
             lines = Files.readAllLines(tmpfile);
-        } catch (IOException ex) {
+        } catch (final IOException ex) {
             errorHandler.accept("Failure read edit file: " + ex.getMessage());
             return ;
         }
@@ -144,8 +144,8 @@
         saveHandler.accept(sb.toString());
     }
 
-    static void edit(String cmd, Consumer<String> errorHandler, String initialText,
-            Consumer<String> saveHandler, Console input) {
+    static void edit(final String cmd, final Consumer<String> errorHandler, final String initialText,
+            final Consumer<String> saveHandler, final Console input) {
         ExternalEditor ed = new ExternalEditor(errorHandler,  saveHandler, input);
         ed.edit(cmd, initialText);
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java	Fri Sep 18 14:21:22 2015 -0700
@@ -40,7 +40,6 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
@@ -384,7 +383,7 @@
         callSiteTypes.pop();
         explodedArguments.pop();
 
-        return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED);
+        return newFunctionNode;
     }
 
     private static boolean isApply(final CallNode callNode) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Fri Sep 18 14:21:22 2015 -0700
@@ -65,7 +65,6 @@
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LexicalContext;
@@ -828,7 +827,7 @@
                        lc.applyTopFlags(functionNode))))
                        .setThisProperties(lc, thisProperties.pop().size()));
         }
-        return finalizedFunction.setState(lc, CompilationState.SYMBOLS_ASSIGNED);
+        return finalizedFunction;
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Sep 18 14:21:22 2015 -0700
@@ -93,7 +93,6 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
@@ -2142,7 +2141,7 @@
                 markOptimistic = false;
             }
 
-            FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.BYTECODE_GENERATED);
+            FunctionNode newFunctionNode = functionNode;
             if (markOptimistic) {
                 newFunctionNode = newFunctionNode.setFlag(lc, FunctionNode.IS_DEOPTIMIZABLE);
             }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Fri Sep 18 14:21:22 2015 -0700
@@ -25,32 +25,17 @@
 
 package jdk.nashorn.internal.codegen;
 
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BUILTINS_TRANSFORMED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BYTECODE_GENERATED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BYTECODE_INSTALLED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOCAL_VARIABLE_TYPES_CALCULATED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.OPTIMISTIC_TYPES_ASSIGNED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SCOPE_DEPTHS_COMPUTED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SYMBOLS_ASSIGNED;
 import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
 
 import java.io.PrintWriter;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import jdk.nashorn.internal.AssertsEnabled;
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
@@ -67,15 +52,9 @@
  * A compilation phase is a step in the processes of turning a JavaScript
  * FunctionNode into bytecode. It has an optional return value.
  */
-enum CompilationPhase {
-    /**
-     * Constant folding pass Simple constant folding that will make elementary
-     * constructs go away
-     */
-    CONSTANT_FOLDING_PHASE(
-            EnumSet.of(
-                INITIALIZED,
-                PARSED)) {
+abstract class CompilationPhase {
+
+    private static final class ConstantFoldingPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             return transformFunction(fn, new FoldConstants(compiler));
@@ -85,20 +64,15 @@
         public String toString() {
             return "'Constant Folding'";
         }
-    },
+    }
 
     /**
-     * Lower (Control flow pass) Finalizes the control flow. Clones blocks for
-     * finally constructs and similar things. Establishes termination criteria
-     * for nodes Guarantee return instructions to method making sure control
-     * flow cannot fall off the end. Replacing high level nodes with lower such
-     * as runtime nodes where applicable.
+     * Constant folding pass Simple constant folding that will make elementary
+     * constructs go away
      */
-    LOWERING_PHASE(
-            EnumSet.of(
-                INITIALIZED,
-                PARSED,
-                CONSTANT_FOLDED)) {
+    static final CompilationPhase CONSTANT_FOLDING_PHASE = new ConstantFoldingPhase();
+
+    private static final class LoweringPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             return transformFunction(fn, new Lower(compiler));
@@ -108,42 +82,35 @@
         public String toString() {
             return "'Control Flow Lowering'";
         }
-    },
+    }
 
     /**
-     * Phase used only when doing optimistic code generation. It assigns all potentially
-     * optimistic ops a program point so that an UnwarrantedException knows from where
-     * a guess went wrong when creating the continuation to roll back this execution
+     * Lower (Control flow pass) Finalizes the control flow. Clones blocks for
+     * finally constructs and similar things. Establishes termination criteria
+     * for nodes Guarantee return instructions to method making sure control
+     * flow cannot fall off the end. Replacing high level nodes with lower such
+     * as runtime nodes where applicable.
      */
-    TRANSFORM_BUILTINS_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED)) {
-        //we only do this if we have a param type map, otherwise this is not a specialized recompile
+    static final CompilationPhase LOWERING_PHASE = new LoweringPhase();
+
+    private static final class ApplySpecializationPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return setStates(transformFunction(fn, new ApplySpecialization(compiler)), BUILTINS_TRANSFORMED);
+            return transformFunction(fn, new ApplySpecialization(compiler));
         }
 
         @Override
         public String toString() {
             return "'Builtin Replacement'";
         }
-    },
+    };
 
     /**
-     * Splitter Split the AST into several compile units based on a heuristic size calculation.
-     * Split IR can lead to scope information being changed.
+     * Phase used to transform Function.prototype.apply.
      */
-    SPLITTING_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED)) {
+    static final CompilationPhase APPLY_SPECIALIZATION_PHASE = new ApplySpecializationPhase();
+
+    private static final class SplittingPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             final CompileUnit  outermostCompileUnit = compiler.addCompileUnit(0L);
@@ -170,16 +137,15 @@
         public String toString() {
             return "'Code Splitting'";
         }
-    },
+    };
 
-    PROGRAM_POINT_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT)) {
+    /**
+     * Splitter Split the AST into several compile units based on a heuristic size calculation.
+     * Split IR can lead to scope information being changed.
+     */
+    static final CompilationPhase SPLITTING_PHASE = new SplittingPhase();
+
+    private static final class ProgramPointPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             return transformFunction(fn, new ProgramPoints());
@@ -189,16 +155,16 @@
         public String toString() {
             return "'Program Point Calculation'";
         }
-    },
+    };
 
-    CACHE_AST(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT)) {
+    /**
+     * Phase used only when doing optimistic code generation. It assigns all potentially
+     * optimistic ops a program point so that an UnwarrantedException knows from where
+     * a guess went wrong when creating the continuation to roll back this execution
+     */
+    static final CompilationPhase PROGRAM_POINT_PHASE = new ProgramPointPhase();
+
+    private static final class CacheAstPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             if (!compiler.isOnDemandCompilation()) {
@@ -217,16 +183,11 @@
         public String toString() {
             return "'Cache ASTs'";
         }
-    },
+    };
 
-    SYMBOL_ASSIGNMENT_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT)) {
+    static final CompilationPhase CACHE_AST_PHASE = new CacheAstPhase();
+
+    private static final class SymbolAssignmentPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             return transformFunction(fn, new AssignSymbols(compiler));
@@ -236,17 +197,11 @@
         public String toString() {
             return "'Symbol Assignment'";
         }
-    },
+    };
 
-    SCOPE_DEPTH_COMPUTATION_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED)) {
+    static final CompilationPhase SYMBOL_ASSIGNMENT_PHASE = new SymbolAssignmentPhase();
+
+    private static final class ScopeDepthComputationPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             return transformFunction(fn, new FindScopeDepths(compiler));
@@ -256,18 +211,11 @@
         public String toString() {
             return "'Scope Depth Computation'";
         }
-    },
+    }
 
-    DECLARE_LOCAL_SYMBOLS_TO_COMPILER(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED,
-                    SCOPE_DEPTHS_COMPUTED)) {
+    static final CompilationPhase SCOPE_DEPTH_COMPUTATION_PHASE = new ScopeDepthComputationPhase();
+
+    private static final class DeclareLocalSymbolsPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             // It's not necessary to guard the marking of symbols as locals with this "if" condition for
@@ -301,43 +249,28 @@
         public String toString() {
             return "'Local Symbols Declaration'";
         }
-    },
+    };
 
-    OPTIMISTIC_TYPE_ASSIGNMENT_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED,
-                    SCOPE_DEPTHS_COMPUTED)) {
+    static final CompilationPhase DECLARE_LOCAL_SYMBOLS_PHASE = new DeclareLocalSymbolsPhase();
+
+    private static final class OptimisticTypeAssignmentPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             if (compiler.useOptimisticTypes()) {
                 return transformFunction(fn, new OptimisticTypesCalculator(compiler));
             }
-            return setStates(fn, OPTIMISTIC_TYPES_ASSIGNED);
+            return fn;
         }
 
         @Override
         public String toString() {
             return "'Optimistic Type Assignment'";
         }
-    },
+    }
 
-    LOCAL_VARIABLE_TYPE_CALCULATION_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED,
-                    SCOPE_DEPTHS_COMPUTED,
-                    OPTIMISTIC_TYPES_ASSIGNED)) {
+    static final CompilationPhase OPTIMISTIC_TYPE_ASSIGNMENT_PHASE = new OptimisticTypeAssignmentPhase();
+
+    private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
@@ -362,25 +295,11 @@
         public String toString() {
             return "'Local Variable Type Calculation'";
         }
-    },
-
+    };
 
-    /**
-     * Reuse compile units, if they are already present. We are using the same compiler
-     * to recompile stuff
-     */
-    REUSE_COMPILE_UNITS_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED,
-                    SCOPE_DEPTHS_COMPUTED,
-                    OPTIMISTIC_TYPES_ASSIGNED,
-                    LOCAL_VARIABLE_TYPES_CALCULATED)) {
+    static final CompilationPhase LOCAL_VARIABLE_TYPE_CALCULATION_PHASE = new LocalVariableTypeCalculationPhase();
+
+    private static final class ReuseCompileUnitsPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             assert phases.isRestOfCompilation() : "reuse compile units currently only used for Rest-Of methods";
@@ -428,16 +347,15 @@
         public String toString() {
             return "'Reuse Compile Units'";
         }
-    },
+    }
 
-    REINITIALIZE_CACHED(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT)) {
+    /**
+     * Reuse compile units, if they are already present. We are using the same compiler
+     * to recompile stuff
+     */
+    static final CompilationPhase REUSE_COMPILE_UNITS_PHASE = new ReuseCompileUnitsPhase();
+
+    private static final class ReinitializeCachedPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet();
@@ -480,26 +398,11 @@
         public String toString() {
             return "'Reinitialize cached'";
         }
-    },
+    }
 
-    /**
-     * Bytecode generation:
-     *
-     * Generate the byte code class(es) resulting from the compiled FunctionNode
-     */
-    BYTECODE_GENERATION_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED,
-                    SCOPE_DEPTHS_COMPUTED,
-                    OPTIMISTIC_TYPES_ASSIGNED,
-                    LOCAL_VARIABLE_TYPES_CALCULATED)) {
+    static final CompilationPhase REINITIALIZE_CACHED = new ReinitializeCachedPhase();
 
+    private static final class BytecodeGenerationPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             final ScriptEnvironment senv = compiler.getScriptEnvironment();
@@ -517,7 +420,7 @@
             try {
                 // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
                 // in the lazy + optimistic world. See CodeGenerator.skipFunction().
-                newFunctionNode = transformFunction(newFunctionNode, codegen).setState(null, BYTECODE_GENERATED);
+                newFunctionNode = transformFunction(newFunctionNode, codegen);
                 codegen.generateScopeCalls();
             } catch (final VerifyError e) {
                 if (senv._verify_code || senv._print_code) {
@@ -565,22 +468,16 @@
         public String toString() {
             return "'Bytecode Generation'";
         }
-    },
+    }
 
-     INSTALL_PHASE(
-            EnumSet.of(
-                    INITIALIZED,
-                    PARSED,
-                    CONSTANT_FOLDED,
-                    LOWERED,
-                    BUILTINS_TRANSFORMED,
-                    SPLIT,
-                    SYMBOLS_ASSIGNED,
-                    SCOPE_DEPTHS_COMPUTED,
-                    OPTIMISTIC_TYPES_ASSIGNED,
-                    LOCAL_VARIABLE_TYPES_CALCULATED,
-                    BYTECODE_GENERATED)) {
+    /**
+     * Bytecode generation:
+     *
+     * Generate the byte code class(es) resulting from the compiled FunctionNode
+     */
+    static final CompilationPhase BYTECODE_GENERATION_PHASE = new BytecodeGenerationPhase();
 
+    private static final class InstallPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
             final DebugLogger log = compiler.getLogger();
@@ -591,8 +488,9 @@
             Class<?> rootClass = null;
             long length = 0L;
 
-            final CodeInstaller       codeInstaller = compiler.getCodeInstaller();
-            final Map<String, byte[]> bytecode      = compiler.getBytecode();
+            final CodeInstaller origCodeInstaller = compiler.getCodeInstaller();
+            final Map<String, byte[]> bytecode = compiler.getBytecode();
+            final CodeInstaller codeInstaller = bytecode.size() > 1 ? origCodeInstaller.getMultiClassCodeInstaller() : origCodeInstaller;
 
             for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
                 final String className = entry.getKey();
@@ -648,18 +546,16 @@
                 log.fine(sb.toString());
             }
 
-            return setStates(fn.setRootClass(null, rootClass), BYTECODE_INSTALLED);
+            return fn.setRootClass(null, rootClass);
         }
 
         @Override
         public String toString() {
             return "'Class Installation'";
         }
-
-     };
+    }
 
-    /** pre conditions required for function node to which this transform is to be applied */
-    private final EnumSet<CompilationState> pre;
+    static final CompilationPhase INSTALL_PHASE = new InstallPhase();
 
     /** start time of transform - used for timing, see {@link jdk.nashorn.internal.runtime.Timing} */
     private long startTime;
@@ -670,21 +566,7 @@
     /** boolean that is true upon transform completion */
     private boolean isFinished;
 
-    private CompilationPhase(final EnumSet<CompilationState> pre) {
-        this.pre = pre;
-    }
-
-    private static FunctionNode setStates(final FunctionNode functionNode, final CompilationState state) {
-        if (!AssertsEnabled.assertsEnabled()) {
-            return functionNode;
-        }
-        return transformFunction(functionNode, new NodeVisitor<LexicalContext>(new LexicalContext()) {
-            @Override
-            public Node leaveFunctionNode(final FunctionNode fn) {
-                return fn.setState(lc, state);
-           }
-        });
-    }
+    private CompilationPhase() {}
 
     /**
      * Start a compilation phase
@@ -694,23 +576,7 @@
      */
     protected FunctionNode begin(final Compiler compiler, final FunctionNode functionNode) {
         compiler.getLogger().indent();
-
-        assert pre != null;
-
-        if (!functionNode.hasState(pre)) {
-            final StringBuilder sb = new StringBuilder("Compilation phase ");
-            sb.append(this).
-                append(" is not applicable to ").
-                append(quote(functionNode.getName())).
-                append("\n\tFunctionNode state = ").
-                append(functionNode.getState()).
-                append("\n\tRequired state     = ").
-                append(this.pre);
-
-            throw new CompilationException(sb.toString());
-         }
-
-         startTime = System.nanoTime();
+        startTime = System.nanoTime();
 
          return functionNode;
      }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Fri Sep 18 14:21:22 2015 -0700
@@ -172,17 +172,17 @@
                 "Common initial phases",
                 CompilationPhase.CONSTANT_FOLDING_PHASE,
                 CompilationPhase.LOWERING_PHASE,
-                CompilationPhase.TRANSFORM_BUILTINS_PHASE,
+                CompilationPhase.APPLY_SPECIALIZATION_PHASE,
                 CompilationPhase.SPLITTING_PHASE,
                 CompilationPhase.PROGRAM_POINT_PHASE,
                 CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
                 CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
-                CompilationPhase.CACHE_AST
+                CompilationPhase.CACHE_AST_PHASE
                 );
 
         private final static CompilationPhases COMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
                 "After common phases, before bytecode generator",
-                CompilationPhase.DECLARE_LOCAL_SYMBOLS_TO_COMPILER,
+                CompilationPhase.DECLARE_LOCAL_SYMBOLS_PHASE,
                 CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
                 CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
                 );
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java	Fri Sep 18 14:21:22 2015 -0700
@@ -34,7 +34,6 @@
 import java.util.Set;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
@@ -180,8 +179,7 @@
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         final String name = functionNode.getName();
-        FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.SCOPE_DEPTHS_COMPUTED);
-
+        FunctionNode newFunctionNode = functionNode;
         if (compiler.isOnDemandCompilation()) {
             final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(newFunctionNode.getId());
             if (data.inDynamicContext()) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java	Fri Sep 18 14:21:22 2015 -0700
@@ -37,7 +37,6 @@
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
@@ -101,7 +100,7 @@
 
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
-        return functionNode.setState(lc, CompilationState.CONSTANT_FOLDED);
+        return functionNode;
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Fri Sep 18 14:21:22 2015 -0700
@@ -54,7 +54,6 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
@@ -1478,7 +1477,6 @@
         newFunction = newFunction.setReturnType(lc, returnType);
 
 
-        newFunction = newFunction.setState(lc, CompilationState.LOCAL_VARIABLE_TYPES_CALCULATED);
         newFunction = newFunction.setParameters(lc, newFunction.visitParameters(applyChangesVisitor));
         return newFunction;
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Fri Sep 18 14:21:22 2015 -0700
@@ -52,7 +52,6 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
@@ -276,7 +275,7 @@
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         log.info("END FunctionNode: ", functionNode.getName());
-        return functionNode.setState(lc, CompilationState.LOWERED);
+        return functionNode;
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java	Fri Sep 18 14:21:22 2015 -0700
@@ -38,7 +38,6 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
@@ -208,7 +207,7 @@
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         neverOptimistic.pop();
-        return functionNode.setState(lc, CompilationState.OPTIMISTIC_TYPES_ASSIGNED);
+        return functionNode;
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Fri Sep 18 14:21:22 2015 -0700
@@ -29,7 +29,6 @@
 import java.util.List;
 import jdk.nashorn.internal.ir.CompileUnitHolder;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
@@ -64,7 +63,7 @@
 
     @Override
     public Node leaveFunctionNode(final FunctionNode node) {
-        return node.setCompileUnit(lc, getExistingReplacement(node)).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
+        return node.setCompileUnit(lc, getExistingReplacement(node));
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Fri Sep 18 14:21:22 2015 -0700
@@ -47,7 +47,6 @@
 import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.GetSplitState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
@@ -176,11 +175,9 @@
                 // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
                 FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT,
                 body,
-                CompilationState.INITIALIZED,
                 null
         )
-        .setCompileUnit(lc, splitNode.getCompileUnit())
-        .copyCompilationState(lc, originalFn);
+        .setCompileUnit(lc, splitNode.getCompileUnit());
 
         // Call the function:
         //     either "(function () { ... }).call(this)"
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Splitter.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Splitter.java	Fri Sep 18 14:21:22 2015 -0700
@@ -33,7 +33,6 @@
 import java.util.Map;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
@@ -158,7 +157,7 @@
 
         assert functionNode.getCompileUnit() != null;
 
-        return functionNode.setState(null, CompilationState.SPLIT);
+        return functionNode;
     }
 
     private static List<FunctionNode> directChildren(final FunctionNode functionNode) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Fri Sep 18 14:21:22 2015 -0700
@@ -33,10 +33,8 @@
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
 
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
-import jdk.nashorn.internal.AssertsEnabled;
 import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -74,40 +72,6 @@
         SETTER
     }
 
-    /** Compilation states available */
-    public enum CompilationState {
-        /** compiler is ready */
-        INITIALIZED,
-        /** method has been parsed */
-        PARSED,
-        /** method has been parsed */
-        PARSE_ERROR,
-        /** constant folding pass */
-        CONSTANT_FOLDED,
-        /** method has been lowered */
-        LOWERED,
-        /** program points have been assigned to unique locations */
-        PROGRAM_POINTS_ASSIGNED,
-        /** any transformations of builtins have taken place, e.g. apply=&gt;call */
-        BUILTINS_TRANSFORMED,
-        /** method has been split */
-        SPLIT,
-        /** method has had symbols assigned */
-        SYMBOLS_ASSIGNED,
-        /** computed scope depths for symbols */
-        SCOPE_DEPTHS_COMPUTED,
-        /** method has had types calculated*/
-        OPTIMISTIC_TYPES_ASSIGNED,
-        /** method has had types calculated */
-        LOCAL_VARIABLE_TYPES_CALCULATED,
-        /** compile units reused (optional) */
-        COMPILE_UNITS_REUSED,
-        /** method has been emitted to bytecode */
-        BYTECODE_GENERATED,
-        /** method has been installed */
-        BYTECODE_INSTALLED
-    }
-
     /** Source of entity. */
     private transient final Source source;
 
@@ -145,10 +109,6 @@
     /** Method's namespace. */
     private transient final Namespace namespace;
 
-    /** Current compilation state */
-    @Ignore
-    private final EnumSet<CompilationState> compilationState;
-
     /** Number of properties of "this" object assigned in this function */
     @Ignore
     private final int thisProperties;
@@ -306,7 +266,6 @@
      * @param kind       kind of function as in {@link FunctionNode.Kind}
      * @param flags      initial flags
      * @param body       body of the function
-     * @param state      The initial state from the parser. Must be one of {@link CompilationState#PARSED} and {@link CompilationState#PARSE_ERROR}
      * @param endParserState The parser state at the end of the parsing.
      */
     public FunctionNode(
@@ -323,7 +282,6 @@
         final FunctionNode.Kind kind,
         final int flags,
         final Block body,
-        final CompilationState state,
         final Object endParserState) {
         super(token, finish);
 
@@ -336,7 +294,6 @@
         this.firstToken       = firstToken;
         this.lastToken        = lastToken;
         this.namespace        = namespace;
-        this.compilationState = EnumSet.of(CompilationState.INITIALIZED, state);
         this.flags            = flags;
         this.compileUnit      = null;
         this.body             = body;
@@ -353,7 +310,6 @@
         final String name,
         final Type returnType,
         final CompileUnit compileUnit,
-        final EnumSet<CompilationState> compilationState,
         final Block body,
         final List<IdentNode> parameters,
         final int thisProperties,
@@ -368,7 +324,6 @@
         this.returnType       = returnType;
         this.compileUnit      = compileUnit;
         this.lastToken        = lastToken;
-        this.compilationState = compilationState;
         this.body             = body;
         this.parameters       = parameters;
         this.thisProperties   = thisProperties;
@@ -468,7 +423,6 @@
             name,
             returnType,
             compileUnit,
-            compilationState,
             body,
             parameters,
             thisProperties,
@@ -544,80 +498,6 @@
     }
 
     /**
-     * Get the compilation state of this function
-     * @return the compilation state
-     */
-    public EnumSet<CompilationState> getState() {
-        return compilationState;
-    }
-
-    /**
-     * Check whether this FunctionNode has reached a give CompilationState.
-     *
-     * @param state the state to check for
-     * @return true of the node is in the given state
-     */
-    public boolean hasState(final EnumSet<CompilationState> state) {
-        return !AssertsEnabled.assertsEnabled() || compilationState.containsAll(state);
-    }
-
-    /**
-     * Add a state to the total CompilationState of this node, e.g. if
-     * FunctionNode has been lowered, the compiler will add
-     * {@code CompilationState#LOWERED} to the state vector
-     *
-     * @param lc lexical context
-     * @param state {@link CompilationState} to add
-     * @return function node or a new one if state was changed
-     */
-    public FunctionNode setState(final LexicalContext lc, final CompilationState state) {
-        if (!AssertsEnabled.assertsEnabled() || this.compilationState.contains(state)) {
-            return this;
-        }
-        final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
-        newState.add(state);
-        return setCompilationState(lc, newState);
-    }
-
-    /**
-     * Copy a compilation state from an original function to this function. Used when creating synthetic
-     * function nodes by the splitter.
-     *
-     * @param lc lexical context
-     * @param original the original function node to copy compilation state from
-     * @return function node or a new one if state was changed
-     */
-    public FunctionNode copyCompilationState(final LexicalContext lc, final FunctionNode original) {
-        final EnumSet<CompilationState> origState = original.compilationState;
-        if (!AssertsEnabled.assertsEnabled() || this.compilationState.containsAll(origState)) {
-            return this;
-        }
-        final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
-        newState.addAll(origState);
-        return setCompilationState(lc, newState);
-    }
-
-    private FunctionNode setCompilationState(final LexicalContext lc, final EnumSet<CompilationState> compilationState) {
-        return Node.replaceInLexicalContext(
-                lc,
-                this,
-                new FunctionNode(
-                        this,
-                        lastToken,
-                        endParserState,
-                        flags,
-                        name,
-                        returnType,
-                        compileUnit,
-                        compilationState,
-                        body,
-                        parameters,
-                        thisProperties,
-                        rootClass, source, namespace));
-    }
-
-
-    /**
      * Create a unique name in the namespace of this FunctionNode
      * @param base prefix for name
      * @return base if no collision exists, otherwise a name prefix with base
@@ -682,7 +562,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
@@ -823,7 +702,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
@@ -919,7 +797,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
@@ -996,7 +873,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
@@ -1070,7 +946,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
@@ -1158,7 +1033,6 @@
                 name,
                 type,
                 compileUnit,
-                compilationState,
                 body,
                 parameters,
                 thisProperties,
@@ -1224,7 +1098,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
@@ -1280,7 +1153,6 @@
                         name,
                         returnType,
                         compileUnit,
-                        compilationState,
                         body,
                         parameters,
                         thisProperties,
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Fri Sep 18 14:21:22 2015 -0700
@@ -345,7 +345,8 @@
     /**
      * Given a script object and a Java type, converts the script object into the desired Java type. Currently it
      * performs shallow creation of Java arrays, as well as wrapping of objects in Lists, Dequeues, Queues,
-     * and Collections. Example:
+     * and Collections. If conversion is not possible or fails for some reason, TypeError is thrown.
+     * Example:
      * <pre>
      * var anArray = [1, "13", false]
      * var javaIntArray = Java.to(anArray, "int[]")
@@ -389,7 +390,11 @@
         }
 
         if(targetClass.isArray()) {
-            return JSType.toJavaArray(obj, targetClass.getComponentType());
+            try {
+                return JSType.toJavaArray(obj, targetClass.getComponentType());
+            } catch (final Exception exp) {
+                throw typeError(exp, "java.array.conversion.failed", targetClass.getName());
+            }
         }
 
         if (targetClass == List.class || targetClass == Deque.class || targetClass == Queue.class || targetClass == Collection.class) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java	Fri Sep 18 14:21:22 2015 -0700
@@ -134,7 +134,7 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
         final Object retval = createProperty(name);
         if (isValid(programPoint)) {
             throw new UnwarrantedOptimismException(retval, programPoint);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Fri Sep 18 14:21:22 2015 -0700
@@ -84,7 +84,6 @@
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
@@ -487,7 +486,6 @@
     }
 
     private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){
-        final CompilationState state = errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED;
         // Start new block.
         final FunctionNode functionNode =
             new FunctionNode(
@@ -504,7 +502,6 @@
                 kind,
                 function.getFlags(),
                 body,
-                state,
                 function.getEndParserState());
 
         printAST(functionNode);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java	Fri Sep 18 14:21:22 2015 -0700
@@ -101,16 +101,24 @@
     public StoredScript loadScript(Source source, String functionKey);
 
     /**
-     * Returns a new code installer that shares most of the functionality of this code installer, but uses a
-     * new, independent class loader.
-     * @return a new code installer with a new independent class loader.
+     * Returns a code installer {@code #isCompatibleWith(CodeInstaller) compatible with} this installer, but
+     * is suitable for on-demand compilations. Can return itself if it is itself suitable.
+     * @return a compatible code installer suitable for on-demand compilations.
      */
-    public CodeInstaller withNewLoader();
+    public CodeInstaller getOnDemandCompilationInstaller();
+
+    /**
+     * Returns a code installer {@code #isCompatibleWith(CodeInstaller) compatible with} this installer, but
+     * is suitable for installation of multiple classes that reference each other by name. Should be used when
+     * a compilation job produces multiple compilation units. Can return itself if it is itself suitable.
+     * @return a compatible code installer suitable for installation of multiple classes.
+     */
+    public CodeInstaller getMultiClassCodeInstaller();
 
     /**
      * Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
      * an equivalence relation, and installers are supposed to be compatible with those they create using
-     * {@link #withNewLoader()}.
+     * {@link #getOnDemandCompilationInstaller()}.
      * @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.
      */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Fri Sep 18 14:21:22 2015 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.runtime;
 
+import static jdk.internal.org.objectweb.asm.Opcodes.V1_7;
 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
@@ -41,8 +42,10 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.SwitchPoint;
+import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.net.MalformedURLException;
@@ -61,14 +64,18 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.LongAdder;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 import java.util.logging.Level;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
 import jdk.nashorn.api.scripting.ClassFilter;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
@@ -87,6 +94,7 @@
 import jdk.nashorn.internal.runtime.logging.Logger;
 import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo;
 import jdk.nashorn.internal.runtime.options.Options;
+import sun.misc.Unsafe;
 
 /**
  * This class manages the global state of execution. Context is immutable.
@@ -128,9 +136,12 @@
     private static final String LOAD_FX = "fx:";
     private static final String LOAD_NASHORN = "nashorn:";
 
-    private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
-    private static MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
+    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+    private static final MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
 
+    private static final LongAdder NAMED_INSTALLED_SCRIPT_COUNT = new LongAdder();
+    private static final LongAdder ANONYMOUS_INSTALLED_SCRIPT_COUNT = new LongAdder();
+    private static final boolean DISABLE_VM_ANONYMOUS_CLASSES = Options.getBooleanProperty("nashorn.disableVmAnonymousClasses");
     /**
      * Should scripts use only object slots for fields, or dual long/object slots? The default
      * behaviour is to couple this to optimistic types, using dual representation if optimistic types are enabled
@@ -163,25 +174,24 @@
         DebuggerSupport.FORCELOAD = true;
     }
 
+    static long getNamedInstalledScriptCount() {
+        return NAMED_INSTALLED_SCRIPT_COUNT.sum();
+    }
+
+    static long getAnonymousInstalledScriptCount() {
+        return ANONYMOUS_INSTALLED_SCRIPT_COUNT.sum();
+    }
+
     /**
      * 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 {
-        private final Context      context;
-        private final ScriptLoader loader;
-        private final CodeSource   codeSource;
-        private int usageCount = 0;
-        private int bytesDefined = 0;
+    private abstract static class ContextCodeInstaller implements CodeInstaller {
+        final Context context;
+        final CodeSource codeSource;
 
-        // We reuse this installer for 10 compilations or 200000 defined bytes. Usually the first condition
-        // will occur much earlier, the second is a safety measure for very large scripts/functions.
-        private final static int MAX_USAGES = 10;
-        private final static int MAX_BYTES_DEFINED = 200_000;
-
-        private ContextCodeInstaller(final Context context, final ScriptLoader loader, final CodeSource codeSource) {
-            this.context    = context;
-            this.loader     = loader;
+        ContextCodeInstaller(final Context context, final CodeSource codeSource) {
+            this.context = context;
             this.codeSource = codeSource;
         }
 
@@ -191,14 +201,6 @@
         }
 
         @Override
-        public Class<?> install(final String className, final byte[] bytecode) {
-            usageCount++;
-            bytesDefined += bytecode.length;
-            final String   binaryName = Compiler.binaryName(className);
-            return loader.installClass(binaryName, bytecode, codeSource);
-        }
-
-        @Override
         public void initialize(final Collection<Class<?>> classes, final Source source, final Object[] constants) {
             try {
                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@@ -250,15 +252,6 @@
         }
 
         @Override
-        public CodeInstaller withNewLoader() {
-            // Reuse this installer if we're within our limits.
-            if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
-                return this;
-            }
-            return new ContextCodeInstaller(context, context.createNewLoader(), codeSource);
-        }
-
-        @Override
         public boolean isCompatibleWith(final CodeInstaller other) {
             if (other instanceof ContextCodeInstaller) {
                 final ContextCodeInstaller cci = (ContextCodeInstaller)other;
@@ -268,6 +261,116 @@
         }
     }
 
+    private static class NamedContextCodeInstaller extends ContextCodeInstaller {
+        private final ScriptLoader loader;
+        private int usageCount = 0;
+        private int bytesDefined = 0;
+
+        // We reuse this installer for 10 compilations or 200000 defined bytes. Usually the first condition
+        // will occur much earlier, the second is a safety measure for very large scripts/functions.
+        private final static int MAX_USAGES = 10;
+        private final static int MAX_BYTES_DEFINED = 200_000;
+
+        private NamedContextCodeInstaller(final Context context, final CodeSource codeSource, final ScriptLoader loader) {
+            super(context, codeSource);
+            this.loader = loader;
+        }
+
+        @Override
+        public Class<?> install(final String className, final byte[] bytecode) {
+            usageCount++;
+            bytesDefined += bytecode.length;
+            NAMED_INSTALLED_SCRIPT_COUNT.increment();
+            return loader.installClass(Compiler.binaryName(className), bytecode, codeSource);
+        }
+
+        @Override
+        public CodeInstaller getOnDemandCompilationInstaller() {
+            // Reuse this installer if we're within our limits.
+            if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
+                return this;
+            }
+            return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader());
+        }
+
+        @Override
+        public CodeInstaller getMultiClassCodeInstaller() {
+            // This installer is perfectly suitable for installing multiple classes that reference each other
+            // as it produces classes with resolvable names, all defined in a single class loader.
+            return this;
+        }
+    }
+
+    private final Map<CodeSource, Reference<Class<?>>> anonymousHostClasses = new ConcurrentHashMap<>();
+
+    private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller {
+        private static final Unsafe UNSAFE = getUnsafe();
+        private static final String ANONYMOUS_HOST_CLASS_NAME = Compiler.SCRIPTS_PACKAGE.replace('/', '.') + ".AnonymousHost";
+        private static final byte[] ANONYMOUS_HOST_CLASS_BYTES = getAnonymousHostClassBytes();
+
+        private final Class<?> hostClass;
+
+        private AnonymousContextCodeInstaller(final Context context, final CodeSource codeSource) {
+            super(context, codeSource);
+            hostClass = getAnonymousHostClass();
+        }
+
+        @Override
+        public Class<?> install(final String className, final byte[] bytecode) {
+            ANONYMOUS_INSTALLED_SCRIPT_COUNT.increment();
+            return UNSAFE.defineAnonymousClass(hostClass, bytecode, null);
+        }
+
+        @Override
+        public CodeInstaller getOnDemandCompilationInstaller() {
+            // This code loader can be indefinitely reused for on-demand recompilations for the same code source.
+            return this;
+        }
+
+        @Override
+        public CodeInstaller getMultiClassCodeInstaller() {
+            // This code loader can not be used to install multiple classes that reference each other, as they
+            // would have no resolvable names. Therefore, in such situation we must revert to an installer that
+            // produces named classes.
+            return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader());
+        }
+
+        private Class<?> getAnonymousHostClass() {
+            final Reference<Class<?>> ref = context.anonymousHostClasses.get(codeSource);
+            if (ref != null) {
+                final Class<?> existingHostClass = ref.get();
+                if (existingHostClass != null) {
+                    return existingHostClass;
+                }
+            }
+            final Class<?> newHostClass = context.createNewLoader().installClass(ANONYMOUS_HOST_CLASS_NAME, ANONYMOUS_HOST_CLASS_BYTES, codeSource);
+            context.anonymousHostClasses.put(codeSource, new WeakReference<>(newHostClass));
+            return newHostClass;
+        }
+
+        private static final byte[] getAnonymousHostClassBytes() {
+            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+            cw.visit(V1_7, Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, ANONYMOUS_HOST_CLASS_NAME.replace('.', '/'), null, "java/lang/Object", null);
+            cw.visitEnd();
+            return cw.toByteArray();
+        }
+
+        private static Unsafe getUnsafe() {
+            return AccessController.doPrivileged(new PrivilegedAction<Unsafe>() {
+                @Override
+                public Unsafe run() {
+                    try {
+                        final Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+                        theUnsafeField.setAccessible(true);
+                        return (Unsafe)theUnsafeField.get(null);
+                    } catch (final ReflectiveOperationException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            });
+        }
+    }
+
     /** Is Context global debug mode enabled ? */
     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
 
@@ -1294,9 +1397,15 @@
         }
 
         final URL          url    = source.getURL();
-        final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
-        final CodeInstaller installer = new ContextCodeInstaller(this, loader, cs);
+        final CodeInstaller installer;
+        if (DISABLE_VM_ANONYMOUS_CLASSES || env._persistent_cache || !env._lazy_compilation) {
+            // Persistent code cache and eager compilation preclude use of VM anonymous classes
+            final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
+            installer = new NamedContextCodeInstaller(this, cs, loader);
+        } else {
+            installer = new AnonymousContextCodeInstaller(this, cs);
+        }
 
         if (storedScript == null) {
             final CompilationPhases phases = Compiler.CompilationPhases.COMPILE_ALL;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Debug.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Debug.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Fri Sep 18 14:21:22 2015 -0700
@@ -206,7 +206,7 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String key, final int programPoint) {
+    protected Object invokeNoSuchProperty(final String key, final boolean isScope, final int programPoint) {
         final Object retval = createProperty(key);
         if (isValid(programPoint)) {
             throw new UnwarrantedOptimismException(retval, programPoint);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java	Fri Sep 18 14:21:22 2015 -0700
@@ -54,32 +54,36 @@
  * 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 {
     /** 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;
+
+    /** 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;
@@ -95,24 +99,21 @@
     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;
 
         if (Context.DEBUG) {
             count.increment();
@@ -120,20 +121,22 @@
     }
 
     /**
-     * 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) {
         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;
 
         if (Context.DEBUG) {
             count.increment();
@@ -142,12 +145,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);
     }
 
     private void writeObject(final ObjectOutputStream out) throws IOException {
@@ -183,7 +186,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 +208,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 +230,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 +256,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 +271,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 +287,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 +300,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 +321,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 +337,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 +355,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 +379,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 +392,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,13 +436,10 @@
      * @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);
-        }
+    public final PropertyMap addPropertyNoHistory(final Property property) {
+        propertyAdded(property, true);
         final PropertyHashMap newProperties = properties.immutableAdd(property);
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
-        newMap.updateFlagsAndBoundaries(property);
+        final PropertyMap newMap = new PropertyMap(this, newProperties, newFlags(property), newFieldCount(property), newSpillLength(property));
         newMap.updateFreeSlots(null, property);
 
         return newMap;
@@ -439,16 +452,13 @@
      *
      * @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 = new PropertyMap(this, newProperties, newFlags(property), newFieldCount(property), newSpillLength(property));
             newMap.updateFreeSlots(null, property);
             addToHistory(property, newMap);
         }
@@ -463,10 +473,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 +485,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 = new PropertyMap(this, 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 = new PropertyMap(this, newProperties, flags, fieldCount - 1, spillLength);
                 newMap.freeSlots = freeSlots;
             } else {
-                newMap = new PropertyMap(this, newProperties);
+                newMap = new PropertyMap(this, newProperties, flags, fieldCount, spillLength);
                 newMap.updateFreeSlots(property, null);
             }
             addToHistory(property, newMap);
@@ -500,13 +508,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 +531,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 = new PropertyMap(this, newProperties, flags, fieldCount, newSpillLength);
+
         if (!sameType) {
-            newMap.spillLength = Math.max(spillLength, newProperty.getSlot() + 1);
             newMap.updateFreeSlots(oldProperty, newProperty);
         }
         return newMap;
@@ -551,7 +557,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 +568,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 +579,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 = new PropertyMap(this, 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,7 +599,7 @@
      *
      * @return Properties as an array.
      */
-    public Property[] getProperties() {
+    public final Property[] getProperties() {
         return properties.getProperties();
     }
 
@@ -602,7 +608,7 @@
      *
      * @return class name of owner objects.
      */
-    public String getClassName() {
+    public final String getClassName() {
         return className;
     }
 
@@ -612,9 +618,7 @@
      * @return New map with {@link #NOT_EXTENSIBLE} flag set.
      */
     PropertyMap preventExtensions() {
-        final PropertyMap newMap = new PropertyMap(this);
-        newMap.flags |= NOT_EXTENSIBLE;
-        return newMap;
+        return new PropertyMap(this, properties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
     }
 
     /**
@@ -630,10 +634,7 @@
             newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE));
         }
 
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
-        newMap.flags |= NOT_EXTENSIBLE;
-
-        return newMap;
+        return new PropertyMap(this, newProperties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
     }
 
     /**
@@ -655,10 +656,7 @@
             newProperties = newProperties.immutableAdd(oldProperty.addFlags(propertyFlags));
         }
 
-        final PropertyMap newMap = new PropertyMap(this, newProperties);
-        newMap.flags |= NOT_EXTENSIBLE;
-
-        return newMap;
+        return new PropertyMap(this, newProperties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
     }
 
     /**
@@ -830,13 +828,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.
@@ -914,12 +905,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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Fri Sep 18 14:21:22 2015 -0700
@@ -368,8 +368,8 @@
     }
 
     @Override
-    PropertyMap getAllocatorMap() {
-        return allocationStrategy.getAllocatorMap();
+    PropertyMap getAllocatorMap(final ScriptObject prototype) {
+        return allocationStrategy.getAllocatorMap(prototype);
     }
 
     @Override
@@ -649,7 +649,7 @@
      */
     private CodeInstaller getInstallerForNewCode() {
         final ScriptEnvironment env = installer.getContext().getEnv();
-        return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
+        return env._optimistic_types || env._loader_per_compile ? installer.getOnDemandCompilationInstaller() : installer;
     }
 
     Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType,
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Sep 18 14:21:22 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(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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Sep 18 14:21:22 2015 -0700
@@ -149,7 +149,7 @@
     /** Method handle to retrieve prototype of this object */
     public static final MethodHandle GETPROTO      = findOwnMH_V("getProto", ScriptObject.class);
 
-    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class);
+    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class, boolean.class);
     static final MethodHandle GLOBALFILTER       = findOwnMH_S("globalFilter", Object.class, Object.class);
     static final MethodHandle DECLARE_AND_SET    = findOwnMH_V("declareAndSet", void.class, String.class, Object.class);
 
@@ -809,9 +809,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 +834,7 @@
         if (deep) {
             final ScriptObject myProto = getProto();
             if (myProto != null) {
-                return myProto.hasProperty(key, deep);
+                return myProto.hasProperty(key, true);
             }
         }
 
@@ -1258,11 +1260,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 +1313,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));
         }
@@ -2012,11 +2011,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;
@@ -2024,30 +2023,30 @@
                 // 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));
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
         Context.getContextTrusted().getLogger(ObjectClassGenerator.class).warning("Megamorphic getter: " + desc + " " + name + " " +isMethod);
-        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
+        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, NashornCallSiteDescriptor.isScope(desc));
         final MethodHandle guard   = getScriptObjectGuard(desc.getMethodType(), true);
         return new GuardedInvocation(invoker, guard);
     }
 
     @SuppressWarnings("unused")
-    private Object megamorphicGet(final String key, final boolean isMethod) {
+    private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
         final FindProperty find = findProperty(key, true);
         if (find != null) {
             return find.getObjectValue();
         }
 
-        return isMethod ? getNoSuchMethod(key, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
+        return isMethod ? getNoSuchMethod(key, isScope, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, isScope, INVALID_PROGRAM_POINT);
     }
 
     // Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
@@ -2128,17 +2127,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());
+        }
     }
 
     /**
@@ -2220,7 +2234,7 @@
         return new GuardedInvocation(
                 Lookup.EMPTY_SETTER,
                 NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
-                getProtoSwitchPoint(name, null),
+                getProtoSwitchPoints(name, null),
                 explicitInstanceOfCheck ? null : ClassCastException.class);
     }
 
@@ -2366,7 +2380,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);
             }
@@ -2382,20 +2396,21 @@
     /**
      * Invoke fall back if a property is not found.
      * @param name Name of property.
+     * @param isScope is this a scope access?
      * @param programPoint program point
      * @return Result from call.
      */
-    protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
         final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
+        final Object func = (find != null)? find.getObjectValue() : null;
 
         Object ret = UNDEFINED;
-
-        if (find != null) {
-            final Object func = find.getObjectValue();
-
-            if (func instanceof ScriptFunction) {
-                ret = ScriptRuntime.apply((ScriptFunction)func, this, name);
-            }
+        if (func instanceof ScriptFunction) {
+            final ScriptFunction sfunc = (ScriptFunction)func;
+            final Object self = isScope && sfunc.isStrict()? UNDEFINED : this;
+            ret = ScriptRuntime.apply(sfunc, self, name);
+        } else if (isScope) {
+            throw referenceError("not.defined", name);
         }
 
         if (isValid(programPoint)) {
@@ -2409,21 +2424,27 @@
     /**
      * Get __noSuchMethod__ as a function bound to this object and {@code name} if it is defined.
      * @param name the method name
+     * @param isScope is this a scope access?
      * @return the bound function, or undefined
      */
-    private Object getNoSuchMethod(final String name, final int programPoint) {
+    private Object getNoSuchMethod(final String name, final boolean isScope, final int programPoint) {
         final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
 
         if (find == null) {
-            return invokeNoSuchProperty(name, programPoint);
+            return invokeNoSuchProperty(name, isScope, programPoint);
         }
 
         final Object value = find.getObjectValue();
         if (!(value instanceof ScriptFunction)) {
+            if (isScope) {
+                throw referenceError("not.defined", name);
+            }
             return UNDEFINED;
         }
 
-        return ((ScriptFunction)value).createBound(this, new Object[] {name});
+        final ScriptFunction func = (ScriptFunction)value;
+        final Object self = isScope && func.isStrict()? UNDEFINED : this;
+        return func.createBound(self, new Object[] {name});
     }
 
     private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String name) {
@@ -2432,7 +2453,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);
     }
 
@@ -2738,7 +2759,7 @@
             }
         }
 
-        return JSType.toInt32(invokeNoSuchProperty(key, programPoint));
+        return JSType.toInt32(invokeNoSuchProperty(key, false, programPoint));
     }
 
     @Override
@@ -2820,7 +2841,7 @@
             }
         }
 
-        return JSType.toLong(invokeNoSuchProperty(key, programPoint));
+        return JSType.toLong(invokeNoSuchProperty(key, false, programPoint));
     }
 
     @Override
@@ -2902,7 +2923,7 @@
             }
         }
 
-        return JSType.toNumber(invokeNoSuchProperty(key, INVALID_PROGRAM_POINT));
+        return JSType.toNumber(invokeNoSuchProperty(key, false, INVALID_PROGRAM_POINT));
     }
 
     @Override
@@ -2983,7 +3004,7 @@
             }
         }
 
-        return invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
+        return invokeNoSuchProperty(key, false, INVALID_PROGRAM_POINT);
     }
 
     @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SharedPropertyMap.java	Fri Sep 18 14:21:22 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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java	Fri Sep 18 14:21:22 2015 -0700
@@ -220,19 +220,20 @@
             }
 
             final long total = t - startTime;
-            sb.append('\n');
-            sb.append("Total runtime: ").
+            return sb.append("\nTotal runtime: ").
                 append(toMillisPrint(total)).
                 append(" ms (Non-runtime: ").
                 append(toMillisPrint(knownTime)).
                 append(" ms [").
                 append((int)(knownTime * 100.0 / total)).
-                append("%])");
-
-            sb.append("\n\nEmitted compile units: ").
-                append(CompileUnit.getEmittedUnitCount());
-
-            return sb.toString();
+                append("%])").
+                append("\n\nEmitted compile units: ").
+                append(CompileUnit.getEmittedUnitCount()).
+                append("\nCompile units installed as named classes: ").
+                append(Context.getNamedInstalledScriptCount()).
+                append("\nCompile units installed as anonymous classes: ").
+                append(Context.getAnonymousInstalledScriptCount()).
+                toString();
         }
 
         private void accumulateTime(final String module, final long duration) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Fri Sep 18 14:21:22 2015 -0700
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.runtime;
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -45,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);
@@ -209,16 +210,18 @@
     }
 
     @Override
-    protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+    protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
         FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
         if (find != null) {
             final Object func = find.getObjectValue();
             if (func instanceof ScriptFunction) {
-                return ScriptRuntime.apply((ScriptFunction)func, expression, name);
+                final ScriptFunction sfunc = (ScriptFunction)func;
+                final Object self = isScope && sfunc.isStrict()? UNDEFINED : expression;
+                return ScriptRuntime.apply(sfunc, self, name);
             }
         }
 
-        return getProto().invokeNoSuchProperty(name, programPoint);
+        return getProto().invokeNoSuchProperty(name, isScope, programPoint);
     }
 
     @Override
@@ -357,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.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Fri Sep 18 10:46:55 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Fri Sep 18 14:21:22 2015 -0700
@@ -150,6 +150,7 @@
 type.error.method.not.constructor=Java method {0} cannot be used as a constructor.
 type.error.env.not.object=$ENV must be an Object.
 type.error.unsupported.java.to.type=Unsupported Java.to target type {0}.
+type.error.java.array.conversion.failed=Java.to conversion to array type {0} failed
 type.error.constructor.requires.new=Constructor {0} requires "new".
 type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}.
 
--- a/test/script/basic/JDK-8044750.js	Fri Sep 18 10:46:55 2015 -0700
+++ b/test/script/basic/JDK-8044750.js	Fri Sep 18 14:21:22 2015 -0700
@@ -25,6 +25,8 @@
  * JDK-8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook
  *
  * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=16
  * @run
  */
 
@@ -40,7 +42,9 @@
     }
 }
 
-for (var i = 0; i < 20; i++) {
+var LIMIT = 20; // should be more than megamorphic threshold set via @option
+
+for (var i = 0; i < LIMIT; i++) {
     var obj = {};
     obj.foo = i;
     obj[i] = i;
@@ -51,3 +55,30 @@
 // callsite inside func should see __noSuchProperty__
 // hook on global scope object.
 func({});
+
+function checkFoo() {
+    with({}) {
+        try {
+            foo;
+            return true;
+        } catch (e) {
+            return false;
+        }
+    }
+}
+
+var oldNoSuchProperty = this.__noSuchProperty__;
+delete this.__noSuchProperty__;
+
+// keep deleting/restorting __noSuchProperty__ alternatively
+// to make "foo" access in checkFoo function megamorphic!
+
+for (var i = 0; i < LIMIT; i++) {
+    // no __noSuchProperty__ and 'with' scope object has no 'foo'
+    delete __noSuchProperty__;
+    Assert.assertFalse(checkFoo(), "Expected false in iteration " + i);
+
+    // __noSuchProperty__ is exists but 'with' scope object has no 'foo'
+    this.__noSuchProperty__ = oldNoSuchProperty;
+    Assert.assertTrue(checkFoo(), "Expected true in iteration " + i);
+}
--- a/test/script/basic/JDK-8134569.js	Fri Sep 18 10:46:55 2015 -0700
+++ b/test/script/basic/JDK-8134569.js	Fri Sep 18 14:21:22 2015 -0700
@@ -62,67 +62,146 @@
     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) }
 
-var a, b;
+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);
--- a/test/script/basic/JDK-8134569.js.EXPECTED	Fri Sep 18 10:46:55 2015 -0700
+++ b/test/script/basic/JDK-8134569.js.EXPECTED	Fri Sep 18 14:21:22 2015 -0700
@@ -1,16 +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	Fri Sep 18 14:21:22 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-8136544.js	Fri Sep 18 14:21:22 2015 -0700
@@ -0,0 +1,65 @@
+/*
+ * 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-8136544: Call site switching to megamorphic causes incorrect property read
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=8
+ * @run
+ */
+
+var ScriptContext = Java.type("javax.script.ScriptContext");
+var ScriptEngineManager = Java.type("javax.script.ScriptEngineManager");
+var m = new ScriptEngineManager();
+var e = m.getEngineByName("nashorn");
+
+var scope = e.getBindings(ScriptContext.ENGINE_SCOPE);
+var MYVAR = "myvar";
+
+function loopupVar() {
+    try {
+        e.eval(MYVAR);
+        return true;
+    } catch (e) {
+        return false;
+    }
+}
+
+// make sure we exercise callsite beyond megamorphic threshold we set
+// in this test via nashorn.unstable.relink.threshold property
+// In each iteration, callsite is exercised twice (two evals)
+// So, LIMIT should be more than 4 to exercise megamorphic callsites.
+
+var LIMIT = 5; // This LIMIT should be more than 4
+
+for (var i = 0; i < LIMIT; i++) {
+    // remove the variable and lookup
+    delete scope[MYVAR];
+    Assert.assertFalse(loopupVar(), "Expected true in iteration " + i);
+
+    // set that variable and check again
+    scope[MYVAR] = "foo";
+    Assert.assertTrue(loopupVar(), "Expected false in iteration " + i);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8136694.js	Fri Sep 18 14:21:22 2015 -0700
@@ -0,0 +1,74 @@
+/*
+ * 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-8136694: Megemorphic scope access does not throw ReferenceError when property is missing
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=16
+ * @run
+ */
+
+function checkFoo() {
+    try {
+        // The 'foo' access becomes megamorphic
+        foo;
+        return true;
+    } catch (e) {
+        return false;
+    }
+}
+
+
+// Similar check for 'with' blocks as well.
+function checkFooInWith() {
+    with({}) {
+        try {
+            // The 'foo' access becomes megamorphic
+            foo;
+            return true;
+        } catch (e) {
+            return false;
+        }
+    }
+}
+
+function loop(checker) {
+    // LIMIT has to be more than the megamorphic threashold
+    // set via @option in this test header!
+    var LIMIT = 20;
+    for (var i = 0; i < LIMIT; i++) {
+        // make sure global has no "foo"
+        delete foo;
+        Assert.assertFalse(checker(), "Expected false in interation " + i);
+
+        // now add 'foo' in global
+        foo = 44;
+        Assert.assertTrue(checker(), "Expected true in interation " + i);
+    }
+}
+
+
+loop(checkFoo);
+loop(checkFooInWith);
--- a/test/script/basic/javaarrayconversion.js	Fri Sep 18 10:46:55 2015 -0700
+++ b/test/script/basic/javaarrayconversion.js	Fri Sep 18 14:21:22 2015 -0700
@@ -128,24 +128,32 @@
 // Converting to string, toString takes precedence over valueOf
 test({ valueOf: function() { return "42"; },  toString: function() { return "43"; } }, "java.lang.String", "43")
 
+function assertCanConvert(sourceType, targetType) {
+  Java.to([new (Java.type(sourceType))()], targetType + "[]")
+  ++testCount;
+}
+
 function assertCantConvert(sourceType, targetType) {
   try {
-    Java.to([new Java.type(sourceType)()], targetType + "[]")
+    Java.to([new (Java.type(sourceType))()], targetType + "[]")
     throw "no TypeError encountered"
   } catch(e) {
-      if(!(e instanceof TypeError)) {
+      if(!(e instanceof TypeError) ||
+          !e.message.startsWith("Java.to conversion to array type")) {
         throw e;
       }
       ++testCount;
   }
 }
 
+// Arbitrary POJOs to JS Primitive type should work
+assertCanConvert("java.util.BitSet", "int")
+assertCanConvert("java.util.BitSet", "double")
+assertCanConvert("java.util.BitSet", "long")
+assertCanConvert("java.util.BitSet", "boolean")
+assertCanConvert("java.util.BitSet", "java.lang.String")
+
 // Arbitrary POJOs can't be converted to Java values
-assertCantConvert("java.util.BitSet", "int")
-assertCantConvert("java.util.BitSet", "double")
-assertCantConvert("java.util.BitSet", "long")
-assertCantConvert("java.util.BitSet", "boolean")
-assertCantConvert("java.util.BitSet", "java.lang.String")
 assertCantConvert("java.util.BitSet", "java.lang.Double")
 assertCantConvert("java.util.BitSet", "java.lang.Long")
 
--- a/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Fri Sep 18 10:46:55 2015 -0700
+++ b/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Fri Sep 18 14:21:22 2015 -0700
@@ -26,6 +26,7 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 import javax.script.Bindings;
@@ -820,4 +821,38 @@
     public void recursiveEvalCallScriptContextTest() throws ScriptException {
         new RecursiveEval().program();
     }
+
+    private static final String VAR_NAME = "myvar";
+
+    private static boolean lookupVar(final ScriptEngine engine, final String varName) {
+        try {
+            engine.eval(varName);
+            return true;
+        } catch (final ScriptException se) {
+            return false;
+        }
+    }
+
+    // @bug 8136544: Call site switching to megamorphic causes incorrect property read
+    @Test
+    public void megamorphicPropertyReadTest() throws ScriptException {
+        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+        final ScriptEngine engine = factory.getScriptEngine();
+        final Bindings scope = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+        boolean ret;
+
+        // Why 16 is the upper limit of this loop? The default nashorn dynalink megamorphic threshold is 16.
+        // See jdk.nashorn.internal.runtime.linker.Bootstrap.NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD
+        // We do, 'eval' of the same in this loop twice. So, 16*2 = 32 times that callsite in the script
+        // is exercised - much beyond the default megamorphic threshold.
+
+        for (int i = 0; i < 16; i++) {
+            scope.remove(VAR_NAME);
+            ret = lookupVar(engine, VAR_NAME);
+            assertFalse(ret, "Expected false in iteration " + i);
+            scope.put(VAR_NAME, "foo");
+            ret = lookupVar(engine, VAR_NAME);
+            assertTrue(ret, "Expected true in iteration " + i);
+        }
+    }
 }