8051889: Implement block scoping in symbol assignment and scope computation
authorhannesw
Thu, 04 Sep 2014 15:37:14 +0200
changeset 26377 028dad61662f
parent 26376 31155daecdc7
child 26378 ca7093bd5fd1
8051889: Implement block scoping in symbol assignment and scope computation Reviewed-by: attila, lagergren
nashorn/make/build.xml
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MapCreator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java
nashorn/test/script/basic/es6/block-function-decl.js
nashorn/test/script/basic/es6/block-function-decl.js.EXPECTED
nashorn/test/script/basic/es6/const-empty.js
nashorn/test/script/basic/es6/const-empty.js.EXPECTED
nashorn/test/script/basic/es6/const-reassign.js
nashorn/test/script/basic/es6/const-reassign.js.EXPECTED
nashorn/test/script/basic/es6/const-redeclare.js
nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED
nashorn/test/script/basic/es6/const-self.js
nashorn/test/script/basic/es6/const-self.js.EXPECTED
nashorn/test/script/basic/es6/const-tdz.js
nashorn/test/script/basic/es6/const-tdz.js.EXPECTED
nashorn/test/script/basic/es6/const.js
nashorn/test/script/basic/es6/const.js.EXPECTED
nashorn/test/script/basic/es6/for-let.js
nashorn/test/script/basic/es6/for-let.js.EXPECTED
nashorn/test/script/basic/es6/let-eval.js
nashorn/test/script/basic/es6/let-eval.js.EXPECTED
nashorn/test/script/basic/es6/let-load-lib.js
nashorn/test/script/basic/es6/let-load.js
nashorn/test/script/basic/es6/let-load.js.EXPECTED
nashorn/test/script/basic/es6/let-nodeclare.js
nashorn/test/script/basic/es6/let-nodeclare.js.EXPECTED
nashorn/test/script/basic/es6/let-redeclare.js
nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED
nashorn/test/script/basic/es6/let-self.js
nashorn/test/script/basic/es6/let-self.js.EXPECTED
nashorn/test/script/basic/es6/let-tdz.js
nashorn/test/script/basic/es6/let-tdz.js.EXPECTED
nashorn/test/script/basic/es6/let.js
nashorn/test/script/basic/es6/let.js.EXPECTED
nashorn/test/script/trusted/JDK-8006529.js
nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java
nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java
--- a/nashorn/make/build.xml	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/make/build.xml	Thu Sep 04 15:37:14 2014 +0200
@@ -341,6 +341,13 @@
     permission java.util.PropertyPermission "nashorn.test.*", "read";
 };
 
+grant codeBase "file:/${basedir}/test/script/basic/es6/*" {
+    permission java.io.FilePermission "${basedir}/test/script/-", "read";
+    permission java.io.FilePermission "$${user.dir}", "read";
+    permission java.util.PropertyPermission "user.dir", "read";
+    permission java.util.PropertyPermission "nashorn.test.*", "read";
+};
+
 grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
     permission java.util.PropertyPermission "java.security.policy", "read";
 };
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Sep 04 15:37:14 2014 +0200
@@ -36,6 +36,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 import static jdk.nashorn.internal.ir.Symbol.HAS_OBJECT_VALUE;
+import static jdk.nashorn.internal.ir.Symbol.IS_CONST;
 import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
 import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
@@ -83,11 +84,13 @@
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.Property;
-import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ECMAErrors;
+import jdk.nashorn.internal.runtime.ErrorManager;
+import jdk.nashorn.internal.runtime.JSErrorType;
+import jdk.nashorn.internal.runtime.ParserException;
+import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.logging.Loggable;
 import jdk.nashorn.internal.runtime.logging.Logger;
@@ -101,7 +104,7 @@
  * visitor.
  */
 @Logger(name="symbols")
