Merge
authorlana
Thu, 03 Sep 2015 16:14:47 -0700
changeset 32446 a62e4c149f6f
parent 32433 053f7a765483 (current diff)
parent 32445 9d05e7490a07 (diff)
child 32447 ad25202a41d0
Merge
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AstSerializer.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java
--- a/nashorn/make/project.properties	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/make/project.properties	Thu Sep 03 16:14:47 2015 -0700
@@ -302,7 +302,7 @@
   -XX:+HeapDumpOnOutOfMemoryError
 
 # turn on assertions for tests
-run.test.jvmargs.main=${run.test.jvmargs.common} -esa -ea
+run.test.jvmargs.main=${run.test.jvmargs.common} -esa -ea -da:java.lang.invoke.LambdaFormEditor
 
 # Extra jvmargs that might be useful for debugging
 # and performance improvements/monitoring
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Thu Sep 03 16:14:47 2015 -0700
@@ -107,7 +107,7 @@
     private final AccessibleObject target;
     private final MethodType type;
 
-    public CallerSensitiveDynamicMethod(final AccessibleObject target) {
+    CallerSensitiveDynamicMethod(final AccessibleObject target) {
         super(getName(target));
         this.target = target;
         this.type = getMethodType(target);
@@ -115,8 +115,9 @@
 
     private static String getName(final AccessibleObject target) {
         final Member m = (Member)target;
-        return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
-                m.getName()));
+        final boolean constructor = m instanceof Constructor;
+        return getMethodNameWithSignature(getMethodType(target), constructor ? m.getName() :
+            getClassAndMethodName(m.getDeclaringClass(), m.getName()), !constructor);
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Thu Sep 03 16:14:47 2015 -0700
@@ -86,7 +86,9 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -242,6 +244,35 @@
         return methods.getFirst().isConstructor();
     }
 
+    @Override
+    public String toString() {
+        // First gather the names and sort them. This makes it consistent and easier to read.
+        final List<String> names = new ArrayList<>(methods.size());
+        int len = 0;
+        for (final SingleDynamicMethod m: methods) {
+            final String name = m.getName();
+            len += name.length();
+            names.add(name);
+        }
+        // Case insensitive sorting, so e.g. "Object" doesn't come before "boolean".
+        final Collator collator = Collator.getInstance();
+        collator.setStrength(Collator.SECONDARY);
+        Collections.sort(names, collator);
+
+        final String className = getClass().getName();
+        // Class name length + length of signatures + 2 chars/per signature for indentation and newline +
+        // 3 for brackets and initial newline
+        final int totalLength = className.length() + len + 2 * names.size() + 3;
+        final StringBuilder b = new StringBuilder(totalLength);
+        b.append('[').append(className).append('\n');
+        for(final String name: names) {
+            b.append(' ').append(name).append('\n');
+        }
+        b.append(']');
+        assert b.length() == totalLength;
+        return b.toString();
+    };
+
     ClassLoader getClassLoader() {
         return classLoader;
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Thu Sep 03 16:14:47 2015 -0700
@@ -122,13 +122,13 @@
      * @param constructor does this represent a constructor?
      */
     SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
-        super(getName(target, clazz, name));
+        super(getName(target, clazz, name, constructor));
         this.target = target;
         this.constructor = constructor;
     }
 