-final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements Loggable {
+final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggable {
     private final DebugLogger log;
     private final boolean     debug;
 
@@ -190,8 +193,7 @@
      * @param body the body of the FunctionNode we are entering
      */
     private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
-        // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
-        // in a separate step above) and "var" declarations in for loop initializers.
+        // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
         //
         body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
             @Override
@@ -204,8 +206,8 @@
             public Node leaveVarNode(final VarNode varNode) {
                 if (varNode.isStatement()) {
                     final IdentNode ident  = varNode.getName();
-                    final Symbol    symbol = defineSymbol(body, ident.getName(), IS_VAR);
-                    functionNode.addDeclaredSymbol(symbol);
+                    final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;
+                    final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
                     if (varNode.isFunctionDeclaration()) {
                         symbol.setIsFunctionDeclaration();
                     }
@@ -303,23 +305,31 @@
         return functionNode.setBody(lc, body.setStatements(lc, newStatements));
     }
 
-    private Symbol defineGlobalSymbol(final Block block, final String name) {
-        return defineSymbol(block, name, IS_GLOBAL);
-    }
-
     /**
      * Defines a new symbol in the given block.
      *
      * @param block        the block in which to define the symbol
      * @param name         name of symbol.
+     * @param origin       origin node
      * @param symbolFlags  Symbol flags.
      *
      * @return Symbol for given name or null for redefinition.
      */
-    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
+    private Symbol defineSymbol(final Block block, final String name, final Node origin, final int symbolFlags) {
         int    flags  = symbolFlags;
-        Symbol symbol = findSymbol(block, name); // Locate symbol.
-        final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
+        final boolean isBlockScope = (flags & IS_LET) != 0 || (flags & IS_CONST) != 0;
+        final boolean isGlobal     = (flags & KINDMASK) == IS_GLOBAL;
+
+        Symbol symbol;
+        final FunctionNode function;
+        if (isBlockScope) {
+            // block scoped variables always live in current block, no need to look for existing symbols in parent blocks.
+            symbol = block.getExistingSymbol(name);
+            function = lc.getCurrentFunction();
+        } else {
+            symbol = findSymbol(block, name);
+            function = lc.getFunction(block);
+        }
 
         // Global variables are implicitly always scope variables too.
         if (isGlobal) {
@@ -333,7 +343,6 @@
         final boolean isParam = (flags & KINDMASK) == IS_PARAM;
         final boolean isVar =   (flags & KINDMASK) == IS_VAR;
 
-        final FunctionNode function = lc.getFunction(block);
         if (symbol != null) {
             // Symbol was already defined. Check if it needs to be redefined.
             if (isParam) {
@@ -345,10 +354,21 @@
                     throw new AssertionError("duplicate parameter");
                 }
             } else if (isVar) {
-                if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
+                if (isBlockScope) {
+                    // Check redeclaration in same block
+                    if (symbol.hasBeenDeclared()) {
+                        throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
+                    } else {
+                        symbol.setHasBeenDeclared();
+                    }
+                } else if ((flags & IS_INTERNAL) != 0) {
                     // Always create a new definition.
                     symbol = null;
                 } else {
+                    // Found LET or CONST in parent scope of same function - s SyntaxError
+                    if (symbol.isBlockScoped() && isLocal(lc.getCurrentFunction(), symbol)) {
+                        throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
+                    }
                     // Not defined in this function. Create a new definition.
                     if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
                         symbol = null;
@@ -359,10 +379,10 @@
 
         if (symbol == null) {
             // If not found, then create a new one.
-            Block symbolBlock;
+            final Block symbolBlock;
 
             // Determine where to create it.
-            if (isVar && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
+            if (isVar && ((flags & IS_INTERNAL) != 0 || isBlockScope)) {
                 symbolBlock = block; //internal vars are always defined in the block closest to them
             } else if (isGlobal) {
                 symbolBlock = lc.getOutermostFunction().getBody();
@@ -420,9 +440,9 @@
     @Override
     public boolean enterBlock(final Block block) {
         start(block);
-        block.clearSymbols();
 
         if (lc.isFunctionBody()) {
+            block.clearSymbols();
             enterFunctionBody();
         }
 
@@ -441,7 +461,10 @@
         // If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
         // symbol is naturally internal, and should be treated as such.
         final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
-        defineSymbol(block, exname, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
+        // IS_LET flag is required to make sure symbol is not visible outside catch block. However, we need to
+        // clear the IS_LET flag after creation to allow redefinition of symbol inside the catch block.
+        final Symbol symbol = defineSymbol(block, exname, catchNode, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
+        symbol.clearFlag(IS_LET);
 
         return true;
     }
@@ -452,15 +475,13 @@
 
         initFunctionWideVariables(functionNode, body);
 
-        if (functionNode.isProgram()) {
-            initGlobalSymbols(body);
-        } else if (!functionNode.isDeclared() && !functionNode.isAnonymous()) {
+        if (!functionNode.isProgram() && !functionNode.isDeclared() && !functionNode.isAnonymous()) {
             // It's neither declared nor program - it's a function expression then; assign it a self-symbol unless it's
             // anonymous.
             final String name = functionNode.getIdent().getName();
             assert name != null;
             assert body.getExistingSymbol(name) == null;
-            defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
+            defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
             if(functionNode.allVarsInScope()) { // basically, has deep eval
                 lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
             }
@@ -485,7 +506,8 @@
         if (functionNode.isDeclared()) {
             final Iterator<Block> blocks = lc.getBlocks();
             if (blocks.hasNext()) {
-                defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
+                final IdentNode ident = functionNode.getIdent();
+                defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
             }
         }
 
@@ -495,10 +517,16 @@
     @Override
     public boolean enterVarNode(final VarNode varNode) {
         start(varNode);
-        defineSymbol(lc.getCurrentBlock(), varNode.getName().getName(), IS_VAR | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
         return true;
     }
 
+    @Override
+    public Node leaveVarNode(final VarNode varNode) {
+        final IdentNode ident = varNode.getName();
+        defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
+        return super.leaveVarNode(varNode);
+    }
+
     private Symbol exceptionSymbol() {
         return newObjectInternal(EXCEPTION_PREFIX);
     }
@@ -597,7 +625,7 @@
     }
 
     private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
-        defineSymbol(block, cc.symbolName(), flags).setNeedsSlot(true);
+        defineSymbol(block, cc.symbolName(), null, flags).setNeedsSlot(true);
     }
 
     private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
@@ -608,7 +636,7 @@
             initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
             if (functionNode.needsArguments()) {
                 initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
-                defineSymbol(body, ARGUMENTS_VAR.symbolName(), IS_VAR | HAS_OBJECT_VALUE);
+                defineSymbol(body, ARGUMENTS_VAR.symbolName(), null, IS_VAR | HAS_OBJECT_VALUE);
             }
         }
 
@@ -617,20 +645,6 @@
         initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL);
     }
 
-
-    /**
-     * Move any properties from the global map into the scope of this function (which must be a program function).
-     * @param block the function node body for which to init scope vars
-     */
-    private void initGlobalSymbols(final Block block) {
-        final PropertyMap map = Context.getGlobalMap();
-
-        for (final Property property : map.getProperties()) {
-            final Symbol symbol = defineGlobalSymbol(block, property.getKey());
-            log.info("Added global symbol from property map ", symbol);
-        }
-    }
-
     /**
      * Initialize parameters for function node.
      * @param functionNode the function node
@@ -639,7 +653,7 @@
         final boolean isVarArg = functionNode.isVarArg();
         final boolean scopeParams = functionNode.allVarsInScope() || isVarArg;
         for (final IdentNode param : functionNode.getParameters()) {
-            final Symbol symbol = defineSymbol(body, param.getName(), IS_PARAM);
+            final Symbol symbol = defineSymbol(body, param.getName(), param, IS_PARAM);
             if(scopeParams) {
                 // NOTE: this "set is scope" is a poor substitute for clear expression of where the symbol is stored.
                 // It will force creation of scopes where they would otherwise not necessarily be needed (functions
@@ -665,10 +679,29 @@
         return definingFn == function;
     }
 
+    private void checkConstAssignment(final IdentNode ident) {
+        // Check for reassignment of constant
+        final Symbol symbol = ident.getSymbol();
+        if (symbol.isConst()) {
+            throwParserException(ECMAErrors.getMessage("syntax.error.assign.constant", symbol.getName()), ident);
+        }
+    }
+
     @Override
-    public Node leaveASSIGN(final BinaryNode binaryNode) {
+    public Node leaveBinaryNode(final BinaryNode binaryNode) {
+        if (binaryNode.isAssignment() && binaryNode.lhs() instanceof IdentNode) {
+            checkConstAssignment((IdentNode) binaryNode.lhs());
+        }
+        switch (binaryNode.tokenType()) {
+        case ASSIGN:
+            return leaveASSIGN(binaryNode);
+        default:
+            return super.leaveBinaryNode(binaryNode);
+        }
+    }
+
+    private Node leaveASSIGN(final BinaryNode binaryNode) {
         // If we're assigning a property of the this object ("this.foo = ..."), record it.
-
         final Expression lhs = binaryNode.lhs();
         if (lhs instanceof AccessNode) {
             final AccessNode accessNode = (AccessNode) lhs;
@@ -684,6 +717,21 @@
     }
 
     @Override
+    public Node leaveUnaryNode(final UnaryNode unaryNode) {
+        if (unaryNode.isAssignment() && unaryNode.getExpression() instanceof IdentNode) {
+            checkConstAssignment((IdentNode) unaryNode.getExpression());
+        }
+        switch (unaryNode.tokenType()) {
+        case DELETE:
+            return leaveDELETE(unaryNode);
+        case TYPEOF:
+            return leaveTYPEOF(unaryNode);
+        default:
+            return super.leaveUnaryNode(unaryNode);
+        }
+    }
+
+    @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
@@ -699,8 +747,7 @@
         return block;
     }
 
-    @Override
-    public Node leaveDELETE(final UnaryNode unaryNode) {
+    private Node leaveDELETE(final UnaryNode unaryNode) {
         final FunctionNode currentFunctionNode = lc.getCurrentFunction();
         final boolean      strictMode          = currentFunctionNode.isStrict();
         final Expression   rhs                 = unaryNode.getExpression();
@@ -799,9 +846,8 @@
             // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
             maybeForceScope(symbol);
         } else {
-            log.info("No symbol exists. Declare as global: ", symbol);
-            symbol = defineGlobalSymbol(block, name);
-            Symbol.setSymbolIsScope(lc, symbol);
+            log.info("No symbol exists. Declare as global: ", name);
+            symbol = defineSymbol(block, name, identNode, IS_GLOBAL | IS_SCOPE);
         }
 
         functionUsesSymbol(symbol);
@@ -810,7 +856,15 @@
             symbol.increaseUseCount();
         }
 
-        return end(identNode.setSymbol(symbol));
+        IdentNode newIdentNode = identNode.setSymbol(symbol);
+
+        // If a block-scoped var is used before its declaration mark it as dead.
+        // We can only statically detect this for local vars, cross-function symbols require runtime checks.
+        if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
+            newIdentNode = newIdentNode.markDead();
+        }
+
+        return end(newIdentNode);
     }
 
     @Override
@@ -834,8 +888,7 @@
         return tryNode;
     }
 
-    @Override
-    public Node leaveTYPEOF(final UnaryNode unaryNode) {
+    private Node leaveTYPEOF(final UnaryNode unaryNode) {
         final Expression rhs = unaryNode.getExpression();
 
         final List<Expression> args = new ArrayList<>();
@@ -875,7 +928,7 @@
     }
 
     private Symbol newInternal(final CompilerConstants cc, final int flags) {
-        return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), IS_VAR | IS_INTERNAL | flags); //NASHORN-73
+        return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), null, IS_VAR | IS_INTERNAL | flags); //NASHORN-73
     }
 
     private Symbol newObjectInternal(final CompilerConstants cc) {
@@ -915,7 +968,8 @@
             return false;
         }
 
-        if (lc.getCurrentFunction().allVarsInScope()) {
+        final FunctionNode func = lc.getCurrentFunction();
+        if ( func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) {
             return true;
         }
 
@@ -955,4 +1009,16 @@
         final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
         return !(units == null || units.isEmpty());
     }
+
+    private void throwParserException(final String message, final Node origin) {
+        if (origin == null) {
+            throw new ParserException(message);
+        }
+        final Source source = compiler.getSource();
+        final long token = origin.getToken();
+        final int line = source.getLine(origin.getStart());
+        final int column = source.getColumn(origin.getStart());
+        final String formatted = ErrorManager.format(message, source, line, column, token);
+        throw new ParserException(JSErrorType.SYNTAX_ERROR, formatted, source, line, column, token);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Sep 04 15:37:14 2014 +0200
@@ -52,6 +52,7 @@
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_APPLY_TO_CALL;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_DECLARE;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
@@ -302,6 +303,7 @@
      * @return the method generator used
      */
     private MethodEmitter loadIdent(final IdentNode identNode, final TypeBounds resultBounds) {
+        checkTemporalDeadZone(identNode);
         final Symbol symbol = identNode.getSymbol();
 
         if (!symbol.isScope()) {
@@ -334,6 +336,15 @@
         return method;
     }
 
+    // Any access to LET and CONST variables before their declaration must throw ReferenceError.
+    // This is called the temporal dead zone (TDZ). See https://gist.github.com/rwaldron/f0807a758aa03bcdd58a
+    private void checkTemporalDeadZone(final IdentNode identNode) {
+        if (identNode.isDead()) {
+            method.load(identNode.getSymbol().getName());
+            method.invoke(ScriptRuntime.THROW_REFERENCE_ERROR);
+        }
+    }
+
     private boolean isRestOf() {
         return continuationEntryPoints != null;
     }
@@ -3216,27 +3227,34 @@
             return false;
         }
         final Expression init = varNode.getInit();
+        final IdentNode identNode = varNode.getName();
+        final Symbol identSymbol = identNode.getSymbol();
+        assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
+        final boolean needsScope = identSymbol.isScope();
 
         if (init == null) {
+            if (needsScope && varNode.isBlockScoped()) {
+                // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
+                method.loadCompilerConstant(SCOPE);
+                method.loadUndefined(Type.OBJECT);
+                final int flags = CALLSITE_SCOPE | getCallSiteFlags() | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
+                assert isFastScope(identSymbol);
+                storeFastScopeVar(identSymbol, flags);
+            }
             return false;
         }
 
         enterStatement(varNode);
-
-        final IdentNode identNode = varNode.getName();
-        final Symbol identSymbol = identNode.getSymbol();
-        assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
-
         assert method != null;
 
-        final boolean needsScope = identSymbol.isScope();
         if (needsScope) {
             method.loadCompilerConstant(SCOPE);
         }
 
         if (needsScope) {
             loadExpressionUnbounded(init);
-            final int flags = CALLSITE_SCOPE | getCallSiteFlags();
+            // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
+            final int flags = CALLSITE_SCOPE | getCallSiteFlags() | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
             if (isFastScope(identSymbol)) {
                 storeFastScopeVar(identSymbol, flags);
             } else {
@@ -4343,6 +4361,9 @@
         protected abstract void evaluate();
 
         void store() {
+            if (target instanceof IdentNode) {
+                checkTemporalDeadZone((IdentNode)target);
+            }
             prologue();
             evaluate(); // leaves an operation of whatever the operationType was on the stack
             storeNonDiscard();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Thu Sep 04 15:37:14 2014 +0200
@@ -59,7 +59,9 @@
 import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
 import jdk.nashorn.internal.runtime.CodeInstaller;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.FunctionInitializer;
+import jdk.nashorn.internal.runtime.ParserException;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -89,6 +91,8 @@
 
     private final String sourceName;
 
+    private final ErrorManager errors;
+
     private final boolean optimistic;
 
     private final Map<String, byte[]> bytecode;
@@ -311,6 +315,7 @@
      * @param env       script environment
      * @param installer code installer
      * @param source    source to compile
+     * @param errors    error manager
      * @param isStrict  is this a strict compilation
      */
     public Compiler(
@@ -318,8 +323,9 @@
             final ScriptEnvironment env,
             final CodeInstaller<ScriptEnvironment> installer,
             final Source source,
+            final ErrorManager errors,
             final boolean isStrict) {
-        this(context, env, installer, source, isStrict, false, null, null, null, null, null, null);
+        this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null);
     }
 
     /**
@@ -329,6 +335,7 @@
      * @param env                      script environment
      * @param installer                code installer
      * @param source                   source to compile
+     * @param errors                   error manager
      * @param isStrict                 is this a strict compilation
      * @param isOnDemand               is this an on demand compilation
      * @param compiledFunction         compiled function, if any
@@ -343,6 +350,7 @@
             final ScriptEnvironment env,
             final CodeInstaller<ScriptEnvironment> installer,
             final Source source,
+            final ErrorManager errors,
             final boolean isStrict,
             final boolean isOnDemand,
             final RecompilableScriptFunctionData compiledFunction,
@@ -359,6 +367,7 @@
         this.bytecode                 = new LinkedHashMap<>();
         this.log                      = initLogger(context);
         this.source                   = source;
+        this.errors                   = errors;
         this.sourceName               = FunctionNode.getSourceName(source);
         this.onDemand                 = isOnDemand;
         this.compiledFunction         = compiledFunction;
@@ -524,7 +533,17 @@
 
         for (final CompilationPhase phase : phases) {
             log.fine(phase, " starting for ", quote(name));
-            newFunctionNode = phase.apply(this, phases, newFunctionNode);
+
+            try {
+                newFunctionNode = phase.apply(this, phases, newFunctionNode);
+            } catch (final ParserException error) {
+                errors.error(error);
+                if (env._dump_on_error) {
+                    error.printStackTrace(env.getErr());
+                }
+                return null;
+            }
+
             log.fine(phase, " done for function ", quote(name));
 
             if (env._print_mem_usage) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Thu Sep 04 15:37:14 2014 +0200
@@ -69,9 +69,7 @@
      * Constructor
      *
      * @param codegen  code generator
-     * @param keys     keys for fields in object
-     * @param symbols  symbols for fields in object
-     * @param values   list of values corresponding to keys
+     * @param tuples   tuples for fields in object
      */
     FieldObjectCreator(final CodeGenerator codegen, final List<MapTuple<T>> tuples) {
         this(codegen, tuples, false, false);
@@ -81,9 +79,7 @@
      * Constructor
      *
      * @param codegen      code generator
-     * @param keys         keys for fields in object
-     * @param symbols      symbols for fields in object
-     * @param values       values (or null where no value) to be written to the fields
+     * @param tuples       tuples for fields in object
      * @param isScope      is this a scope object
      * @param hasArguments does the created object have an "arguments" property
      */
@@ -165,7 +161,7 @@
      * @param method      Script method.
      * @param key         Property key.
      * @param fieldIndex  Field number.
-     * @param value       Value to store.
+     * @param tuple       Tuple to store.
      */
     private void putField(final MethodEmitter method, final String key, final int fieldIndex, final MapTuple<T> tuple) {
         method.dup();
@@ -188,7 +184,7 @@
      *
      * @param method Script method.
      * @param index  Slot index.
-     * @param value  Value to store.
+     * @param tuple  Tuple to store.
      */
     private void putSlot(final MethodEmitter method, final long index, final MapTuple<T> tuple) {
         method.dup();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MapCreator.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MapCreator.java	Thu Sep 04 15:37:14 2014 +0200
@@ -52,8 +52,7 @@
      * Constructor
      *
      * @param structure structure to generate map for (a JO subclass)
-     * @param keys      list of keys for map
-     * @param symbols   list of symbols for map
+     * @param tuples    list of tuples for map
      */
     MapCreator(final Class<? extends ScriptObject> structure, final List<MapTuple<T>> tuples) {
         this.structure = structure;
@@ -149,6 +148,15 @@
             flags |= Property.IS_FUNCTION_DECLARATION;
         }
 
+        if (symbol.isConst()) {
+            flags |= Property.NOT_WRITABLE;
+        }
+
+        // Mark symbol as needing declaration. Access before declaration will throw a ReferenceError.
+        if (symbol.isBlockScoped() && symbol.isScope()) {
+            flags |= Property.NEEDS_DECLARATION;
+        }
+
         return flags;
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Sep 04 15:37:14 2014 +0200
@@ -2233,9 +2233,8 @@
     /**
      * Generate dynamic setter. Pop receiver and property from stack.
      *
-     * @param valueType the type of the value to set
-     * @param name      name of property
-     * @param flags     call site flags
+     * @param name  name of property
+     * @param flags call site flags
      */
      void dynamicSet(final String name, final int flags) {
          assert !isOptimistic(flags);
@@ -2462,7 +2461,6 @@
      * Register line number at a label
      *
      * @param line  line number
-     * @param label label
      */
     void lineNumber(final int line) {
         if (context.getEnv()._debug_lines) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java	Thu Sep 04 15:37:14 2014 +0200
@@ -108,7 +108,7 @@
 
         // Safely evaluate the property, and return the narrowest type for the actual value (e.g. Type.INT for a boxed
         // integer).
-        final Object value = property.getObjectValue(owner, owner);
+        final Object value = property.needsDeclaration() ? ScriptRuntime.UNDEFINED : property.getObjectValue(owner, owner);
         if (value == ScriptRuntime.UNDEFINED) {
             return null;
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Thu Sep 04 15:37:14 2014 +0200
@@ -138,10 +138,6 @@
     /** Last token of function. **/
     private final long lastToken;
 
-    /** Declared symbols in this function node */
-    @Ignore
-    private final Set<Symbol> declaredSymbols;
-
     /** Method's namespace. */
     private final Namespace namespace;
 
@@ -330,7 +326,6 @@
         this.lastToken        = token;
         this.namespace        = namespace;
         this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
-        this.declaredSymbols  = new HashSet<>();
         this.flags            = flags;
         this.compileUnit      = null;
         this.body             = null;
@@ -369,7 +364,6 @@
         this.id              = functionNode.id;
         this.ident           = functionNode.ident;
         this.namespace       = functionNode.namespace;
-        this.declaredSymbols = functionNode.declaredSymbols;
         this.kind            = functionNode.kind;
         this.firstToken      = functionNode.firstToken;
     }
@@ -724,24 +718,6 @@
     }
 
     /**
-     * Return a set of symbols declared in this function node. This
-     * is only relevant after Attr, otherwise it will be an empty
-     * set as no symbols have been introduced
-     * @return set of declared symbols in function
-     */
-    public Set<Symbol> getDeclaredSymbols() {
-        return Collections.unmodifiableSet(declaredSymbols);
-    }
-
-    /**
-     * Add a declared symbol to this function node
-     * @param symbol symbol that is declared
-     */
-    public void addDeclaredSymbol(final Symbol symbol) {
-        declaredSymbols.add(symbol);
-    }
-
-    /**
      * Get the function body
      * @return the function body
      */
@@ -970,13 +946,13 @@
     }
 
     /**
-     * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
+     * Check if this function should have all its variables in its own scope. Split sub-functions, and
      * functions having with and/or eval blocks are such.
      *
      * @return true if all variables should be in scope
      */
     public boolean allVarsInScope() {
-        return isProgram() || getFlag(HAS_ALL_VARS_IN_SCOPE);
+        return getFlag(HAS_ALL_VARS_IN_SCOPE);
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Thu Sep 04 15:37:14 2014 +0200
@@ -46,6 +46,8 @@
     private static final int INITIALIZED_HERE  = 1 << 1;
     private static final int FUNCTION          = 1 << 2;
     private static final int FUTURESTRICT_NAME = 1 << 3;
+    private static final int IS_DECLARED_HERE  = 1 << 4;
+    private static final int IS_DEAD           = 1 << 5;
 
     /** Identifier. */
     private final String name;
@@ -247,6 +249,45 @@
     }
 
     /**
+     * Is this a LET or CONST identifier used before its declaration?
+     *
+     * @return true if identifier is dead
+     */
+    public boolean isDead() {
+        return (flags & IS_DEAD) != 0;
+    }
+
+    /**
+     * Flag this IdentNode as a LET or CONST identifier used before its declaration.
+     *
+     * @return a new IdentNode equivalent to this but marked as dead.
+     */
+    public IdentNode markDead() {
+        return new IdentNode(this, name, type, flags | IS_DEAD, programPoint, conversion);
+    }
+
+    /**
+     * Is this IdentNode declared here?
+     *
+     * @return true if identifier is declared here
+     */
+    public boolean isDeclaredHere() {
+        return (flags & IS_DECLARED_HERE) != 0;
+    }
+
+    /**
+     * Flag this IdentNode as being declared here.
+     *
+     * @return a new IdentNode equivalent to this but marked as declared here.
+     */
+    public IdentNode setIsDeclaredHere() {
+        if (isDeclaredHere()) {
+            return this;
+        }
+        return new IdentNode(this, name, type, flags | IS_DECLARED_HERE, programPoint, conversion);
+    }
+
+    /**
      * Check if the name of this IdentNode is same as that of a compile-time property (currently __DIR__, __FILE__, and
      * __LINE__).
      *
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java	Thu Sep 04 15:37:14 2014 +0200
@@ -54,17 +54,17 @@
     public static final int IS_VAR      = 2;
     /** Is this a parameter */
     public static final int IS_PARAM    = 3;
-    /** Is this a constant */
-    public static final int IS_CONSTANT = 4;
     /** Mask for kind flags */
-    public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits
+    public static final int KINDMASK = (1 << 2) - 1; // Kinds are represented by lower two bits
 
     /** Is this symbol in scope */
-    public static final int IS_SCOPE                = 1 <<  3;
+    public static final int IS_SCOPE                = 1 <<  2;
     /** Is this a this symbol */
-    public static final int IS_THIS                 = 1 <<  4;
+    public static final int IS_THIS                 = 1 <<  3;
     /** Is this a let */
-    public static final int IS_LET                  = 1 <<  5;
+    public static final int IS_LET                  = 1 <<  4;
+    /** Is this a const */
+    public static final int IS_CONST                = 1 <<  5;
     /** Is this an internal symbol, never represented explicitly in source code */
     public static final int IS_INTERNAL             = 1 <<  6;
     /** Is this a function self-reference symbol */
@@ -83,6 +83,8 @@
     public static final int HAS_DOUBLE_VALUE        = 1 << 13;
     /** Is this symbol known to store an object value ? */
     public static final int HAS_OBJECT_VALUE        = 1 << 14;
+    /** Is this symbol seen a declaration? Used for block scoped LET and CONST symbols only. */
+    public static final int HAS_BEEN_DECLARED       = 1 << 15;
 
     /** Null or name identifying symbol. */
     private final String name;
@@ -184,14 +186,17 @@
             sb.append(" global");
             break;
         case IS_VAR:
-            sb.append(" var");
+            if (isConst()) {
+                sb.append(" const");
+            } else if (isLet()) {
+                sb.append(" let");
+            } else {
+                sb.append(" var");
+            }
             break;
         case IS_PARAM:
             sb.append(" param");
             break;
-        case IS_CONSTANT:
-            sb.append(" const");
-            break;
         default:
             break;
         }
@@ -204,10 +209,6 @@
             sb.append(" internal");
         }
 
-        if (isLet()) {
-            sb.append(" let");
-        }
-
         if (isThis()) {
             sb.append(" this");
         }
@@ -410,8 +411,8 @@
      * Check if this symbol is a constant
      * @return true if a constant
      */
-    public boolean isConstant() {
-        return (flags & KINDMASK) == IS_CONSTANT;
+    public boolean isConst() {
+        return (flags & IS_CONST) != 0;
     }
 
     /**
@@ -440,15 +441,6 @@
     }
 
     /**
-     * Flag this symbol as a let
-     */
-    public void setIsLet() {
-        if (!isLet()) {
-            flags |= IS_LET;
-        }
-    }
-
-    /**
      * Flag this symbol as a function's self-referencing symbol.
      * @return true if this symbol as a function's self-referencing symbol.
      */
@@ -456,6 +448,20 @@
         return (flags & IS_FUNCTION_SELF) != 0;
     }
 
+    public boolean isBlockScoped() {
+        return isLet() || isConst();
+    }
+
+    public boolean hasBeenDeclared() {
+        return (flags & HAS_BEEN_DECLARED) != 0;
+    }
+
+    public void setHasBeenDeclared() {
+        if (!hasBeenDeclared()) {
+            flags |= HAS_BEEN_DECLARED;
+        }
+    }
+
     /**
      * Get the index of the field used to store this symbol, should it be an AccessorProperty
      * and get allocated in a JO-prefixed ScriptObject subclass.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java	Thu Sep 04 15:37:14 2014 +0200
@@ -27,6 +27,7 @@
 
 import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.parser.Token;
 
 /**
  * Node represents a var/let declaration.
@@ -43,12 +44,18 @@
     private final int flags;
 
     /** Flag that determines if this function node is a statement */
-    public static final int IS_STATEMENT = 1 << 0;
+    public static final int IS_STATEMENT                 = 1 << 0;
+
+    /** Flag for ES6 LET declaration */
+    public static final int IS_LET                       = 1 << 1;
+
+    /** Flag for ES6 CONST declaration */
+    public static final int IS_CONST                     = 1 << 2;
 
     /** Flag that determines if this is the last function declaration in a function
      *  This is used to micro optimize the placement of return value assignments for
      *  a program node */
-    public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 1;
+    public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3;
 
     /**
      * Constructor
@@ -109,6 +116,43 @@
     }
 
     /**
+     * Is this a VAR node block scoped? This returns true for ECMAScript 6 LET and CONST nodes.
+     * @return true if an ES6 LET or CONST node
+     */
+    public boolean isBlockScoped() {
+        return getFlag(IS_LET) || getFlag(IS_CONST);
+    }
+
+    /**
+     * Is this an ECMAScript 6 LET node?
+     * @return true if LET node
+     */
+    public boolean isLet() {
+        return getFlag(IS_LET);
+    }
+
+    /**
+     * Is this an ECMAScript 6 CONST node?
+     * @return true if CONST node
+     */
+    public boolean isConst() {
+        return getFlag(IS_CONST);
+    }
+
+    /**
+     * Return the flags to use for symbols for this declaration.
+     * @return the symbol flags
+     */
+    public int getSymbolFlags() {
+        if (isLet()) {
+            return Symbol.IS_VAR | Symbol.IS_LET;
+        } else if (isConst()) {
+            return Symbol.IS_VAR | Symbol.IS_CONST;
+        }
+        return Symbol.IS_VAR;
+    }
+
+    /**
      * Does this variable declaration have an init value
      * @return true if an init exists, false otherwise
      */
@@ -139,7 +183,7 @@
 
     @Override
     public void toString(final StringBuilder sb, final boolean printType) {
-        sb.append("var ");
+        sb.append(Token.descType(getToken()).getName()).append(' ');
         name.toString(sb, printType);
 
         if (init != null) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Thu Sep 04 15:37:14 2014 +0200
@@ -45,6 +45,7 @@
 import static jdk.nashorn.internal.parser.TokenType.IF;
 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
+import static jdk.nashorn.internal.parser.TokenType.LET;
 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
@@ -579,6 +580,10 @@
         }
     }
 
+    private boolean useBlockScope() {
+        return env._es6;
+    }
+
     private static boolean isArguments(final String name) {
         return ARGUMENTS_NAME.equals(name);
     }
@@ -694,9 +699,20 @@
             FunctionNode.Kind.SCRIPT,
             functionLine);
 
+        // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
+        final int startLine = start;
+        Block outer = useBlockScope() ? newBlock() : null;
         functionDeclarations = new ArrayList<>();
-        sourceElements(allowPropertyFunction);
-        addFunctionDeclarations(script);
+
+        try {
+            sourceElements(allowPropertyFunction);
+            addFunctionDeclarations(script);
+        } finally {
+            if (outer != null) {
+                outer = restoreBlock(outer);
+                appendStatement(new BlockStatement(startLine, outer));
+            }
+        }
         functionDeclarations = null;
 
         expect(EOF);
@@ -868,7 +884,7 @@
             block();
             break;
         case VAR:
-            variableStatement(true);
+            variableStatement(type, true);
             break;
         case SEMICOLON:
             emptyStatement();
@@ -918,8 +934,12 @@
             expect(SEMICOLON);
             break;
         default:
+            if (useBlockScope() && (type == LET || type == CONST)) {
+                variableStatement(type, true);
+                break;
+            }
             if (env._const_as_var && type == CONST) {
-                variableStatement(true);
+                variableStatement(TokenType.VAR, true);
                 break;
             }
 
@@ -1035,11 +1055,17 @@
      * Parse a VAR statement.
      * @param isStatement True if a statement (not used in a FOR.)
      */
-    private List<VarNode> variableStatement(final boolean isStatement) {
+    private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) {
         // VAR tested in caller.
         next();
 
         final List<VarNode> vars = new ArrayList<>();
+        int varFlags = VarNode.IS_STATEMENT;
+        if (varType == LET) {
+            varFlags |= VarNode.IS_LET;
+        } else if (varType == CONST) {
+            varFlags |= VarNode.IS_CONST;
+        }
 
         while (true) {
             // Get starting token.
@@ -1063,10 +1089,12 @@
                 } finally {
                     defaultNames.pop();
                 }
+            } else if (varType == CONST) {
+                throw error(AbstractParser.message("missing.const.assignment", name.getName()));
             }
 
             // Allocate var node.
-            final VarNode var = new VarNode(varLine, varToken, finish, name, init);
+            final VarNode var = new VarNode(varLine, varToken, finish, name.setIsDeclaredHere(), init, varFlags);
             vars.add(var);
             appendStatement(var);
 
@@ -1180,9 +1208,12 @@
      * Parse a FOR statement.
      */
     private void forStatement() {
+        // When ES6 for-let is enabled we create a container block to capture the LET.
+        final int startLine = start;
+        Block outer = useBlockScope() ? newBlock() : null;
+
         // Create FOR node, capturing FOR token.
         ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
-
         lc.push(forNode);
 
         try {
@@ -1203,14 +1234,19 @@
             switch (type) {
             case VAR:
                 // Var statements captured in for outer block.
-                vars = variableStatement(false);
+                vars = variableStatement(type, false);
                 break;
             case SEMICOLON:
                 break;
             default:
+                if (useBlockScope() && (type == LET || type == CONST)) {
+                    // LET/CONST captured in container block created above.
+                    vars = variableStatement(type, false);
+                    break;
+                }
                 if (env._const_as_var && type == CONST) {
                     // Var statements captured in for outer block.
-                    vars = variableStatement(false);
+                    vars = variableStatement(TokenType.VAR, false);
                     break;
                 }
 
@@ -1290,8 +1326,13 @@
             appendStatement(forNode);
         } finally {
             lc.pop(forNode);
+            if (outer != null) {
+                outer.setFinish(forNode.getFinish());
+                outer = restoreBlock(outer);
+                appendStatement(new BlockStatement(startLine, outer));
+            }
         }
-     }
+    }
 
     /**
      * ... IterationStatement :
@@ -1722,7 +1763,7 @@
         }
     }
 
-   /**
+    /**
      * ThrowStatement :
      *      throw Expression ; // [no LineTerminator here]
      *
@@ -2609,7 +2650,7 @@
         FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
 
         if (isStatement) {
-            if (topLevel) {
+            if (topLevel || useBlockScope()) {
                 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
             } else if (isStrictMode) {
                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
@@ -2661,9 +2702,16 @@
         }
 
         if (isStatement) {
-            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
+            int varFlags = VarNode.IS_STATEMENT;
+            if (!topLevel && useBlockScope()) {
+                // mark ES6 block functions as lexically scoped
+                varFlags |= VarNode.IS_LET;
+            }
+            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
             if (topLevel) {
                 functionDeclarations.add(varNode);
+            } else if (useBlockScope()) {
+                prependStatement(varNode); // Hoist to beginning of current block
             } else {
                 appendStatement(varNode);
             }
@@ -2838,7 +2886,6 @@
     }
 
     private void addFunctionDeclarations(final FunctionNode functionNode) {
-        assert lc.peek() == lc.getFunctionBody(functionNode);
         VarNode lastDecl = null;
         for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
             Statement decl = functionDeclarations.get(i);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Sep 04 15:37:14 2014 +0200
@@ -549,6 +549,8 @@
                 type == Object.class :
                 "invalid getter type " + type + " for " + getKey();
 
+        checkUndeclared();
+
         //all this does is add a return value filter for object fields only
         final MethodHandle[] getterCache = GETTER_CACHE;
         final MethodHandle cachedGetter = getterCache[i];
@@ -579,6 +581,8 @@
             return getOptimisticPrimitiveGetter(type, programPoint);
         }
 
+        checkUndeclared();
+
         return debug(
             createGetter(
                 getCurrentType(),
@@ -608,6 +612,13 @@
         return newMap;
     }
 
+    private void checkUndeclared() {
+        if ((getFlags() & NEEDS_DECLARATION) != 0) {
+            // a lexically defined variable that hasn't seen its declaration - throw ReferenceError
+            throw ECMAErrors.referenceError("not.defined", getKey());
+        }
+    }
+
     // the final three arguments are for debug printout purposes only
     @SuppressWarnings("unused")
     private static Object replaceMap(final Object sobj, final PropertyMap newMap) {
@@ -635,13 +646,14 @@
 
     @Override
     public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
-        final int      i       = getAccessorTypeIndex(type);
-        final int      ci      = isUndefined() ? -1 : getAccessorTypeIndex(getCurrentType());
-        final Class<?> forType = isUndefined() ? type : getCurrentType();
+        checkUndeclared();
+
+        final int typeIndex        = getAccessorTypeIndex(type);
+        final int currentTypeIndex = getAccessorTypeIndex(getCurrentType());
 
         //if we are asking for an object setter, but are still a primitive type, we might try to box it
         MethodHandle mh;
-        if (needsInvalidator(i, ci)) {
+        if (needsInvalidator(typeIndex, currentTypeIndex)) {
             final Property     newProperty = getWiderProperty(type);
             final PropertyMap  newMap      = getWiderMap(currentMap, newProperty);
 
@@ -652,6 +664,7 @@
                  mh = ObjectClassGenerator.createGuardBoxedPrimitiveSetter(ct, generateSetter(ct, ct), mh);
             }
         } else {
+            final Class<?> forType = isUndefined() ? type : getCurrentType();
             mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
         }
 
@@ -692,11 +705,12 @@
         if (OBJECT_FIELDS_ONLY) {
             return false;
         }
-        return getCurrentType() != Object.class && (isConfigurable() || isWritable());
+        // Return true for currently undefined even if non-writable/configurable to allow initialization of ES6 CONST.
+        return getCurrentType() == null || (getCurrentType() != Object.class && (isConfigurable() || isWritable()));
     }
 
-    private boolean needsInvalidator(final int ti, final int fti) {
-        return canChangeType() && ti > fti;
+    private boolean needsInvalidator(final int typeIndex, final int currentTypeIndex) {
+        return canChangeType() && typeIndex > currentTypeIndex;
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Thu Sep 04 15:37:14 2014 +0200
@@ -1132,7 +1132,7 @@
         if (storedScript == null) {
             functionNode = new Parser(env, source, errMan, strict, getLogger(Parser.class)).parse();
 
-            if (errors.hasErrors()) {
+            if (errMan.hasErrors()) {
                 return null;
             }
 
@@ -1162,9 +1162,13 @@
                     env,
                     installer,
                     source,
+                    errMan,
                     strict | functionNode.isStrict());
 
             final FunctionNode compiledFunction = compiler.compile(functionNode, phases);
+            if (errMan.hasErrors()) {
+                return null;
+            }
             script = compiledFunction.getRootClass();
             compiler.persistClassInfo(cacheKey, compiledFunction);
         } else {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java	Thu Sep 04 15:37:14 2014 +0200
@@ -58,6 +58,18 @@
     }
 
     /**
+     * Return a copy of this FindProperty with a different property.
+     *
+     * @param newProperty the new property
+     * @return the new FindProperty instance
+     */
+    public FindProperty replaceProperty(final Property newProperty) {
+        assert this.property.getKey().equals(newProperty.getKey());
+        assert this.property.getSlot() == newProperty.getSlot();
+        return new FindProperty(self, prototype, newProperty);
+    }
+
+    /**
      * Ask for a getter that returns the given type. The type has nothing to do with the
      * internal representation of the property. It may be an Object (boxing primitives) or
      * a primitive (primitive fields with -Dnashorn.fields.dual=true)
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java	Thu Sep 04 15:37:14 2014 +0200
@@ -82,11 +82,14 @@
      * is narrower than object, e.g. Math.PI which is declared
      * as a double
      */
-    public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
+    public static final int IS_NASGEN_PRIMITIVE     = 1 << 6;
 
     /** Is this property bound to a receiver? This means get/set operations will be delegated to
      *  a statically defined object instead of the object passed as callsite parameter. */
-    public static final int IS_BOUND = 1 << 8;
+    public static final int IS_BOUND                = 1 << 7;
+
+    /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */
+    public static final int NEEDS_DECLARATION       = 1 << 8;
 
     /** Property key. */
     private final String key;
@@ -287,6 +290,15 @@
     }
 
     /**
+     * Is this a LET or CONST property that needs to see its declaration before being usable?
+     *
+     * @return true if this is a block-scoped variable
+     */
+    public boolean needsDeclaration() {
+        return (flags & NEEDS_DECLARATION) == NEEDS_DECLARATION;
+    }
+
+    /**
      * Add more property flags to the property. Properties are immutable here,
      * so any property change that results in a larger flag set results in the
      * property being cloned. Use only the return value
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Sep 04 15:37:14 2014 +0200
@@ -394,6 +394,7 @@
                 context.getEnv(),
                 installer,
                 functionNode.getSource(),  // source
+                context.getErrorManager(),
                 isStrict() | functionNode.isStrict(), // is strict
                 true,       // is on demand
                 this,       // compiledFunction, i.e. this RecompilableScriptFunctionData
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu Sep 04 15:37:14 2014 +0200
@@ -94,6 +94,9 @@
     /** Use single Global instance per jsr223 engine instance. */
     public final boolean _global_per_engine;
 
+    /** Enable experimental ECMAScript 6 features. */
+    public final boolean _es6;
+
     /** Argument passed to compile only if optimistic compilation should take place */
     public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic";
 
@@ -258,6 +261,15 @@
         _version              = options.getBoolean("version");
         _verify_code          = options.getBoolean("verify.code");
 
+        final String language = options.getString("language");
+        if (language == null || language.equals("es5")) {
+            _es6 = false;
+        } else if (language.equals("es6")) {
+            _es6 = true;
+        } else {
+            throw new RuntimeException("Unsupported language: " + language);
+        }
+
         String dir = null;
         String func = null;
         final String pc = options.getString("print.code");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Sep 04 15:37:14 2014 +0200
@@ -158,6 +158,7 @@
 
     static final MethodHandle MEGAMORPHIC_GET    = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class);
     static final MethodHandle GLOBALFILTER       = findOwnMH_S("globalFilter", Object.class, Object.class);
+    static final MethodHandle DECLARE_AND_SET    = findOwnMH_V("declareAndSet", void.class, String.class, Object.class);
 
     private static final MethodHandle TRUNCATINGFILTER   = findOwnMH_S("truncatingFilter", Object[].class, int.class, Object[].class);
     private static final MethodHandle KNOWNFUNCPROPGUARDSELF = findOwnMH_S("knownFunctionPropertyGuardSelf", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, ScriptFunction.class);
@@ -2027,6 +2028,22 @@
         return isMethod ? getNoSuchMethod(key, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
     }
 
+    // Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
+    @SuppressWarnings("unused")
+    private void declareAndSet(final String key, final Object value) {
+        final PropertyMap map = getMap();
+        final FindProperty find = findProperty(key, false);
+        assert find != null;
+
+        final Property property = find.getProperty();
+        assert property != null;
+        assert property.needsDeclaration();
+
+        final PropertyMap newMap = map.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
+        setMap(newMap);
+        set(key, value, true);
+    }
+
     /**
      * Find the appropriate GETINDEX method for an invoke dynamic call.
      *
@@ -2140,7 +2157,7 @@
         }
 
         if (find != null) {
-            if (!find.getProperty().isWritable()) {
+            if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
                 // Existing, non-writable property
                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
             }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Sep 04 15:37:14 2014 +0200
@@ -108,6 +108,11 @@
     public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class);
 
     /**
+     * Throws a reference error for an undefined variable.
+     */
+    public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
+
+    /**
      * Converts a switch tag value to a simple integer. deflt value if it can't.
      *
      * @param tag   Switch statement tag value.
@@ -382,6 +387,15 @@
     }
 
     /**
+     * Throws a reference error for an undefined variable.
+     *
+     * @param name the variable name
+     */
+    public static void throwReferenceError(final String name) {
+        throw referenceError("not.defined", name);
+    }
+
+    /**
      * Call a script function as a constructor with given args.
      *
      * @param target ScriptFunction object.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java	Thu Sep 04 15:37:14 2014 +0200
@@ -140,7 +140,29 @@
 
     private SetMethod createExistingPropertySetter() {
         final Property property = find.getProperty();
-        final MethodHandle methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+        final MethodHandle methodHandle;
+
+        if (NashornCallSiteDescriptor.isDeclaration(desc)) {
+            assert property.needsDeclaration();
+            // This is a LET or CONST being declared. The property is already there but flagged as needing declaration.
+            // We create a new PropertyMap with the flag removed. The map is installed with a fast compare-and-set
+            // method if the pre-callsite map is stable (which should be the case for function scopes except for
+            // non-strict functions containing eval() with var). Otherwise we have to use a slow setter that creates
+            // a new PropertyMap on the fly.
+            final PropertyMap oldMap = getMap();
+            final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION);
+            final PropertyMap newMap = oldMap.replaceProperty(property, newProperty);
+            final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+            final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type());
+
+            // cas map used as guard, if true that means we can do the set fast
+            MethodHandle casMap = MH.insertArguments(ScriptObject.CAS_MAP, 1, oldMap, newMap);
+            casMap = MH.dropArguments(casMap, 1, type);
+            casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
+            methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter);
+        } else {
+            methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+        }
 
         assert methodHandle != null;
         assert property     != null;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Thu Sep 04 15:37:14 2014 +0200
@@ -54,23 +54,25 @@
     public static final int CALLSITE_OPTIMISTIC    = 1 << 3;
     /** Is this really an apply that we try to call as a call? */
     public static final int CALLSITE_APPLY_TO_CALL = 1 << 4;
+    /** Does this a callsite for a variable declaration? */
+    public static final int CALLSITE_DECLARE       = 1 << 5;
 
     /** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
      * code where call sites have this flag set. */
-    public static final int CALLSITE_PROFILE        = 1 << 5;
+    public static final int CALLSITE_PROFILE         = 1 << 6;
     /** Flags that the call site is traced; Contexts that have {@code "trace.callsites"} property set emit code where
      * call sites have this flag set. */
-    public static final int CALLSITE_TRACE          = 1 << 6;
+    public static final int CALLSITE_TRACE           = 1 << 7;
     /** Flags that the call site linkage miss (and thus, relinking) is traced; Contexts that have the keyword
      * {@code "miss"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
-    public static final int CALLSITE_TRACE_MISSES   = 1 << 7;
+    public static final int CALLSITE_TRACE_MISSES    = 1 << 8;
     /** Flags that entry/exit to/from the method linked at call site are traced; Contexts that have the keyword
      * {@code "enterexit"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
-    public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 8;
+    public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 9;
     /** Flags that values passed as arguments to and returned from the method linked at call site are traced; Contexts
      * that have the keyword {@code "values"} in their {@code "trace.callsites"} property emit code where call sites
      * have this flag set. */
-    public static final int CALLSITE_TRACE_VALUES   = 1 << 9;
+    public static final int CALLSITE_TRACE_VALUES    = 1 << 10;
 
     //we could have more tracing flags here, for example CALLSITE_TRACE_SCOPE, but bits are a bit precious
     //right now given the program points
@@ -82,10 +84,10 @@
      * TODO: rethink if we need the various profile/trace flags or the linker can use the Context instead to query its
      * trace/profile settings.
      */
-    public static final int CALLSITE_PROGRAM_POINT_SHIFT = 10;
+    public static final int CALLSITE_PROGRAM_POINT_SHIFT = 11;
 
     /**
-     * Maximum program point value. 22 bits should be enough for anyone
+     * Maximum program point value. 21 bits should be enough for anyone
      */
     public static final int MAX_PROGRAM_POINT_VALUE = (1 << 32 - CALLSITE_PROGRAM_POINT_SHIFT) - 1;
 
@@ -123,6 +125,9 @@
                 assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
                 sb.append("scope ");
             }
+            if ((flags & CALLSITE_DECLARE) != 0) {
+                sb.append("declare ");
+            }
         }
         if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
             sb.append("apply2call ");
@@ -329,6 +334,15 @@
     }
 
     /**
+     * Does this callsite contain a declaration for its target?
+     * @param desc descriptor
+     * @return true if contains declaration
+     */
+    public static boolean isDeclaration(final CallSiteDescriptor desc) {
+        return isFlag(desc, CALLSITE_DECLARE);
+    }
+
+    /**
      * Get a program point from a descriptor (must be optimistic)
      * @param desc descriptor
      * @return program point
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Sep 04 15:37:14 2014 +0200
@@ -58,6 +58,7 @@
 parser.error.regex.repeated.flag=Repeated RegExp flag: {0}
 parser.error.regex.syntax={0}
 parser.error.trailing.comma.in.json=Trailing comma is not allowed in JSON
+parser.error.missing.const.assignment=Missing assignment to constant "{0}"
 
 # strict mode error messages
 parser.error.strict.no.with="with" statement cannot be used in strict mode
@@ -162,6 +163,8 @@
 
 syntax.error.invalid.json=Invalid JSON: {0}
 syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
+syntax.error.redeclare.variable=Variable "{0}" has already been declared
+syntax.error.assign.constant=Assignment to constant "{0}"
 
 io.error.cant.write=cannot write "{0}"
 config.error.no.dest=no destination directory supplied
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties	Thu Sep 04 15:37:14 2014 +0200
@@ -329,6 +329,14 @@
     desc="Enable scripting features."   \
 }
 
+nashorn.option.language = {                      \
+    name="--language",                           \
+    type=String,                                 \
+    params=[es5|es6],                            \
+    default=es5,                                 \
+    desc="Specify ECMAScript language version."  \
+}
+
 nashorn.option.stdout = {                                                \
     name="--stdout",                                                     \
     is_undocumented=true,                                                \
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Thu Sep 04 15:37:14 2014 +0200
@@ -252,6 +252,15 @@
                     return COMPILATION_ERROR;
                 }
 
+                new Compiler(
+                       context,
+                       env,
+                       null, //null - pass no code installer - this is compile only
+                       functionNode.getSource(),
+                       context.getErrorManager(),
+                       env._strict | functionNode.isStrict()).
+                       compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
+
                 if (env._print_ast) {
                     context.getErr().println(new ASTWriter(functionNode));
                 }
@@ -260,14 +269,9 @@
                     context.getErr().println(new PrintVisitor(functionNode));
                 }
 
-                //null - pass no code installer - this is compile only
-                new Compiler(
-                       context,
-                       env,
-                       null,
-                       functionNode.getSource(),
-                       env._strict | functionNode.isStrict()).
-                       compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
+                if (errors.getNumberOfErrors() != 0) {
+                    return COMPILATION_ERROR;
+                }
             }
         } finally {
             env.getOut().flush();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/block-function-decl.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+"use strict";
+
+{
+    // f is defined on block level
+    print(f);
+    f();
+    function f() {
+        print("in f");
+    }
+    print(f);
+    f();
+}
+
+try {
+    print(typeof f);
+    f();
+} catch (e) {
+    print(e);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/block-function-decl.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,10 @@
+function f() {
+        print("in f");
+    }
+in f
+function f() {
+        print("in f");
+    }
+in f
+undefined
+ReferenceError: "f" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-empty.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+    eval('"use strict";\n' +
+        'const x;\n');
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-empty.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,3 @@
+SyntaxError: test/script/basic/es6/const-empty.js#33:4<eval>@1:2:7 Missing assignment to constant "x"
+const x;
+       ^
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-reassign.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x = 1;\n');
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x++;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x--;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        '++x;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        '--x;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x += 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x *= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x /= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x %= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x |= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x &= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x ^= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x <<= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x >>= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'x >>>= 1;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
+
+try {
+    eval('"use strict";\n' +
+        'const x = 2;\n' +
+        'delete x;\n');
+    fail("const assignment didn't throw");
+} catch (e) {
+    print(e.name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-reassign.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,16 @@
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
+SyntaxError
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-redeclare.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+    eval('"use strict";\n' +
+         'const x = 2;\n' +
+         'const x = 2;\n');
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,3 @@
+SyntaxError: test/script/basic/es6/const-redeclare.js#33:4<eval>@1:2:6 Variable "x" has already been declared
+const x = 2;
+      ^
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-self.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+const a = 1, b = a;
+
+print(a, b);
+
+try {
+    eval('"use strict";\n' +
+         'const a = a;\n');
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-self.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,2 @@
+1 1
+ReferenceError: "a" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-tdz.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+{
+    print("test 1");
+
+    function f() {
+        try {
+            print(a);
+        } catch (a) {
+            print(a);
+        }
+    }
+
+    f();
+    const a = 1;
+    f();
+}
+
+{
+    print("test 2");
+
+    function f() {
+        try {
+            print(a);
+        } catch (a) {
+            print(a);
+        }
+    }
+
+    f();
+    const a = 2;
+    f();
+}
+
+{
+    print("test 3");
+    {
+        try {
+            print(a);
+        } catch (a) {
+            print(a);
+        }
+    }
+
+    const a = 3;
+
+    {
+        print(a);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-tdz.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,9 @@
+test 1
+ReferenceError: "a" is not defined
+1
+test 2
+ReferenceError: "a" is not defined
+2
+test 3
+ReferenceError: "a" is not defined
+3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+"use strict";
+
+const a = 2;
+const c = 2;
+print(a, c);
+
+function f(x) {
+    const a = 5;
+    const c = 10;
+    print(a, c);
+    if (x) {
+        const a = 42;
+        const c = 43;
+        print(a, c);
+    }
+    print(a, c);
+
+    function inner() {
+        (function() {
+            print(a, c);
+        })();
+    }
+    inner();
+}
+
+f(true);
+f(false);
+
+(function() {
+    (function() {
+        print(a, c);
+    })();
+})();
+
+function outer() {
+    print(a, c);
+}
+outer();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,10 @@
+2 2
+5 10
+42 43
+5 10
+5 10
+5 10
+5 10
+5 10
+2 2
+2 2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/for-let.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+for (let i = 0; i < 10; i++) {
+    print(i);
+}
+
+try {
+    print(i);
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/for-let.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,11 @@
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+ReferenceError: "i" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-eval.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+function f() {
+    var a;
+    let b;
+    const c = 0;
+
+    print(a, b, c);
+
+    try {
+        eval("x = 1; print('x: ' + x);");
+        print("assignment to x succeeded");
+    } catch (e) {
+        print(e);
+    }
+    try {
+        eval("'use strict'; let z = 1; print('z: ' + z);");
+        print("assignment to z succeeded");
+        eval("print('z: ' + z);");
+    } catch (e) {
+        print(e);
+    }
+
+    try {
+        eval("a = 1; print(a);");
+        print("assignment to a succeeded");
+    } catch (e) {
+        print(e);
+    }
+    print("a: " + a);
+
+    try {
+        eval("b = 1; print('b: ' + b);");
+        print("assignment to b succeeded");
+    } catch (e) {
+        print(e);
+    }
+    print("b: " + b);
+
+    try {
+        eval("c = 1; print('c: ' + c);");
+        print("assignment to c succeeded");
+    } catch (e) {
+        print(e);
+    }
+    print("c: " + c);
+
+    eval("a = 2; let b = 3;");
+
+    try {
+        print(a, b, c);
+    } catch (e) {
+        print(e);
+    }
+
+    let x;
+
+    try {
+        print(a, b, c, x);
+    } catch (e) {
+        print(e);
+    }
+
+}
+
+f();
+
+print(typeof a, typeof b, typeof c, typeof x, typeof z);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-eval.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,16 @@
+undefined undefined 0
+ReferenceError: "x" is not defined
+z: 1
+assignment to z succeeded
+ReferenceError: "z" is not defined
+1
+assignment to a succeeded
+a: 1
+b: 1
+assignment to b succeeded
+b: 1
+TypeError: "c" is not a writable property of [object Object]
+c: 0
+2 1 0
+2 1 0 undefined
+undefined undefined undefined undefined undefined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-load-lib.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @subtest
+ */
+
+"use strict";
+
+// var should be visible in other script, let and const not
+var a = 1;
+let b = 2;
+const c = 3;
+
+// top level function should be visible
+function top() {
+    print("top level function");
+}
+
+// block level function not visible outside script
+{
+    function block() {
+        print("block function");
+    }
+
+    top();
+    block();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-load.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+load(__DIR__ + "let-load-lib.js");
+
+{
+    let a = 20;
+    const c = 30;
+    print("print local defs: " + a, c);
+}
+
+print("imported var: " + a);
+try {
+    print("imported let: " + b);
+} catch (e) {
+    print(e);
+}
+
+try {
+    print("imported const: " + c);
+} catch (e) {
+    print(e);
+}
+
+top();
+
+try {
+    block();
+} catch (e) {
+    print(e);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-load.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,8 @@
+top level function
+block function
+print local defs: 20 30
+imported var: 1
+ReferenceError: "b" is not defined
+ReferenceError: "c" is not defined
+top level function
+ReferenceError: "block" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-nodeclare.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+try {
+    if (true) {
+        let x = 2;
+        print(x);
+    }
+    print(x);
+} catch (e) {
+    print(e);
+}
+
+
+try {
+    if (true) {
+        const x = 2;
+        print(x);
+    }
+    print(x);
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-nodeclare.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,4 @@
+2
+ReferenceError: "x" is not defined
+2
+ReferenceError: "x" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-redeclare.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+    eval('"use strict";\n' +
+         'let x = 2;\n' +
+         'let x = 2;\n');
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,3 @@
+SyntaxError: test/script/basic/es6/let-redeclare.js#33:4<eval>@1:2:4 Variable "x" has already been declared
+let x = 2;
+    ^
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-self.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+let a, b = a;
+
+print(a, b);
+
+try {
+    eval('"use strict";\n' +
+         'let a = a;\n');
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-self.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,2 @@
+undefined undefined
+ReferenceError: "a" is not defined
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-tdz.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+{
+    print("test 1");
+
+    function f() {
+        try {
+            print(a);
+        } catch (a) {
+            print(a);
+        }
+    }
+
+    f();
+    let a = 1;
+    f();
+}
+
+{
+    print("test 2");
+
+    function f() {
+        try {
+            print(a);
+        } catch (a) {
+            print(a);
+        }
+    }
+
+    f();
+    let a = 2;
+    f();
+}
+
+{
+    print("test 3");
+
+    {
+        try {
+            print(a);
+        } catch (a) {
+            print(a);
+        }
+    }
+
+    let a = 3;
+
+    {
+        print(a);
+    }
+}
+
+{
+    print("test 4");
+    let a;
+
+    {
+        print(a);
+    }
+
+    a = 4;
+
+    {
+        print(a);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-tdz.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,12 @@
+test 1
+ReferenceError: "a" is not defined
+1
+test 2
+ReferenceError: "a" is not defined
+2
+test 3
+ReferenceError: "a" is not defined
+3
+test 4
+undefined
+4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let.js	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8051889: Implement block scoping in symbol assignment and scope computation
+ *
+ * @test
+ * @run
+ * @option --language=es6 */
+
+"use strict";
+
+let a = 2;
+let c = 2;
+print(a, c);
+
+function f(x) {
+    let a = 5;
+    const c = 10;
+    print(a, c);
+    if (x) {
+        let a = 42;
+        const c = 43;
+        print(a, c);
+    }
+    print(a, c);
+
+    function inner() {
+        (function() {
+            print(a, c);
+        })();
+    }
+    inner();
+}
+
+f(true);
+f(false);
+
+(function() {
+    (function() {
+        print(a, c);
+    })();
+})();
+
+function outer() {
+    print(a, c);
+}
+outer();
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let.js.EXPECTED	Thu Sep 04 15:37:14 2014 +0200
@@ -0,0 +1,10 @@
+2 2
+5 10
+42 43
+5 10
+5 10
+5 10
+5 10
+5 10
+2 2
+2 2
--- a/nashorn/test/script/trusted/JDK-8006529.js	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/test/script/trusted/JDK-8006529.js	Thu Sep 04 15:37:14 2014 +0200
@@ -120,7 +120,7 @@
 
 var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
 var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
-var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, boolean.class);
+var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, ErrorManager.class, boolean.class);
 
 // compile(script) -- compiles a script specified as a string with its
 // source code, returns a jdk.nashorn.internal.ir.FunctionNode object
@@ -134,7 +134,7 @@
     var parser   = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance());
     var func     = parseMethod.invoke(parser);
 
-    var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, false);
+    var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, null, false);
 
     return compileMethod.invoke(compiler, func, phases);
 };
--- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Thu Sep 04 15:37:14 2014 +0200
@@ -98,11 +98,16 @@
             compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() {
                 @Override
                 public boolean exclude(final File file, final String content) {
-                    return content.indexOf("@negative") != -1;
+                    return content != null && content.contains("@negative");
                 }
             });
         }
-        compileTestSet(new File(TEST_BASIC_DIR), null);
+        compileTestSet(new File(TEST_BASIC_DIR), new TestFilter() {
+            @Override
+            public boolean exclude(final File file, final String content) {
+                return file.getName().equals("es6");
+            }
+        });
         compileTestSet(new File(TEST_NODE_DIR, "node"), null);
         compileTestSet(new File(TEST_NODE_DIR, "src"), null);
     }
@@ -136,6 +141,9 @@
     private int skipped;
 
     private void compileJSDirectory(final File dir, final TestFilter filter) {
+        if (filter != null && filter.exclude(dir, null)) {
+            return;
+        }
         for (final File f : dir.listFiles()) {
             if (f.isDirectory()) {
                 compileJSDirectory(f, filter);
--- a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java	Thu Sep 04 14:42:30 2014 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java	Thu Sep 04 15:37:14 2014 +0200
@@ -82,11 +82,16 @@
             parseTestSet(TEST262_SUITE_DIR, new TestFilter() {
                 @Override
                 public boolean exclude(final File file, final String content) {
-                    return content.indexOf("@negative") != -1;
+                    return content != null && content.contains("@negative");
                 }
             });
         }
-        parseTestSet(TEST_BASIC_DIR, null);
+        parseTestSet(TEST_BASIC_DIR,  new TestFilter() {
+            @Override
+            public boolean exclude(final File file, final String content) {
+                return file.getName().equals("es6");
+            }
+        });
     }
 
     private void parseTestSet(final String testSet, final TestFilter filter) {
@@ -120,6 +125,9 @@
     private int skipped;
 
     private void parseJSDirectory(final File dir, final TestFilter filter) {
+        if (filter != null && filter.exclude(dir, null)) {
+            return;
+        }
         for (final File f : dir.listFiles()) {
             if (f.isDirectory()) {
                 parseJSDirectory(f, filter);