-    private static String getName(final MethodHandle target, final Class<?> clazz, final String name) {
-        return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
+    private static String getName(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
+        return getMethodNameWithSignature(target.type(), constructor ? name : getClassAndMethodName(clazz, name), !constructor);
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Thu Sep 03 16:14:47 2015 -0700
@@ -143,14 +143,18 @@
         return getMethodType().parameterList().equals(method.getMethodType().parameterList());
     }
 
-    static String getMethodNameWithSignature(final MethodType type, final String methodName) {
+    static String getMethodNameWithSignature(final MethodType type, final String methodName, final boolean withReturnType) {
         final String typeStr = type.toString();
         final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
         int secondParamIndex = typeStr.indexOf(',') + 1;
         if(secondParamIndex == 0) {
             secondParamIndex = retTypeIndex - 1;
         }
-        return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
+        final StringBuilder b = new StringBuilder();
+        if (withReturnType) {
+            b.append(typeStr, retTypeIndex, typeStr.length()).append(' ');
+        }
+        return b.append(methodName).append('(').append(typeStr, secondParamIndex, retTypeIndex).toString();
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Thu Sep 03 16:14:47 2015 -0700
@@ -51,6 +51,8 @@
     private String fileName;
     // script line number
     private int line;
+    // are the line and fileName unknown?
+    private boolean lineAndFileNameUnknown;
     // script column number
     private int column;
     // underlying ECMA error object - lazily initialized
@@ -92,27 +94,10 @@
      */
     protected NashornException(final String msg, final Throwable cause) {
         super(msg, cause == null ? null : cause);
-        // This is not so pretty - but it gets the job done. Note that the stack
-        // trace has been already filled by "fillInStackTrace" call from
-        // Throwable
-        // constructor and so we don't pay additional cost for it.
-
         // Hard luck - no column number info
         this.column = -1;
-
-        // Find the first JavaScript frame by walking and set file, line from it
-        // Usually, we should be able to find it in just few frames depth.
-        for (final StackTraceElement ste : getStackTrace()) {
-            if (ECMAErrors.isScriptFrame(ste)) {
-                // Whatever here is compiled from JavaScript code
-                this.fileName = ste.getFileName();
-                this.line = ste.getLineNumber();
-                return;
-            }
-        }
-
-        this.fileName = null;
-        this.line = 0;
+        // We can retrieve the line number and file name from the stack trace if needed
+        this.lineAndFileNameUnknown = true;
     }
 
     /**
@@ -121,6 +106,7 @@
      * @return the file name
      */
     public final String getFileName() {
+        ensureLineAndFileName();
         return fileName;
     }
 
@@ -131,6 +117,7 @@
      */
     public final void setFileName(final String fileName) {
         this.fileName = fileName;
+        lineAndFileNameUnknown = false;
     }
 
     /**
@@ -139,6 +126,7 @@
      * @return the line number
      */
     public final int getLineNumber() {
+        ensureLineAndFileName();
         return line;
     }
 
@@ -148,6 +136,7 @@
      * @param line the line number
      */
     public final void setLineNumber(final int line) {
+        lineAndFileNameUnknown = false;
         this.line = line;
     }
 
@@ -274,4 +263,19 @@
     public void setEcmaError(final Object ecmaError) {
         this.ecmaError = ecmaError;
     }
+
+    private void ensureLineAndFileName() {
+        if (lineAndFileNameUnknown) {
+            for (final StackTraceElement ste : getStackTrace()) {
+                if (ECMAErrors.isScriptFrame(ste)) {
+                    // Whatever here is compiled from JavaScript code
+                    fileName = ste.getFileName();
+                    line = ste.getLineNumber();
+                    return;
+                }
+            }
+
+            lineAndFileNameUnknown = false;
+        }
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java	Thu Sep 03 16:14:47 2015 -0700
@@ -283,17 +283,13 @@
             start++;
         }
 
-        start++; //we always uses this
+        start++; // we always use this
 
-        final List<IdentNode> params    = functionNode.getParameters();
+        assert functionNode.getNumOfParams() == 0 : "apply2call on function with named paramaters!";
         final List<IdentNode> newParams = new ArrayList<>();
-        final long to = Math.max(params.size(), actualCallSiteType.parameterCount() - start);
+        final long to = actualCallSiteType.parameterCount() - start;
         for (int i = 0; i < to; i++) {
-            if (i >= params.size()) {
-                newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
-            } else {
-                newParams.add(params.get(i));
-            }
+            newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
         }
 
         callSiteTypes.push(actualCallSiteType);
@@ -316,6 +312,10 @@
             return false;
         }
 
+        if (functionNode.getNumOfParams() != 0) {
+            return false;
+        }
+
         if (functionNode.hasEval()) {
             return false;
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Sep 03 16:14:47 2015 -0700
@@ -149,12 +149,14 @@
     private final Deque<Set<String>> thisProperties = new ArrayDeque<>();
     private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
     private final Compiler compiler;
+    private final boolean isOnDemand;
 
     public AssignSymbols(final Compiler compiler) {
         super(new LexicalContext());
         this.compiler = compiler;
         this.log   = initLogger(compiler.getContext());
         this.debug = log.isEnabled();
+        this.isOnDemand = compiler.isOnDemandCompilation();
     }
 
     @Override
@@ -390,7 +392,7 @@
 
             // Create and add to appropriate block.
             symbol = createSymbol(name, flags);
-            symbolBlock.putSymbol(lc, symbol);
+            symbolBlock.putSymbol(symbol);
 
             if ((flags & IS_SCOPE) == 0) {
                 // Initial assumption; symbol can lose its slot later
@@ -440,7 +442,7 @@
         start(block);
 
         if (lc.isFunctionBody()) {
-            block.clearSymbols();
+            assert !block.hasSymbols();
             final FunctionNode fn = lc.getCurrentFunction();
             if (isUnparsedFunction(fn)) {
                 // It's a skipped nested function. Just mark the symbols being used by it as being in use.
@@ -459,7 +461,7 @@
     }
 
     private boolean isUnparsedFunction(final FunctionNode fn) {
-        return compiler.isOnDemandCompilation() && fn != lc.getOutermostFunction();
+        return isOnDemand && fn != lc.getOutermostFunction();
     }
 
     @Override
@@ -747,28 +749,6 @@
         }
     }
 
-    @Override
-    public Node leaveBlock(final Block block) {
-        // It's not necessary to guard the marking of symbols as locals with this "if" condition for
-        // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
-        // is not an on-demand optimistic compilation, so we can skip locals marking then.
-        if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
-            // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
-            // compilation, and we're skipping parsing the function bodies for nested functions, this
-            // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
-            // symbol in the outer function named the same as one of the parameters, though.
-            if (lc.getFunction(block) == lc.getOutermostFunction()) {
-                for (final Symbol symbol: block.getSymbols()) {
-                    if (!symbol.isScope()) {
-                        assert symbol.isVar() || symbol.isParam();
-                        compiler.declareLocalSymbol(symbol.getName());
-                    }
-                }
-            }
-        }
-        return block;
-    }
-
     private Node leaveDELETE(final UnaryNode unaryNode) {
         final FunctionNode currentFunctionNode = lc.getCurrentFunction();
         final boolean      strictMode          = currentFunctionNode.isStrict();
@@ -786,9 +766,9 @@
 
             if (symbol.isThis()) {
                 // Can't delete "this", ignore and return true
-                return LiteralNode.newInstance(unaryNode, true).accept(this);
+                return LiteralNode.newInstance(unaryNode, true);
             }
-            final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
+            final Expression literalNode = LiteralNode.newInstance(unaryNode, name);
             final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
 
             if (!failDelete) {
@@ -799,7 +779,7 @@
 
             if (failDelete) {
                 request = Request.FAIL_DELETE;
-            } else if (symbol.isGlobal() && !symbol.isFunctionDeclaration()) {
+            } else if ((symbol.isGlobal() && !symbol.isFunctionDeclaration()) || symbol.isProgramLevel()) {
                 request = Request.SLOW_DELETE;
             }
         } else if (rhs instanceof AccessNode) {
@@ -807,7 +787,7 @@
             final String     property = ((AccessNode)rhs).getProperty();
 
             args.add(base);
-            args.add((Expression)LiteralNode.newInstance(unaryNode, property).accept(this));
+            args.add(LiteralNode.newInstance(unaryNode, property));
             args.add(strictFlagNode);
 
         } else if (rhs instanceof IndexNode) {
@@ -820,15 +800,15 @@
             args.add(strictFlagNode);
 
         } else {
-            return LiteralNode.newInstance(unaryNode, true).accept(this);
+            return LiteralNode.newInstance(unaryNode, true);
         }
-        return new RuntimeNode(unaryNode, request, args).accept(this);
+        return new RuntimeNode(unaryNode, request, args);
     }
 
     @Override
     public Node leaveForNode(final ForNode forNode) {
         if (forNode.isForIn()) {
-            forNode.setIterator(newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
+            return forNode.setIterator(lc, newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
         }
 
         return end(forNode);
@@ -904,19 +884,18 @@
     public Node leaveSwitchNode(final SwitchNode switchNode) {
         // We only need a symbol for the tag if it's not an integer switch node
         if(!switchNode.isUniqueInteger()) {
-            switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
+            return switchNode.setTag(lc, newObjectInternal(SWITCH_TAG_PREFIX));
         }
         return switchNode;
     }
 
     @Override
     public Node leaveTryNode(final TryNode tryNode) {
-        tryNode.setException(exceptionSymbol());
         assert tryNode.getFinallyBody() == null;
 
         end(tryNode);
 
-        return tryNode;
+        return tryNode.setException(lc, exceptionSymbol());
     }
 
     private Node leaveTYPEOF(final UnaryNode unaryNode) {
@@ -925,13 +904,13 @@
         final List<Expression> args = new ArrayList<>();
         if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) {
             args.add(compilerConstantIdentifier(SCOPE));
-            args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
+            args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName())); //null
         } else {
             args.add(rhs);
-            args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
+            args.add(LiteralNode.newInstance(unaryNode)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
         }
 
-        final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args).accept(this);
+        final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
 
         end(unaryNode);
 
@@ -939,7 +918,7 @@
     }
 
     private FunctionNode markProgramBlock(final FunctionNode functionNode) {
-        if (compiler.isOnDemandCompilation() || !functionNode.isProgram()) {
+        if (isOnDemand || !functionNode.isProgram()) {
             return functionNode;
         }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AstSerializer.java	Thu Sep 03 14:24:47 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.nashorn.internal.codegen;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.util.Collections;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
-import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.Statement;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.options.Options;
-
-/**
- * This static utility class performs serialization of FunctionNode ASTs to a byte array.
- * The format is a standard Java serialization stream, deflated.
- */
-final class AstSerializer {
-    // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
-    // and size.
-    private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
-    static byte[] serialize(final FunctionNode fn) {
-        final ByteArrayOutputStream out = new ByteArrayOutputStream();
-        final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
-        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
-            oout.writeObject(removeInnerFunctionBodies(fn));
-        } catch (final IOException e) {
-            throw new AssertionError("Unexpected exception serializing function", e);
-        } finally {
-            deflater.end();
-        }
-        return out.toByteArray();
-    }
-
-    private static FunctionNode removeInnerFunctionBodies(final FunctionNode fn) {
-        return (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-            @Override
-            public Node leaveBlock(final Block block) {
-                if (lc.isFunctionBody() && lc.getFunction(block) != lc.getOutermostFunction()) {
-                    return block.setStatements(lc, Collections.<Statement>emptyList());
-                }
-                return super.leaveBlock(block);
-            }
-        });
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CacheAst.java	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,87 @@
+/*
+ * 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.codegen;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+
+class CacheAst extends NodeVisitor<LexicalContext> {
+    private final Deque<RecompilableScriptFunctionData> dataStack = new ArrayDeque<>();
+
+    private final Compiler compiler;
+
+    CacheAst(final Compiler compiler) {
+        super(new LexicalContext());
+        this.compiler = compiler;
+        assert !compiler.isOnDemandCompilation();
+    }
+
+    @Override
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        final int id = functionNode.getId();
+        // It isn't necessary to keep a stack of RecompilableScriptFunctionData, but then we'd need to do a
+        // potentially transitive lookup with compiler.getScriptFunctionData(id) for deeper functions; this way
+        // we keep it constant time.
+        dataStack.push(dataStack.isEmpty() ? compiler.getScriptFunctionData(id) : dataStack.peek().getScriptFunctionData(id));
+        return true;
+    }
+
+    @Override
+    public Node leaveFunctionNode(final FunctionNode functionNode) {
+        final RecompilableScriptFunctionData data = dataStack.pop();
+        if (functionNode.isSplit()) {
+            // NOTE: cache only split function ASTs from eager pass. Caching non-split functions would require
+            // some additional work, namely creating the concept of "uncacheable" function and reworking
+            // ApplySpecialization to ensure that functions undergoing apply-to-call transformations are not
+            // cacheable as well as recomputing Symbol.useCount when caching the eagerly parsed AST.
+            // Recomputing Symbol.useCount would be needed so it will only reflect uses from within the
+            // function being cached (and not reflect uses from its own nested functions or functions it is
+            // nested in). This is consistent with the count an on-demand recompilation of the function would
+            // produce. This is important as the decision to emit shared scope calls is based on this count,
+            // and if it is not matched between a previous version of the code and its deoptimizing rest-of
+            // compilation, it can result in rest-of not emitting a shared scope call where a previous version
+            // of the code (compiled from a cached eager pre-pass seeing higher (global) useCount) would emit
+            // it, causing a mismatch in stack shapes between previous code and its rest-of.
+            data.setCachedAst(functionNode);
+        }
+
+        if (!dataStack.isEmpty() && ((dataStack.peek().getFunctionFlags() & FunctionNode.IS_SPLIT) != 0)) {
+            // Return a function node with no body so that caching outer functions doesn't hold on to nested
+            // functions' bodies. Note we're doing this only for functions directly nested inside split
+            // functions, since we're only caching the split ones. It is not necessary to limit body removal
+            // to just these functions, but it's a cheap way to prevent unnecessary AST mutations.
+            return functionNode.setBody(lc, functionNode.getBody().setStatements(null, Collections.<Statement>emptyList()));
+        }
+        return functionNode;
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Sep 03 16:14:47 2015 -0700
@@ -48,11 +48,13 @@
 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;
+import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -189,7 +191,7 @@
         }
     },
 
-    SERIALIZE_SPLIT_PHASE(
+    CACHE_AST(
             EnumSet.of(
                     INITIALIZED,
                     PARSED,
@@ -199,20 +201,21 @@
                     SPLIT)) {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
-                @Override
-                public boolean enterFunctionNode(final FunctionNode functionNode) {
-                    if (functionNode.isSplit()) {
-                        compiler.serializeAst(functionNode);
-                    }
-                    return true;
-                }
-            });
+            if (!compiler.isOnDemandCompilation()) {
+                // Only do this on initial preprocessing of the source code. For on-demand compilations from
+                // source, FindScopeDepths#leaveFunctionNode() calls data.setCachedAst() for the sole function
+                // being compiled.
+                transformFunction(fn, new CacheAst(compiler));
+            }
+            // NOTE: we're returning the original fn as we have destructively modified the cached functions by
+            // removing their bodies. This step is associating FunctionNode objects with
+            // RecompilableScriptFunctionData; it's not really modifying the AST.
+            return fn;
         }
 
         @Override
         public String toString() {
-            return "'Serialize Split Functions'";
+            return "'Cache ASTs'";
         }
     },
 
@@ -255,6 +258,51 @@
         }
     },
 
+    DECLARE_LOCAL_SYMBOLS_TO_COMPILER(
+            EnumSet.of(
+                    INITIALIZED,
+                    PARSED,
+                    CONSTANT_FOLDED,
+                    LOWERED,
+                    BUILTINS_TRANSFORMED,
+                    SPLIT,
+                    SYMBOLS_ASSIGNED,
+                    SCOPE_DEPTHS_COMPUTED)) {
+        @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
+            // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
+            // is not an on-demand optimistic compilation, so we can skip locals marking then.
+            if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
+                fn.getBody().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                    @Override
+                    public boolean enterFunctionNode(final FunctionNode functionNode) {
+                        // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
+                        // compilation, and we're skipping parsing the function bodies for nested functions, this
+                        // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
+                        // symbol in the outer function named the same as one of the parameters, though.
+                        return false;
+                    };
+                    @Override
+                    public boolean enterBlock(final Block block) {
+                        for (final Symbol symbol: block.getSymbols()) {
+                            if (!symbol.isScope()) {
+                                compiler.declareLocalSymbol(symbol.getName());
+                            }
+                        }
+                        return true;
+                    };
+                });
+            }
+            return fn;
+        }
+
+        @Override
+        public String toString() {
+            return "'Local Symbols Declaration'";
+        }
+    },
+
     OPTIMISTIC_TYPE_ASSIGNMENT_PHASE(
             EnumSet.of(
                     INITIALIZED,
@@ -382,7 +430,7 @@
         }
     },
 
-    REINITIALIZE_SERIALIZED(
+    REINITIALIZE_CACHED(
             EnumSet.of(
                     INITIALIZED,
                     PARSED,
@@ -430,7 +478,7 @@
 
         @Override
         public String toString() {
-            return "'Deserialize'";
+            return "'Reinitialize cached'";
         }
     },
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Sep 03 16:14:47 2015 -0700
@@ -160,42 +160,41 @@
      */
     private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
 
-    private final Map<Integer, byte[]> serializedAsts = new HashMap<>();
-
     /**
      * Compilation phases that a compilation goes through
      */
     public static class CompilationPhases implements Iterable<CompilationPhase> {
 
         /**
-         * Singleton that describes compilation up to the phase where a function can be serialized.
+         * Singleton that describes compilation up to the phase where a function can be cached.
          */
-        private final static CompilationPhases COMPILE_UPTO_SERIALIZABLE = new CompilationPhases(
+        private final static CompilationPhases COMPILE_UPTO_CACHED = new CompilationPhases(
                 "Common initial phases",
                 CompilationPhase.CONSTANT_FOLDING_PHASE,
                 CompilationPhase.LOWERING_PHASE,
                 CompilationPhase.TRANSFORM_BUILTINS_PHASE,
                 CompilationPhase.SPLITTING_PHASE,
                 CompilationPhase.PROGRAM_POINT_PHASE,
-                CompilationPhase.SERIALIZE_SPLIT_PHASE
+                CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
+                CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+                CompilationPhase.CACHE_AST
                 );
 
-        private final static CompilationPhases COMPILE_SERIALIZABLE_UPTO_BYTECODE = new CompilationPhases(
+        private final static CompilationPhases COMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
                 "After common phases, before bytecode generator",
-                CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
-                CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+                CompilationPhase.DECLARE_LOCAL_SYMBOLS_TO_COMPILER,
                 CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
                 CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
                 );
 
         /**
-         * Singleton that describes additional steps to be taken after deserializing, all the way up to (but not
-         * including) generating and installing code.
+         * Singleton that describes additional steps to be taken after retrieving a cached function, all the
+         * way up to (but not including) generating and installing code.
          */
-        public final static CompilationPhases RECOMPILE_SERIALIZED_UPTO_BYTECODE = new CompilationPhases(
-                "Recompile serialized function up to bytecode",
-                CompilationPhase.REINITIALIZE_SERIALIZED,
-                COMPILE_SERIALIZABLE_UPTO_BYTECODE
+        public final static CompilationPhases RECOMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
+                "Recompile cached function up to bytecode",
+                CompilationPhase.REINITIALIZE_CACHED,
+                COMPILE_CACHED_UPTO_BYTECODE
                 );
 
         /**
@@ -211,8 +210,8 @@
         /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
         public final static CompilationPhases COMPILE_UPTO_BYTECODE = new CompilationPhases(
                 "Compile upto bytecode",
-                COMPILE_UPTO_SERIALIZABLE,
-                COMPILE_SERIALIZABLE_UPTO_BYTECODE);
+                COMPILE_UPTO_CACHED,
+                COMPILE_CACHED_UPTO_BYTECODE);
 
         /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
         public final static CompilationPhases COMPILE_ALL_NO_INSTALL = new CompilationPhases(
@@ -227,9 +226,9 @@
                 GENERATE_BYTECODE_AND_INSTALL);
 
         /** Singleton that describes a full compilation - this includes code installation - from serialized state*/
-        public final static CompilationPhases COMPILE_ALL_SERIALIZED = new CompilationPhases(
+        public final static CompilationPhases COMPILE_ALL_CACHED = new CompilationPhases(
                 "Eager compilation from serializaed state",
-                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+                RECOMPILE_CACHED_UPTO_BYTECODE,
                 GENERATE_BYTECODE_AND_INSTALL);
 
         /**
@@ -248,9 +247,9 @@
                 GENERATE_BYTECODE_AND_INSTALL_RESTOF);
 
         /** Compile from serialized for a rest of method */
-        public final static CompilationPhases COMPILE_SERIALIZED_RESTOF = new CompilationPhases(
+        public final static CompilationPhases COMPILE_CACHED_RESTOF = new CompilationPhases(
                 "Compile serialized, rest of",
-                RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+                RECOMPILE_CACHED_UPTO_BYTECODE,
                 GENERATE_BYTECODE_AND_INSTALL_RESTOF);
 
         private final List<CompilationPhase> phases;
@@ -313,7 +312,7 @@
         }
 
         boolean isRestOfCompilation() {
-            return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_SERIALIZED_RESTOF;
+            return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_CACHED_RESTOF;
         }
 
         String getDesc() {
@@ -766,14 +765,6 @@
         compileUnits.addAll(newUnits);
     }
 
-    void serializeAst(final FunctionNode fn) {
-        serializedAsts.put(fn.getId(), AstSerializer.serialize(fn));
-    }
-
-    byte[] removeSerializedAst(final int fnId) {
-        return serializedAsts.remove(fnId);
-    }
-
     CompileUnit findUnit(final long weight) {
         for (final CompileUnit unit : compileUnits) {
             if (unit.canHold(weight)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java	Thu Sep 03 16:14:47 2015 -0700
@@ -188,6 +188,9 @@
                 log.fine("Reviving scriptfunction ", quote(name), " as defined in previous (now lost) dynamic scope.");
                 newFunctionNode = newFunctionNode.setInDynamicContext(lc);
             }
+            if (newFunctionNode == lc.getOutermostFunction() && !newFunctionNode.hasApplyToCallSpecialization()) {
+                data.setCachedAst(newFunctionNode);
+            }
             return newFunctionNode;
         }
 
@@ -208,8 +211,7 @@
                 ObjectClassGenerator.createAllocationStrategy(newFunctionNode.getThisProperties(), compiler.getContext().useDualFields()),
                 nestedFunctions,
                 externalSymbolDepths.get(fnId),
-                internalSymbols.get(fnId),
-                compiler.removeSerializedAst(fnId));
+                internalSymbols.get(fnId));
 
         if (lc.getOutermostFunction() != newFunctionNode) {
             final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Label.java	Thu Sep 03 16:14:47 2015 -0700
@@ -497,7 +497,7 @@
     private transient Label.Stack stack;
 
     /** ASM representation of this label */
-    private jdk.internal.org.objectweb.asm.Label label;
+    private transient jdk.internal.org.objectweb.asm.Label label;
 
     /** Id for debugging purposes, remove if footprint becomes unmanageable */
     private final int id;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java	Thu Sep 03 16:14:47 2015 -0700
@@ -27,21 +27,18 @@
 
 import java.lang.invoke.MethodType;
 import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.NoSuchElementException;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 
 /**
- * A data structure that maps one or several function nodes (by their unique id:s, not by
- * the FunctionNode object itself, due to copy on write changing it several times through
- * code generation.
+ * A tuple containing function id, parameter types, return type and needsCallee flag.
  */
-public class TypeMap {
-    private final Map<Integer, Type[]> paramTypeMap  = new HashMap<>();
-    private final Map<Integer, Type>   returnTypeMap = new HashMap<>();
+public final class TypeMap {
+    private final int functionNodeId;
+    private final Type[] paramTypes;
+    private final Type returnType;
     private final boolean needsCallee;
 
     /**
@@ -56,9 +53,10 @@
         for (final Class<?> p : type.parameterArray()) {
             types[pos++] = Type.typeFor(p);
         }
-        paramTypeMap.put(functionNodeId, types);
-        returnTypeMap.put(functionNodeId, Type.typeFor(type.returnType()));
 
+        this.functionNodeId = functionNodeId;
+        this.paramTypes = types;
+        this.returnType = Type.typeFor(type.returnType());
         this.needsCallee = needsCallee;
     }
 
@@ -69,20 +67,14 @@
      * @throws NoSuchElementException if the type map has no mapping for the requested function
      */
     public Type[] getParameterTypes(final int functionNodeId) {
-        final Type[] paramTypes = paramTypeMap.get(functionNodeId);
-        if (paramTypes == null) {
-            throw new NoSuchElementException(Integer.toString(functionNodeId));
-        }
+        assert this.functionNodeId == functionNodeId;
         return paramTypes.clone();
     }
 
     MethodType getCallSiteType(final FunctionNode functionNode) {
-        final Type[] types = paramTypeMap.get(functionNode.getId());
-        if (types == null) {
-            return null;
-        }
-
-        MethodType mt = MethodType.methodType(returnTypeMap.get(functionNode.getId()).getTypeClass());
+        assert this.functionNodeId == functionNode.getId();
+        final Type[] types = paramTypes;
+        MethodType mt = MethodType.methodType(returnType.getTypeClass());
         if (needsCallee) {
             mt = mt.appendParameterTypes(ScriptFunction.class);
         }
@@ -116,7 +108,8 @@
      * @return parameter type for this callsite if known
      */
     Type get(final FunctionNode functionNode, final int pos) {
-        final Type[] types = paramTypeMap.get(functionNode.getId());
+        assert this.functionNodeId == functionNode.getId();
+        final Type[] types = paramTypes;
         assert types == null || pos < types.length : "fn = " + functionNode.getId() + " " + "types=" + Arrays.toString(types) + " || pos=" + pos + " >= length=" + types.length + " in " + this;
         if (types != null && pos < types.length) {
             return types[pos];
@@ -124,13 +117,6 @@
         return null;
     }
 
-    boolean has(final FunctionNode functionNode) {
-        final int id = functionNode.getId();
-        final Type[] paramTypes = paramTypeMap.get(id);
-        assert (paramTypes == null) == (returnTypeMap.get(id) == null) : "inconsistent param and return types in param map";
-        return paramTypes != null;
-    }
-
     @Override
     public String toString() {
         return toString("");
@@ -139,27 +125,16 @@
     String toString(final String prefix) {
         final StringBuilder sb = new StringBuilder();
 
-        if (paramTypeMap.isEmpty()) {
-            sb.append(prefix).append("\t<empty>");
-            return sb.toString();
-        }
-
-        for (final Map.Entry<Integer, Type[]> entry : paramTypeMap.entrySet()) {
-            final int id = entry.getKey();
-            sb.append(prefix).append('\t');
-            sb.append("function ").append(id).append('\n');
-            sb.append(prefix).append("\t\tparamTypes=");
-            if (entry.getValue() == null) {
-                sb.append("[]");
-            } else {
-                sb.append(Arrays.toString(entry.getValue()));
-            }
-            sb.append('\n');
-            sb.append(prefix).append("\t\treturnType=");
-            final Type ret = returnTypeMap.get(id);
-            sb.append(ret == null ? "N/A" : ret);
-            sb.append('\n');
-        }
+        final int id = functionNodeId;
+        sb.append(prefix).append('\t');
+        sb.append("function ").append(id).append('\n');
+        sb.append(prefix).append("\t\tparamTypes=");
+        sb.append(Arrays.toString(paramTypes));
+        sb.append('\n');
+        sb.append(prefix).append("\t\treturnType=");
+        final Type ret = returnType;
+        sb.append(ret == null ? "N/A" : ret);
+        sb.append('\n');
 
         return sb.toString();
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Thu Sep 03 16:14:47 2015 -0700
@@ -159,11 +159,42 @@
     }
 
     /**
-     * Clear the symbols in the block.
-     * TODO: make this immutable.
+     * Returns true if this block defines any symbols.
+     * @return true if this block defines any symbols.
+     */
+    public boolean hasSymbols() {
+        return !symbols.isEmpty();
+    }
+
+    /**
+     * Replaces symbols defined in this block with different symbols. Used to ensure symbol tables are
+     * immutable upon construction and have copy-on-write semantics. Note that this method only replaces the
+     * symbols in the symbol table, it does not act on any contained AST nodes that might reference the symbols.
+     * Those should be updated separately as this method is meant to be used as part of such an update pass.
+     * @param lc the current lexical context
+     * @param replacements the map of symbol replacements
+     * @return a new block with replaced symbols, or this block if none of the replacements modified the symbol
+     * table.
      */
-    public void clearSymbols() {
-        symbols.clear();
+    public Block replaceSymbols(final LexicalContext lc, final Map<Symbol, Symbol> replacements) {
+        if (symbols.isEmpty()) {
+            return this;
+        }
+        final LinkedHashMap<String, Symbol> newSymbols = new LinkedHashMap<>(symbols);
+        for (final Map.Entry<String, Symbol> entry: newSymbols.entrySet()) {
+            final Symbol newSymbol = replacements.get(entry.getValue());
+            assert newSymbol != null : "Missing replacement for " + entry.getKey();
+            entry.setValue(newSymbol);
+        }
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, newSymbols, conversion));
+    }
+
+    /**
+     * Returns a copy of this block with a shallow copy of the symbol table.
+     * @return a copy of this block with a shallow copy of the symbol table.
+     */
+    public Block copyWithNewSymbols() {
+        return new Block(this, finish, statements, flags, new LinkedHashMap<>(symbols), conversion);
     }
 
     @Override
@@ -191,7 +222,7 @@
      * @return symbol iterator
      */
     public List<Symbol> getSymbols() {
-        return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
+        return symbols.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList<>(symbols.values()));
     }
 
     /**
@@ -355,10 +386,9 @@
     /**
      * Add or overwrite an existing symbol in the block
      *
-     * @param lc     get lexical context
      * @param symbol symbol
      */
-    public void putSymbol(final LexicalContext lc, final Symbol symbol) {
+    public void putSymbol(final Symbol symbol) {
         symbols.put(symbol.getName(), symbol);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Thu Sep 03 16:14:47 2015 -0700
@@ -43,7 +43,7 @@
     private final JoinPredecessorExpression modify;
 
     /** Iterator symbol. */
-    private Symbol iterator;
+    private final Symbol iterator;
 
     /** Is this a normal for in loop? */
     public static final int IS_FOR_IN           = 1 << 0;
@@ -86,23 +86,23 @@
         this.flags  = flags;
         this.init = init;
         this.modify = modify;
+        this.iterator = null;
 
     }
 
     private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
-            final Block body, final JoinPredecessorExpression modify, final int flags, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
+            final Block body, final JoinPredecessorExpression modify, final int flags,
+            final boolean controlFlowEscapes, final LocalVariableConversion conversion, final Symbol iterator) {
         super(forNode, test, body, controlFlowEscapes, conversion);
         this.init   = init;
         this.modify = modify;
         this.flags  = flags;
-        // Even if the for node gets cloned in try/finally, the symbol can be shared as only one branch of the finally
-        // is executed.
-        this.iterator = forNode.iterator;
+        this.iterator = iterator;
     }
 
     @Override
     public Node ensureUniqueLabels(final LexicalContext lc) {
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     @Override
@@ -175,7 +175,7 @@
         if (this.init == init) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     /**
@@ -204,10 +204,15 @@
 
     /**
      * Assign an iterator symbol to this ForNode. Used for for in and for each constructs
+     * @param lc the current lexical context
      * @param iterator the iterator symbol
+     * @return a ForNode with the iterator set
      */
-    public void setIterator(final Symbol iterator) {
-        this.iterator = iterator;
+    public ForNode setIterator(final LexicalContext lc, final Symbol iterator) {
+        if (this.iterator == iterator) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     /**
@@ -228,7 +233,7 @@
         if (this.modify == modify) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     @Override
@@ -236,7 +241,7 @@
         if (this.test == test) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     @Override
@@ -249,7 +254,7 @@
         if (this.body == body) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     @Override
@@ -257,12 +262,12 @@
         if (this.controlFlowEscapes == controlFlowEscapes) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     @Override
     JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
-        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Sep 03 16:14:47 2015 -0700
@@ -264,6 +264,11 @@
      */
     public static final int NEEDS_CALLEE       = 1 << 26;
 
+    /**
+     * Is the function node cached?
+     */
+    public static final int IS_CACHED = 1 << 27;
+
     /** extension callsite flags mask */
     public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
         IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
@@ -353,7 +358,7 @@
         final List<IdentNode> parameters,
         final int thisProperties,
         final Class<?> rootClass,
-        final Source source, Namespace namespace) {
+        final Source source, final Namespace namespace) {
         super(functionNode);
 
         this.endParserState    = endParserState;
@@ -757,7 +762,7 @@
      */
     public boolean needsCallee() {
         // NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
-        return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
+        return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasApplyToCallSpecialization();
     }
 
     /**
@@ -774,7 +779,7 @@
      * Return true if function contains an apply to call transform
      * @return true if this function has transformed apply to call
      */
-    public boolean hasOptimisticApplyToCall() {
+    public boolean hasApplyToCallSpecialization() {
         return getFlag(HAS_APPLY_TO_CALL_SPECIALIZATION);
     }
 
@@ -1026,6 +1031,14 @@
     }
 
     /**
+     * Return the number of parameters to this function
+     * @return the number of parameters
+     */
+    public int getNumOfParams() {
+        return parameters.size();
+    }
+
+    /**
      * Returns the identifier for a named parameter at the specified position in this function's parameter list.
      * @param index the parameter's position.
      * @return the identifier for the requested named parameter.
@@ -1162,6 +1175,24 @@
     }
 
     /**
+     * Returns true if this function node has been cached.
+     * @return true if this function node has been cached.
+     */
+    public boolean isCached() {
+        return getFlag(IS_CACHED);
+    }
+
+    /**
+     * Mark this function node as having been cached.
+     * @param lc the current lexical context
+     * @return a function node equivalent to this one, with the flag set.
+     */
+    public FunctionNode setCached(final LexicalContext lc) {
+        return setFlag(lc, IS_CACHED);
+    }
+
+
+    /**
      * Get the compile unit used to compile this function
      * @see Compiler
      * @return the compile unit
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SwitchNode.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SwitchNode.java	Thu Sep 03 16:14:47 2015 -0700
@@ -53,7 +53,7 @@
     private final boolean uniqueInteger;
 
     /** Tag symbol. */
-    private Symbol tag;
+    private final Symbol tag;
 
     /**
      * Constructor
@@ -71,15 +71,16 @@
         this.cases            = cases;
         this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
         this.uniqueInteger    = false;
+        this.tag = null;
     }
 
     private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases,
-            final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) {
+            final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger, final Symbol tag) {
         super(switchNode, conversion);
         this.expression       = expression;
         this.cases            = cases;
         this.defaultCaseIndex = defaultCaseIndex;
-        this.tag              = switchNode.getTag(); //TODO are symbols inherited as references?
+        this.tag              = tag;
         this.uniqueInteger    = uniqueInteger;
     }
 
@@ -89,7 +90,7 @@
         for (final CaseNode caseNode : cases) {
             newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion()));
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger, tag));
     }
 
     @Override
@@ -157,7 +158,7 @@
         if (this.cases == cases) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
     }
 
     /**
@@ -189,7 +190,7 @@
         if (this.expression == expression) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
     }
 
     /**
@@ -204,10 +205,15 @@
     /**
      * Set the tag symbol for this switch. The tag symbol is where
      * the switch expression result is stored
+     * @param lc lexical context
      * @param tag a symbol
+     * @return a switch node with the symbol set
      */
-    public void setTag(final Symbol tag) {
-        this.tag = tag;
+    public SwitchNode setTag(final LexicalContext lc, final Symbol tag) {
+        if (this.tag == tag) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
     }
 
     /**
@@ -229,12 +235,12 @@
         if(this.uniqueInteger == uniqueInteger) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
     }
 
     @Override
     JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
-        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
     }
 
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java	Thu Sep 03 16:14:47 2015 -0700
@@ -25,7 +25,10 @@
 
 package jdk.nashorn.internal.ir;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -47,7 +50,9 @@
  * refer to their location.
  */
 
-public final class Symbol implements Comparable<Symbol> {
+public final class Symbol implements Comparable<Symbol>, Cloneable, Serializable {
+    private static final long serialVersionUID = 1L;
+
     /** Is this Global */
     public static final int IS_GLOBAL   = 1;
     /** Is this a variable */
@@ -94,10 +99,10 @@
 
     /** First bytecode method local variable slot for storing the value(s) of this variable. -1 indicates the variable
      * is not stored in local variable slots or it is not yet known. */
-    private int firstSlot = -1;
+    private transient int firstSlot = -1;
 
     /** Field number in scope or property; array index in varargs when not using arguments object. */
-    private int fieldIndex = -1;
+    private transient int fieldIndex = -1;
 
     /** Number of times this symbol is used in code */
     private int useCount;
@@ -144,6 +149,15 @@
         }
     }
 
+    @Override
+    public Symbol clone() {
+        try {
+            return (Symbol)super.clone();
+        } catch (final CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
     private static String align(final String string, final int max) {
         final StringBuilder sb = new StringBuilder();
         sb.append(string.substring(0, Math.min(string.length(), max)));
@@ -337,7 +351,7 @@
      * Flag this symbol as scope as described in {@link Symbol#isScope()}
      * @return the symbol
      */
-     public Symbol setIsScope() {
+    public Symbol setIsScope() {
         if (!isScope()) {
             if(shouldTrace()) {
                 trace("SET IS SCOPE");
@@ -609,11 +623,11 @@
 
     /**
      * Increase the symbol's use count by one.
-     * @return the symbol
      */
-    public Symbol increaseUseCount() {
-        useCount++;
-        return this;
+    public void increaseUseCount() {
+        if (isScope()) { // Avoid dirtying a cache line; we only need the use count for scoped symbols
+            useCount++;
+        }
     }
 
     /**
@@ -669,4 +683,10 @@
             new Throwable().printStackTrace(Context.getCurrentErr());
         }
     }
+
+    private void readObject(final ObjectInputStream in) throws ClassNotFoundException, IOException {
+        in.defaultReadObject();
+        firstSlot = -1;
+        fieldIndex = -1;
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Thu Sep 03 16:14:47 2015 -0700
@@ -65,7 +65,7 @@
     private final List<Block> inlinedFinallies;
 
     /** Exception symbol. */
-    private Symbol exception;
+    private final Symbol exception;
 
     private final LocalVariableConversion conversion;
 
@@ -86,22 +86,23 @@
         this.finallyBody = finallyBody;
         this.conversion  = null;
         this.inlinedFinallies = Collections.emptyList();
+        this.exception = null;
     }
 
-    private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies) {
+    private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies, final Symbol exception) {
         super(tryNode);
         this.body        = body;
         this.catchBlocks = catchBlocks;
         this.finallyBody = finallyBody;
         this.conversion  = conversion;
         this.inlinedFinallies = inlinedFinallies;
-        this.exception = tryNode.exception;
+        this.exception = exception;
     }
 
     @Override
     public Node ensureUniqueLabels(final LexicalContext lc) {
         //try nodes are never in lex context
-        return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
+        return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception);
     }
 
     @Override
@@ -160,7 +161,7 @@
         if (this.body == body) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new TryNode(this,  body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+        return Node.replaceInLexicalContext(lc, this, new TryNode(this,  body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
     }
 
     /**
@@ -197,7 +198,7 @@
         if (this.catchBlocks == catchBlocks) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
     }
 
     /**
@@ -209,12 +210,15 @@
     }
     /**
      * Set the exception symbol for this try block
+     * @param lc lexical context
      * @param exception a symbol for the compiler to store the exception in
      * @return new TryNode or same if unchanged
      */
-    public TryNode setException(final Symbol exception) {
-        this.exception = exception;
-        return this;
+    public TryNode setException(final LexicalContext lc, final Symbol exception) {
+        if (this.exception == exception) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
     }
 
     /**
@@ -277,7 +281,7 @@
         if (this.finallyBody == finallyBody) {
             return this;
         }
-        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
     }
 
     /**
@@ -293,7 +297,7 @@
             return this;
         }
         assert checkInlinedFinallies(inlinedFinallies);
-        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+        return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
     }
 
     private static boolean checkInlinedFinallies(final List<Block> inlinedFinallies) {
@@ -314,7 +318,7 @@
         if(this.conversion == conversion) {
             return this;
         }
-        return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
+        return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception);
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Thu Sep 03 16:14:47 2015 -0700
@@ -2419,7 +2419,7 @@
     }
 
     private void initScripting(final ScriptEnvironment scriptEnv) {
-        Object value;
+        ScriptObject value;
         value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE);
         addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
 
@@ -2428,11 +2428,13 @@
 
         final String execName = ScriptingFunctions.EXEC_NAME;
         value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC);
+        value.addOwnProperty(ScriptingFunctions.THROW_ON_ERROR_NAME, Attribute.NOT_ENUMERABLE, false);
+
         addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value);
 
         // Nashorn extension: global.echo (scripting-mode-only)
         // alias for "print"
-        value = get("print");
+        value = (ScriptObject)get("print");
         addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value);
 
         // Nashorn extension: global.$OPTIONS (scripting-mode-only)
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Sep 03 16:14:47 2015 -0700
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.parser;
 
 import static jdk.nashorn.internal.parser.TokenType.ADD;
+import static jdk.nashorn.internal.parser.TokenType.BINARY_NUMBER;
 import static jdk.nashorn.internal.parser.TokenType.COMMENT;
 import static jdk.nashorn.internal.parser.TokenType.DECIMAL;
 import static jdk.nashorn.internal.parser.TokenType.DIRECTIVE_COMMENT;
@@ -40,6 +41,7 @@
 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
 import static jdk.nashorn.internal.parser.TokenType.OCTAL;
+import static jdk.nashorn.internal.parser.TokenType.OCTAL_LEGACY;
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.REGEX;
 import static jdk.nashorn.internal.parser.TokenType.RPAREN;
@@ -47,6 +49,7 @@
 import static jdk.nashorn.internal.parser.TokenType.XML;
 
 import java.io.Serializable;
+
 import jdk.nashorn.internal.runtime.ECMAErrors;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -75,6 +78,9 @@
     /** True if here and edit strings are supported. */
     private final boolean scripting;
 
+    /** True if parsing in ECMAScript 6 mode. */
+    private final boolean es6;
+
     /** True if a nested scan. (scan to completion, no EOF.) */
     private final boolean nested;
 
@@ -173,7 +179,7 @@
      * @param stream    the token stream to lex
      */
     public Lexer(final Source source, final TokenStream stream) {
-        this(source, stream, false);
+        this(source, stream, false, false);
     }
 
     /**
@@ -182,9 +188,10 @@
      * @param source    the source
      * @param stream    the token stream to lex
      * @param scripting are we in scripting mode
+     * @param es6       are we in ECMAScript 6 mode
      */
-    public Lexer(final Source source, final TokenStream stream, final boolean scripting) {
-        this(source, 0, source.getLength(), stream, scripting, false);
+    public Lexer(final Source source, final TokenStream stream, final boolean scripting, final boolean es6) {
+        this(source, 0, source.getLength(), stream, scripting, es6, false);
     }
 
     /**
@@ -195,16 +202,18 @@
      * @param len       length of source segment to lex
      * @param stream    token stream to lex
      * @param scripting are we in scripting mode
+     * @param es6       are we in ECMAScript 6 mode
      * @param pauseOnFunctionBody if true, lexer will return from {@link #lexify()} when it encounters a
      * function body. This is used with the feature where the parser is skipping nested function bodies to
      * avoid reading ahead unnecessarily when we skip the function bodies.
      */
 
-    public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean pauseOnFunctionBody) {
+    public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
         super(source.getContent(), 1, start, len);
         this.source      = source;
         this.stream      = stream;
         this.scripting   = scripting;
+        this.es6         = es6;
         this.nested      = false;
         this.pendingLine = 1;
         this.last        = EOL;
@@ -218,6 +227,7 @@
         source = lexer.source;
         stream = lexer.stream;
         scripting = lexer.scripting;
+        es6 = lexer.es6;
         nested = true;
 
         pendingLine = state.pendingLine;
@@ -1088,6 +1098,24 @@
             }
 
             type = HEXADECIMAL;
+        } else if (digit == 0 && es6 && (ch1 == 'o' || ch1 == 'O') && convertDigit(ch2, 8) != -1) {
+            // Skip over 0oN.
+            skip(3);
+            // Skip over remaining digits.
+            while (convertDigit(ch0, 8) != -1) {
+                skip(1);
+            }
+
+            type = OCTAL;
+        } else if (digit == 0 && es6 && (ch1 == 'b' || ch1 == 'B') && convertDigit(ch2, 2) != -1) {
+            // Skip over 0bN.
+            skip(3);
+            // Skip over remaining digits.
+            while (convertDigit(ch0, 2) != -1) {
+                skip(1);
+            }
+
+            type = BINARY_NUMBER;
         } else {
             // Check for possible octal constant.
             boolean octal = digit == 0;
@@ -1105,7 +1133,7 @@
             }
 
             if (octal && position - start > 1) {
-                type = OCTAL;
+                type = OCTAL_LEGACY;
             } else if (ch0 == '.' || ch0 == 'E' || ch0 == 'e') {
                 // Must be a double.
                 if (ch0 == '.') {
@@ -1637,10 +1665,14 @@
         switch (Token.descType(token)) {
         case DECIMAL:
             return Lexer.valueOf(source.getString(start, len), 10); // number
-        case OCTAL:
-            return Lexer.valueOf(source.getString(start, len), 8); // number
         case HEXADECIMAL:
             return Lexer.valueOf(source.getString(start + 2, len - 2), 16); // number
+        case OCTAL_LEGACY:
+            return Lexer.valueOf(source.getString(start, len), 8); // number
+        case OCTAL:
+            return Lexer.valueOf(source.getString(start + 2, len - 2), 8); // number
+        case BINARY_NUMBER:
+            return Lexer.valueOf(source.getString(start + 2, len - 2), 2); // number
         case FLOATING:
             final String str   = source.getString(start, len);
             final double value = Double.valueOf(str);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Thu Sep 03 16:14:47 2015 -0700
@@ -273,7 +273,7 @@
 
         try {
             stream = new TokenStream();
-            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null);
+            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
             lexer.line = lexer.pendingLine = lineOffset + 1;
             line = lineOffset;
 
@@ -309,7 +309,7 @@
     public List<IdentNode> parseFormalParameterList() {
         try {
             stream = new TokenStream();
-            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
+            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
 
             // Set up first token (skips opening EOL.)
             k = -1;
@@ -333,7 +333,7 @@
     public FunctionNode parseFunctionBody() {
         try {
             stream = new TokenStream();
-            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
+            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
             final int functionLine = line;
 
             // Set up first token (skips opening EOL.)
@@ -716,7 +716,7 @@
 
         restoreBlock(body);
         body.setFlag(Block.NEEDS_SCOPE);
-        final Block programBody = new Block(functionToken, functionLine, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
+        final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
         lc.pop(script);
         script.setLastToken(token);
 
@@ -1216,11 +1216,10 @@
         final long forToken = token;
         final int forLine = line;
         // start position of this for statement. This is used
-        // for sort order for variables declared in the initialzer
+        // for sort order for variables declared in the initializer
         // part of this 'for' statement (if any).
         final int forStart = Token.descPosition(forToken);
         // When ES6 for-let is enabled we create a container block to capture the LET.
-        final int startLine = start;
         final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
 
         // Create FOR node, capturing FOR token.
@@ -1341,22 +1340,24 @@
             body = getStatement();
         } finally {
             lc.pop(forNode);
-        }
-
-        if (vars != null) {
-            for (final VarNode var : vars) {
-                appendStatement(var);
+
+            if (vars != null) {
+                for (final VarNode var : vars) {
+                    appendStatement(var);
+                }
+            }
+            if (body != null) {
+                appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
             }
-        }
-        if (body != null) {
-            appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
-        }
-        if (outer != null) {
-            restoreBlock(outer);
-            appendStatement(new BlockStatement(startLine, new Block(
-                    outer.getToken(),
-                    body.getFinish(),
-                    outer.getStatements())));
+            if (outer != null) {
+                restoreBlock(outer);
+                if (body != null) {
+                    appendStatement(new BlockStatement(forLine, new Block(
+                                    outer.getToken(),
+                                    body.getFinish(),
+                                    outer.getStatements())));
+                }
+            }
         }
     }
 
@@ -1954,7 +1955,7 @@
             }
             detectSpecialProperty(ident);
             return ident;
-        case OCTAL:
+        case OCTAL_LEGACY:
             if (isStrictMode) {
                throw error(AbstractParser.message("strict.no.octal"), token);
             }
@@ -1962,6 +1963,8 @@
         case ESCSTRING:
         case DECIMAL:
         case HEXADECIMAL:
+        case OCTAL:
+        case BINARY_NUMBER:
         case FLOATING:
         case REGEX:
         case XML:
@@ -2053,13 +2056,13 @@
         // LBRACKET tested in caller.
         next();
 
-        // Prepare to accummulating elements.
+        // Prepare to accumulate elements.
         final List<Expression> elements = new ArrayList<>();
         // Track elisions.
         boolean elision = true;
 loop:
         while (true) {
-             switch (type) {
+            switch (type) {
             case RBRACKET:
                 next();
 
@@ -2223,7 +2226,7 @@
         switch (type) {
         case IDENT:
             return getIdent().setIsPropertyName();
-        case OCTAL:
+        case OCTAL_LEGACY:
             if (isStrictMode) {
                 throw error(AbstractParser.message("strict.no.octal"), token);
             }
@@ -2231,6 +2234,8 @@
         case ESCSTRING:
         case DECIMAL:
         case HEXADECIMAL:
+        case OCTAL:
+        case BINARY_NUMBER:
         case FLOATING:
             return getLiteral();
         default:
@@ -2284,7 +2289,7 @@
                 }
             }
 
-            propertyName =  createIdentNode(propertyToken, finish, ident).setIsPropertyName();
+            propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
         } else {
             propertyName = propertyName();
         }
@@ -2553,7 +2558,7 @@
             final long callToken = token;
 
             switch (type) {
-            case LBRACKET:
+            case LBRACKET: {
                 next();
 
                 // Get array index.
@@ -2565,8 +2570,8 @@
                 lhs = new IndexNode(callToken, finish, lhs, index);
 
                 break;
-
-            case PERIOD:
+            }
+            case PERIOD: {
                 if (lhs == null) {
                     throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
                 }
@@ -2579,7 +2584,7 @@
                 lhs = new AccessNode(callToken, finish, lhs, property.getName());
 
                 break;
-
+            }
             default:
                 break loop;
             }
@@ -3034,7 +3039,7 @@
         assert parserState != null;
 
         stream.reset();
-        lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions);
+        lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6);
         line = parserState.line;
         linePosition = parserState.linePosition;
         // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
@@ -3063,8 +3068,8 @@
             this.linePosition = linePosition;
         }
 
-        Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) {
-            final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true);
+        Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) {
+            final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true);
             newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
             return newLexer;
         }
@@ -3107,15 +3112,6 @@
         return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
     }
 
-    /*
-     * parse LHS [a, b, ..., c].
-     *
-     * JavaScript 1.8.
-     */
-    //private Node destructureExpression() {
-    //    return null;
-    //}
-
     /**
      * PostfixExpression :
      *      LeftHandSideExpression
@@ -3127,7 +3123,7 @@
      * UnaryExpression :
      *      PostfixExpression
      *      delete UnaryExpression
-     *      Node UnaryExpression
+     *      void UnaryExpression
      *      typeof UnaryExpression
      *      ++ UnaryExpression
      *      -- UnaryExpression
@@ -3333,7 +3329,6 @@
         // This method is protected so that subclass can get details
         // at expression start point!
 
-        // TODO - Destructuring array.
         // Include commas in expression parsing.
         return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
     }
@@ -3407,7 +3402,6 @@
         // This method is protected so that subclass can get details
         // at assignment expression start point!
 
-        // TODO - Handle decompose.
         // Exclude commas in expression parsing.
         return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Thu Sep 03 16:14:47 2015 -0700
@@ -170,8 +170,10 @@
     YIELD          (FUTURESTRICT,  "yield"),
 
     DECIMAL        (LITERAL,  null),
+    HEXADECIMAL    (LITERAL,  null),
+    OCTAL_LEGACY   (LITERAL,  null),
     OCTAL          (LITERAL,  null),
-    HEXADECIMAL    (LITERAL,  null),
+    BINARY_NUMBER  (LITERAL,  null),
     FLOATING       (LITERAL,  null),
     STRING         (LITERAL,  null),
     ESCSTRING      (LITERAL,  null),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AstSerializer.java	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.runtime.options.Options;
+
+/**
+ * This static utility class performs serialization of FunctionNode ASTs to a byte array.
+ * The format is a standard Java serialization stream, deflated.
+ */
+final class AstSerializer {
+    // Experimentally, we concluded that compression level 4 gives a good tradeoff between serialization speed
+    // and size.
+    private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
+    static byte[] serialize(final FunctionNode fn) {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
+        try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
+            oout.writeObject(fn);
+        } catch (final IOException e) {
+            throw new AssertionError("Unexpected exception serializing function", e);
+        } finally {
+            deflater.end();
+        }
+        return out.toByteArray();
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu Sep 03 16:14:47 2015 -0700
@@ -27,6 +27,7 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
+
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -820,7 +821,7 @@
         // isn't available, we'll use the old one bound into the call site.
         final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
         FunctionNode fn = effectiveOptInfo.reparse();
-        final boolean serialized = effectiveOptInfo.isSerialized();
+        final boolean cached = fn.isCached();
         final Compiler compiler = effectiveOptInfo.getCompiler(fn, ct, re); //set to non rest-of
 
         if (!shouldRecompile) {
@@ -828,11 +829,11 @@
             // recompiled a deoptimized version for an inner invocation.
             // We still need to do the rest of from the beginning
             logRecompile("Rest-of compilation [STANDALONE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
-            return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
+            return restOfHandle(effectiveOptInfo, compiler.compile(fn, cached ? CompilationPhases.COMPILE_CACHED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
         }
 
         logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
-        fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
+        fn = compiler.compile(fn, cached ? CompilationPhases.RECOMPILE_CACHED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
         log.fine("Reusable IR generated");
 
         // compile the rest of the function, and install it
@@ -956,10 +957,6 @@
         FunctionNode reparse() {
             return data.reparse();
         }
-
-        boolean isSerialized() {
-            return data.isSerialized();
-        }
     }
 
     @SuppressWarnings("unused")
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Sep 03 16:14:47 2015 -0700
@@ -26,16 +26,24 @@
 package jdk.nashorn.internal.runtime;
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
+
 import java.io.IOException;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@@ -45,8 +53,15 @@
 import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
 import jdk.nashorn.internal.codegen.TypeMap;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.SwitchNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TryNode;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.parser.Parser;
@@ -55,6 +70,7 @@
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.logging.Loggable;
 import jdk.nashorn.internal.runtime.logging.Logger;
+import jdk.nashorn.internal.runtime.options.Options;
 /**
  * This is a subclass that represents a script function that may be regenerated,
  * for example with specialization based on call site types, or lazily generated.
@@ -66,6 +82,8 @@
     /** Prefix used for all recompiled script classes */
     public static final String RECOMPILATION_PREFIX = "Recompilation$";
 
+    private static final ExecutorService astSerializerExecutorService = createAstSerializerExecutorService();
+
     /** Unique function node id for this function node */
     private final int functionNodeId;
 
@@ -77,8 +95,12 @@
     /** Source from which FunctionNode was parsed. */
     private transient Source source;
 
-    /** Serialized, compressed form of the AST. Used by split functions as they can't be reparsed from source. */
-    private final byte[] serializedAst;
+    /**
+     * Cached form of the AST. Either a {@code SerializedAst} object used by split functions as they can't be
+     * reparsed from source, or a soft reference to a {@code FunctionNode} for other functions (it is safe
+     * to be cleared as they can be reparsed).
+     */
+    private volatile Object cachedAst;
 
     /** Token of this function within the source. */
     private final long token;
@@ -128,7 +150,6 @@
      * @param nestedFunctions     nested function map
      * @param externalScopeDepths external scope depths
      * @param internalSymbols     internal symbols to method, defined in its scope
-     * @param serializedAst       a serialized AST representation. Normally only used for split functions.
      */
     public RecompilableScriptFunctionData(
         final FunctionNode functionNode,
@@ -136,8 +157,7 @@
         final AllocationStrategy allocationStrategy,
         final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
         final Map<String, Integer> externalScopeDepths,
-        final Set<String> internalSymbols,
-        final byte[] serializedAst) {
+        final Set<String> internalSymbols) {
 
         super(functionName(functionNode),
               Math.min(functionNode.getParameters().size(), MAX_ARITY),
@@ -161,7 +181,6 @@
             nfn.setParent(this);
         }
 
-        this.serializedAst = serializedAst;
         createLogger();
     }
 
@@ -244,7 +263,7 @@
      * @return parent data, or null if non exists and also null IF UNKNOWN.
      */
     public RecompilableScriptFunctionData getParent() {
-       return parent;
+        return parent;
     }
 
     void setParent(final RecompilableScriptFunctionData parent) {
@@ -358,13 +377,11 @@
         return allocationStrategy.allocate(map);
     }
 
-    boolean isSerialized() {
-        return serializedAst != null;
-    }
-
     FunctionNode reparse() {
-        if (isSerialized()) {
-            return deserialize();
+        final FunctionNode cachedFunction = getCachedAst();
+        if (cachedFunction != null) {
+            assert cachedFunction.isCached();
+            return cachedFunction;
         }
 
         final int descPosition = Token.descPosition(token);
@@ -391,7 +408,98 @@
         return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
     }
 
-    private FunctionNode deserialize() {
+    private FunctionNode getCachedAst() {
+        final Object lCachedAst = cachedAst;
+        // Are we softly caching the AST?
+        if (lCachedAst instanceof Reference<?>) {
+            final FunctionNode fn = (FunctionNode)((Reference<?>)lCachedAst).get();
+            if (fn != null) {
+                // Yes we are - this is fast
+                return cloneSymbols(fn);
+            }
+        // Are we strongly caching a serialized AST (for split functions only)?
+        } else if (lCachedAst instanceof SerializedAst) {
+            final SerializedAst serializedAst = (SerializedAst)lCachedAst;
+            // Even so, are we also softly caching the AST?
+            final FunctionNode cachedFn = serializedAst.cachedAst.get();
+            if (cachedFn != null) {
+                // Yes we are - this is fast
+                return cloneSymbols(cachedFn);
+            }
+            final FunctionNode deserializedFn = deserialize(serializedAst.serializedAst);
+            // Softly cache after deserialization, maybe next time we won't need to deserialize
+            serializedAst.cachedAst = new SoftReference<>(deserializedFn);
+            return deserializedFn;
+        }
+        // No cached representation; return null for reparsing
+        return null;
+    }
+
+    /**
+     * Sets the AST to cache in this function
+     * @param astToCache the new AST to cache
+     */
+    public void setCachedAst(final FunctionNode astToCache) {
+        assert astToCache.getId() == functionNodeId; // same function
+        assert !(cachedAst instanceof SerializedAst); // Can't overwrite serialized AST
+
+        final boolean isSplit = astToCache.isSplit();
+        // If we're caching a split function, we're doing it in the eager pass, hence there can be no other
+        // cached representation already. In other words, isSplit implies cachedAst == null.
+        assert !isSplit || cachedAst == null; //
+
+        final FunctionNode symbolClonedAst = cloneSymbols(astToCache);
+        final Reference<FunctionNode> ref = new SoftReference<>(symbolClonedAst);
+        cachedAst = ref;
+
+        // Asynchronously serialize split functions.
+        if (isSplit) {
+            astSerializerExecutorService.execute(() -> {
+                cachedAst = new SerializedAst(symbolClonedAst, ref);
+            });
+        }
+    }
+
+    /**
+     * Creates the AST serializer executor service used for in-memory serialization of split functions' ASTs.
+     * It is created with an unbounded queue (so it can queue any number of pending tasks). Its core and max
+     * threads is the same, but they are all allowed to time out so when there's no work, they can all go
+     * away. The threads will be daemons, and they will time out if idle for a minute. Their priority is also
+     * slightly lower than normal priority as we'd prefer the CPU to keep running the program; serializing
+     * split function is a memory conservation measure (it allows us to release the AST), it can wait a bit.
+     * @return an executor service with above described characteristics.
+     */
+    private static ExecutorService createAstSerializerExecutorService() {
+        final int threads = Math.max(1, Options.getIntProperty("nashorn.serialize.threads", Runtime.getRuntime().availableProcessors() / 2));
+        final ThreadPoolExecutor service = new ThreadPoolExecutor(threads, threads, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(),
+            (r) -> {
+                final Thread t = new Thread(r, "Nashorn AST Serializer");
+                t.setDaemon(true);
+                t.setPriority(Thread.NORM_PRIORITY - 1);
+                return t;
+            });
+        service.allowCoreThreadTimeOut(true);
+        return service;
+    }
+
+    /**
+     * A tuple of a serialized AST and a soft reference to a deserialized AST. This is used to cache split
+     * functions. Since split functions are altered from their source form, they can't be reparsed from
+     * source. While we could just use the {@code byte[]} representation in {@link RecompilableScriptFunctionData#cachedAst}
+     * we're using this tuple instead to also keep a deserialized AST around in memory to cut down on
+     * deserialization costs.
+     */
+    private static class SerializedAst {
+        private final byte[] serializedAst;
+        private volatile Reference<FunctionNode> cachedAst;
+
+        SerializedAst(final FunctionNode fn, final Reference<FunctionNode> cachedAst) {
+            this.serializedAst = AstSerializer.serialize(fn);
+            this.cachedAst = cachedAst;
+        }
+    }
+
+    private FunctionNode deserialize(final byte[] serializedAst) {
         final ScriptEnvironment env = installer.getOwner();
         final Timing timing = env._timing;
         final long t1 = System.nanoTime();
@@ -402,6 +510,107 @@
         }
     }
 
+    private FunctionNode cloneSymbols(final FunctionNode fn) {
+        final IdentityHashMap<Symbol, Symbol> symbolReplacements = new IdentityHashMap<>();
+        final boolean cached = fn.isCached();
+        // blockDefinedSymbols is used to re-mark symbols defined outside the function as global. We only
+        // need to do this when we cache an eagerly parsed function (which currently means a split one, as we
+        // don't cache non-split functions from the eager pass); those already cached, or those not split
+        // don't need this step.
+        final Set<Symbol> blockDefinedSymbols = fn.isSplit() && !cached ? Collections.newSetFromMap(new IdentityHashMap<>()) : null;
+        FunctionNode newFn = (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+
+            private Symbol getReplacement(final Symbol original) {
+                if (original == null) {
+                    return null;
+                }
+                final Symbol existingReplacement = symbolReplacements.get(original);
+                if (existingReplacement != null) {
+                    return existingReplacement;
+                }
+                final Symbol newReplacement = original.clone();
+                symbolReplacements.put(original, newReplacement);
+                return newReplacement;
+            }
+
+            @Override
+            public Node leaveIdentNode(final IdentNode identNode) {
+                final Symbol oldSymbol = identNode.getSymbol();
+                if (oldSymbol != null) {
+                    final Symbol replacement = getReplacement(oldSymbol);
+                    return identNode.setSymbol(replacement);
+                }
+                return identNode;
+            }
+
+            @Override
+            public Node leaveForNode(final ForNode forNode) {
+                return ensureUniqueLabels(forNode.setIterator(lc, getReplacement(forNode.getIterator())));
+            }
+
+            @Override
+            public Node leaveSwitchNode(final SwitchNode switchNode) {
+                return ensureUniqueLabels(switchNode.setTag(lc, getReplacement(switchNode.getTag())));
+            }
+
+            @Override
+            public Node leaveTryNode(final TryNode tryNode) {
+                return ensureUniqueLabels(tryNode.setException(lc, getReplacement(tryNode.getException())));
+            }
+
+            @Override
+            public boolean enterBlock(final Block block) {
+                for(final Symbol symbol: block.getSymbols()) {
+                    final Symbol replacement = getReplacement(symbol);
+                    if (blockDefinedSymbols != null) {
+                        blockDefinedSymbols.add(replacement);
+                    }
+                }
+                return true;
+            }
+
+            @Override
+            public Node leaveBlock(final Block block) {
+                return ensureUniqueLabels(block.replaceSymbols(lc, symbolReplacements));
+            }
+
+            @Override
+            public Node leaveFunctionNode(final FunctionNode functionNode) {
+                return functionNode.setParameters(lc, functionNode.visitParameters(this));
+            }
+
+            @Override
+            protected Node leaveDefault(final Node node) {
+                return ensureUniqueLabels(node);
+            };
+
+            private Node ensureUniqueLabels(final Node node) {
+                // If we're returning a cached AST, we must also ensure unique labels
+                return cached ? node.ensureUniqueLabels(lc) : node;
+            }
+        });
+
+        if (blockDefinedSymbols != null) {
+            // Mark all symbols not defined in blocks as globals
+            Block newBody = null;
+            for(final Symbol symbol: symbolReplacements.values()) {
+                if(!blockDefinedSymbols.contains(symbol)) {
+                    assert symbol.isScope(); // must be scope
+                    assert externalScopeDepths.containsKey(symbol.getName()); // must be known to us as an external
+                    // Register it in the function body symbol table as a new global symbol
+                    symbol.setFlags((symbol.getFlags() & ~Symbol.KINDMASK) | Symbol.IS_GLOBAL);
+                    if (newBody == null) {
+                        newBody = newFn.getBody().copyWithNewSymbols();
+                        newFn = newFn.setBody(null, newBody);
+                    }
+                    assert newBody.getExistingSymbol(symbol.getName()) == null; // must not be defined in the body already
+                    newBody.putSymbol(symbol);
+                }
+            }
+        }
+        return newFn.setCached(null);
+    }
+
     private boolean getFunctionFlag(final int flag) {
         return (functionFlags & flag) != 0;
     }
@@ -512,9 +721,9 @@
         final FunctionNode fn = reparse();
         final Compiler compiler = getCompiler(fn, actualCallSiteType, runtimeScope);
         final FunctionNode compiledFn = compiler.compile(fn,
-                isSerialized() ? CompilationPhases.COMPILE_ALL_SERIALIZED : CompilationPhases.COMPILE_ALL);
+                fn.isCached() ? CompilationPhases.COMPILE_ALL_CACHED : CompilationPhases.COMPILE_ALL);
 
-        if (persist && !compiledFn.getFlag(FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION)) {
+        if (persist && !compiledFn.hasApplyToCallSpecialization()) {
             compiler.persistClassInfo(cacheKey, compiledFn);
         }
         return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Thu Sep 03 16:14:47 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.ECMAErrors.rangeError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
@@ -70,6 +71,9 @@
     /** EXIT name - special property used by $EXEC API. */
     public static final String EXIT_NAME = "$EXIT";
 
+    /** THROW_ON_ERROR name - special property of the $EXEC function used by $EXEC API. */
+    public static final String THROW_ON_ERROR_NAME = "throwOnError";
+
     /** Names of special properties used by $ENV API. */
     public  static final String ENV_NAME  = "$ENV";
 
@@ -247,6 +251,19 @@
             }
         }
 
+        // if we got a non-zero exit code ("failure"), then we have to decide to throw error or not
+        if (exit != 0) {
+            // get the $EXEC function object from the global object
+            final Object exec = global.get(EXEC_NAME);
+            assert exec instanceof ScriptObject : EXEC_NAME + " is not a script object!";
+
+            // Check if the user has set $EXEC.throwOnError property to true. If so, throw RangeError
+            // If that property is not set or set to false, then silently proceed with the rest.
+            if (JSType.toBoolean(((ScriptObject)exec).get(THROW_ON_ERROR_NAME))) {
+                throw rangeError("exec.returned.non.zero", ScriptRuntime.safeToString(exit));
+            }
+        }
+
         // Return the result from stdout.
         return out;
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java	Thu Sep 03 14:24:47 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-/**
- * Mechanism for communicating that something isn't a plain
- * numeric integer array index. This enables things like
- * array getters for the fast case in a try, basically
- * just consisting of an "array[index]" access without
- * any checks of boundary conditions that rarely happen
- */
-@SuppressWarnings("serial")
-class InvalidArrayIndexException extends Exception {
-
-    private final Object index;
-
-    InvalidArrayIndexException(final Object index) {
-        super(index == null ? "null" : index.toString());
-        this.index = index;
-    }
-
-    InvalidArrayIndexException(final int index) {
-        this(Integer.valueOf(index));
-    }
-
-    InvalidArrayIndexException(final long index) {
-        this(Long.valueOf(index));
-    }
-
-    InvalidArrayIndexException(final double index) {
-        this(Double.valueOf(index));
-    }
-
-    @Override
-    public String toString() {
-        return index.toString();
-    }
-
-    Object getIndex() {
-        return index;
-    }
-
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/AdaptationException.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/AdaptationException.java	Thu Sep 03 16:14:47 2015 -0700
@@ -30,6 +30,7 @@
     private final AdaptationResult adaptationResult;
 
     AdaptationException(final AdaptationResult.Outcome outcome, final String classList) {
+        super(null, null, false, false);
         this.adaptationResult = new AdaptationResult(outcome, classList);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Thu Sep 03 16:14:47 2015 -0700
@@ -189,7 +189,7 @@
      * @return true if the obj is an instance of @FunctionalInterface interface
      */
     public static boolean isFunctionalInterfaceObject(final Object obj) {
-        return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
+        return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethodName(obj.getClass()) != null);
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Thu Sep 03 16:14:47 2015 -0700
@@ -79,10 +79,10 @@
     }
 
     // cache of @FunctionalInterface method of implementor classes
-    private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
+    private static final ClassValue<String> FUNCTIONAL_IFACE_METHOD_NAME = new ClassValue<String>() {
         @Override
-        protected Method computeValue(final Class<?> type) {
-            return findFunctionalInterfaceMethod(type);
+        protected String computeValue(final Class<?> type) {
+            return findFunctionalInterfaceMethodName(type);
         }
     };
 
@@ -107,19 +107,21 @@
             // annotated interface. This way Java method, constructor references or
             // implementations of java.util.function.* interfaces can be called as though
             // those are script functions.
-            final Method m = getFunctionalInterfaceMethod(self.getClass());
-            if (m != null) {
+            final String name = getFunctionalInterfaceMethodName(self.getClass());
+            if (name != null) {
                 final MethodType callType = desc.getMethodType();
-                // 'callee' and 'thiz' passed from script + actual arguments
-                if (callType.parameterCount() != m.getParameterCount() + 2) {
-                    throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
-                }
-                return new GuardedInvocation(
-                        // drop 'thiz' passed from the script.
-                        MH.dropArguments(linkerServices.filterInternalObjects(desc.getLookup().unreflect(m)), 1,
-                                callType.parameterType(1)), Guards.getInstanceOfGuard(
-                                        m.getDeclaringClass())).asTypeSafeReturn(
-                                                new NashornBeansLinkerServices(linkerServices), callType);
+                // drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name>
+                final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(desc.getLookup(),
+                        "dyn:callMethod:" + name, desc.getMethodType().dropParameterTypes(1, 2),
+                        NashornCallSiteDescriptor.getFlags(desc));
+                final GuardedInvocation gi = getGuardedInvocation(beansLinker,
+                        linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
+                        new NashornBeansLinkerServices(linkerServices));
+
+                // drop 'thiz' passed from the script.
+                return gi.replaceMethods(
+                    MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)),
+                    gi.getGuard());
             }
         }
         return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
@@ -163,7 +165,7 @@
         return arg instanceof ConsString ? arg.toString() : arg;
     }
 
-    private static Method findFunctionalInterfaceMethod(final Class<?> clazz) {
+    private static String findFunctionalInterfaceMethodName(final Class<?> clazz) {
         if (clazz == null) {
             return null;
         }
@@ -179,20 +181,20 @@
                 // return the first abstract method
                 for (final Method m : iface.getMethods()) {
                     if (Modifier.isAbstract(m.getModifiers())) {
-                        return m;
+                        return m.getName();
                     }
                 }
             }
         }
 
         // did not find here, try super class
-        return findFunctionalInterfaceMethod(clazz.getSuperclass());
+        return findFunctionalInterfaceMethodName(clazz.getSuperclass());
     }
 
     // Returns @FunctionalInterface annotated interface's single abstract
-    // method. If not found, returns null.
-    static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
-        return FUNCTIONAL_IFACE_METHOD.get(clazz);
+    // method name. If not found, returns null.
+    static String getFunctionalInterfaceMethodName(final Class<?> clazz) {
+        return FUNCTIONAL_IFACE_METHOD_NAME.get(clazz);
     }
 
     static MethodHandleTransformer createHiddenObjectFilter() {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java	Thu Sep 03 16:14:47 2015 -0700
@@ -24,6 +24,6 @@
     private static final long serialVersionUID = -6027192180014164667L;
 
     public JOniException(final String message) {
-        super(message);
+        super(message, null, false, false);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Sep 03 16:14:47 2015 -0700
@@ -163,6 +163,7 @@
 range.error.invalid.date=Invalid Date
 range.error.too.many.errors=Script contains too many errors: {0} errors
 range.error.concat.string.too.big=Concatenated String is too big
+range.error.exec.returned.non.zero=$EXEC returned non-zero exit code: {0}
 
 reference.error.not.defined="{0}" is not defined
 reference.error.cant.be.used.as.lhs="{0}" can not be used as the left-hand side of assignment
--- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED	Thu Sep 03 16:14:47 2015 -0700
@@ -1,14 +1,28 @@
 bcd
-[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)]
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
 red
 TypeError: No such Java class: java.lang.NonExistent
 TypeError: No such Java constructor: Object(String)
 TypeError: Java constructor signature invalid: Object()xxxxx
 TypeError: Java constructor signature invalid: Object(
 TypeError: Java constructor signature invalid: Object)
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor.
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor.
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new".
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ String java.lang.System.getProperty(String,String)
+ String java.lang.System.getProperty(String)
+] cannot be used as a constructor.
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+] cannot be used as a constructor.
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
 TypeError: No such Java constructor: Runnable()
 TypeError: No such Java constructor: Runnable(int)
 java.lang.InstantiationException: java.io.InputStream
--- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED	Thu Sep 03 16:14:47 2015 -0700
@@ -1,10 +1,10 @@
 abc
-[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)]
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
 ava
 TypeError: null is not a function
 TypeError: null is not a function
 TypeError: null is not a function
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new".
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
 TypeError: null is not a function
 TypeError: null is not a function
 java.lang.InstantiationException: java.io.InputStream
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068901.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8068901: Surprising behavior with more than one functional interface on a class
+ *
+ * @test
+ * @run
+ */
+
+var Consumer = java.util.function.Consumer;
+var JFunction = java.util.function.Function;
+
+var fc = new (Java.extend(JFunction, Consumer))({
+    apply: function(x) { print("fc invoked as a function") },
+    accept: function(x) { print("fc invoked as a consumer") }
+});
+
+var c = new Consumer(function(x) { print("c invoked as a consumer") });
+
+var cf = new (Java.extend(Consumer, JFunction))({
+    apply: function(x) { print("cf invoked as a function") },
+    accept: function(x) { print("cf invoked as a consumer") }
+});
+
+var f = new JFunction(function(x) { print("f invoked as a function") });
+
+for each(x in [fc, c, fc, cf, f, cf, c, fc, f, cf]) { x(null); }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068901.js.EXPECTED	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,10 @@
+fc invoked as a function
+c invoked as a consumer
+fc invoked as a function
+cf invoked as a consumer
+f invoked as a function
+cf invoked as a consumer
+c invoked as a consumer
+fc invoked as a function
+f invoked as a function
+cf invoked as a consumer
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068903.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,40 @@
+/*
+ * 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-8068903: Can't invoke vararg @FunctionalInterface methods
+ *
+ * @test
+ * @run
+ */
+
+var vc = new (Java.type("jdk.nashorn.test.models.VarArgConsumer"))(
+    function(x) {
+        Assert.assertTrue(x.length == 3);
+        Assert.assertTrue(x[0] == 1);
+        Assert.assertTrue(x[1] == 2);
+        Assert.assertTrue(x[2] == 3);
+    }
+);
+
+vc(1, 2, 3);
--- a/nashorn/test/script/basic/JDK-8079470.js.EXPECTED	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/test/script/basic/JDK-8079470.js.EXPECTED	Thu Sep 03 16:14:47 2015 -0700
@@ -1,2 +1,2 @@
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod File java.io.File.java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134731.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8134731: `Function.prototype.apply` interacts incorrectly with `arguments` 
+ *
+ * @test
+ * @run
+ */
+
+function func() {
+    return (function(f){
+        return function(a1, a2, a3, a4){
+            return (f.apply(this, arguments));
+        }
+    })(function(){
+        return arguments.length;
+    })
+}
+
+Assert.assertTrue(func()() == 0);
+Assert.assertTrue(func()(33) == 1);
+Assert.assertTrue(func()(33, true) == 2);
+Assert.assertTrue(func()(33, true, "hello") == 3);
+Assert.assertTrue(func()(33, true, "hello", "world") == 4);
+Assert.assertTrue(func()(33, true, "hello", "world", 42) == 5);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134865.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 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-8134865: Need to restore for container block from lexical context in finally
+ *
+ * @test
+ * @option --language=es6
+ */
+
+try {
+  eval("function f() { for (x : y) { } }");
+  throw "should not reach here";
+} catch (e) {
+  if (!(e instanceof SyntaxError)) throw e;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134939.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,43 @@
+/*
+ * 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-8134939: Improve toString method of Dynalink OverloadedDynamicMethod
+ *
+ * @test
+ * @run
+ */
+
+var overloadedSetter = new (Java.type("jdk.nashorn.test.models.OverloadedSetter"));
+
+Assert.assertEquals(String(overloadedSetter.foo),
+  "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+  " String jdk.nashorn.test.models.OverloadedSetter.foo(String)\n" +
+  " void jdk.nashorn.test.models.OverloadedSetter.foo(int)\n" +
+  "]");
+
+Assert.assertEquals(String(overloadedSetter.setColor),
+  "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+  " void jdk.nashorn.test.models.OverloadedSetter.setColor(int)\n" +
+  " void jdk.nashorn.test.models.OverloadedSetter.setColor(String)\n" +
+  "]");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/numeric-literals.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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-8134873: ECMAScript 6 Numeric Literals
+ *
+ * @test
+ * @option --language=es6
+ */
+
+function assertEquals(expected, actual) {
+  if (expected !== actual) {
+    throw new Error("expected: " + expected + ", actual: " + actual);
+  }
+}
+
+assertEquals(0b0, 0);
+assertEquals(0B0, 0);
+assertEquals(0b01, 1);
+assertEquals(0B10, 2);
+assertEquals(0b11111111, 255);
+assertEquals(0b11111111111111111111111111111111, 4294967295);
+
+assertEquals(0o0, 0);
+assertEquals(0O0, 0);
+assertEquals(0o01, 1);
+assertEquals(0O10, 8);
+assertEquals(0o777, 511);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8087292.js	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,54 @@
+/*
+ * 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-8087292: nashorn should have a "fail-fast" option for scripting, analog to bash "set -e"
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+function tryExec() {
+    try {
+        `java`
+    } catch (e) {
+        print(e);
+    }
+
+    // make sure we got non-zero ("failure") exit code!
+    if ($EXIT == 0) {
+        print("Error: expected $EXIT code to be non-zero");
+    }
+}
+
+// no exception now!
+tryExec();
+
+// turn on error with non-zero exit code
+$EXEC.throwOnError = true;
+tryExec();
+
+// no exception after this
+$EXEC.throwOnError = false;
+tryExec();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8087292.js.EXPECTED	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,1 @@
+RangeError: $EXEC returned non-zero exit code: 1
--- a/nashorn/test/script/trusted/classfilter.js.EXPECTED	Thu Sep 03 14:24:47 2015 -0700
+++ b/nashorn/test/script/trusted/classfilter.js.EXPECTED	Thu Sep 03 16:14:47 2015 -0700
@@ -4,7 +4,18 @@
 typeof java.util.Map evalutes to function
 typeof java.util.HashMap evalutes to function
 var m = new java.util.HashMap(); m.put('foo', 42); m evalutes to {foo=42}
-java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println]
+java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+]
 java.lang.System.exit evalutes to [jdk.internal.dynalink.beans.SimpleDynamicMethod void java.lang.System.exit(int)]
 new javax.script.SimpleBindings throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.SimpleBindings
 Java.type('javax.script.ScriptContext') throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.ScriptContext
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java	Thu Sep 03 16:14:47 2015 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+/**
+ * Simple function interface with a varargs SAM method.
+ */
+@FunctionalInterface
+public interface VarArgConsumer {
+    public void apply(Object... o);
+}
+