[ES6] Add support for block scope const
https://bugs.webkit.org/show_bug.cgi?id=31813

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

'const' is now implemented in an ES6 spec compliant manner.
'const' variables are always block scoped and always live
either on the stack or in a JSLexicalEnvironment. 'const'
variables never live on the global object.

Inside the BytecodeGenerator, when assigning to a stack
'const' variable or a LocalClosureVar 'const' variable,
we will emit code that just throws a type error.
When assigning to a ClosureVar const variable, CodeBlock linking
will ensure that we perform a dynamic lookup of that variable so
that put_to_scope's slow path throws a type error.

The old 'const' implementation has been removed in this patch.

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::pushLexicalScope):
(JSC::BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration):
(JSC::BytecodeGenerator::variable):
(JSC::BytecodeGenerator::variableForLocalEntry):
(JSC::BytecodeGenerator::createVariable):
(JSC::BytecodeGenerator::emitResolveScope):
(JSC::BytecodeGenerator::emitInstanceOf):
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::isArgumentNumber):
(JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded):
(JSC::BytecodeGenerator::emitEnumeration):
(JSC::BytecodeGenerator::variablePerSymbolTable): Deleted.
(JSC::BytecodeGenerator::emitInitGlobalConst): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::Variable::Variable):
(JSC::Variable::isReadOnly):
(JSC::Variable::isSpecial):
(JSC::Variable::isConst):
(JSC::BytecodeGenerator::thisRegister):
(JSC::BytecodeGenerator::emitTypeOf):
(JSC::BytecodeGenerator::emitIn):
* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::CommaNode::emitBytecode):
(JSC::BindingNode::bindValue):
(JSC::ConstDeclNode::emitCodeSingle): Deleted.
(JSC::ConstDeclNode::emitBytecode): Deleted.
(JSC::ConstStatementNode::emitBytecode): Deleted.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_to_arguments):
(JSC::JIT::emit_op_init_global_const): Deleted.
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_to_arguments):
(JSC::JIT::emit_op_init_global_const): Deleted.
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createDeclarationStatement):
(JSC::ASTBuilder::createEmptyVarExpression):
(JSC::ASTBuilder::createDebugger):
(JSC::ASTBuilder::appendStatement):
(JSC::ASTBuilder::createVarStatement): Deleted.
(JSC::ASTBuilder::createLetStatement): Deleted.
(JSC::ASTBuilder::createConstStatement): Deleted.
(JSC::ASTBuilder::appendConstDecl): Deleted.
* parser/NodeConstructors.h:
(JSC::CommaNode::CommaNode):
(JSC::SourceElements::SourceElements):
(JSC::SwitchNode::SwitchNode):
(JSC::BlockNode::BlockNode):
(JSC::ConstStatementNode::ConstStatementNode): Deleted.
(JSC::ConstDeclNode::ConstDeclNode): Deleted.
* parser/Nodes.h:
(JSC::ConstDeclNode::hasInitializer): Deleted.
(JSC::ConstDeclNode::ident): Deleted.
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseVariableDeclaration):
(JSC::Parser<LexerType>::parseWhileStatement):
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::parseDestructuringPattern):
(JSC::Parser<LexerType>::parseDefaultValueForDestructuringPattern):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseTryStatement):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseConstDeclaration): Deleted.
(JSC::Parser<LexerType>::parseConstDeclarationList): Deleted.
* parser/Parser.h:
(JSC::isEvalNode):
(JSC::isEvalNode<EvalNode>):
(JSC::isArguments):
(JSC::isEval):
(JSC::isEvalOrArgumentsIdentifier):
(JSC::Scope::Scope):
(JSC::Scope::declareCallee):
(JSC::Scope::declareVariable):
(JSC::Scope::declareLexicalVariable):
(JSC::Scope::hasDeclaredVariable):
(JSC::Scope::allowsVarDeclarations):
(JSC::Scope::allowsLexicalDeclarations):
(JSC::Scope::declareParameter):
(JSC::Scope::declareBoundParameter):
(JSC::Parser::destructuringKindFromDeclarationType):
(JSC::Parser::assignmentContextFromDeclarationType):
(JSC::Parser::isEvalOrArguments):
(JSC::Parser::currentScope):
(JSC::Parser::popScope):
(JSC::Parser::declareVariable):
(JSC::Parser::hasDeclaredVariable):
(JSC::Parser::setStrictMode):
(JSC::Parser::strictMode):
(JSC::Parser::isValidStrictMode):
(JSC::Parser::declareParameter):
(JSC::Parser::declareBoundParameter):
(JSC::Parser::breakIsValid):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createForInLoop):
(JSC::SyntaxChecker::createForOfLoop):
(JSC::SyntaxChecker::createEmptyStatement):
(JSC::SyntaxChecker::createDeclarationStatement):
(JSC::SyntaxChecker::createReturnStatement):
(JSC::SyntaxChecker::createBreakStatement):
(JSC::SyntaxChecker::createVarStatement): Deleted.
(JSC::SyntaxChecker::createLetStatement): Deleted.
* parser/VariableEnvironment.h:
(JSC::VariableEnvironmentEntry::isCaptured):
(JSC::VariableEnvironmentEntry::isConst):
(JSC::VariableEnvironmentEntry::isVar):
(JSC::VariableEnvironmentEntry::isLet):
(JSC::VariableEnvironmentEntry::setIsCaptured):
(JSC::VariableEnvironmentEntry::setIsConst):
(JSC::VariableEnvironmentEntry::setIsVar):
(JSC::VariableEnvironmentEntry::setIsLet):
(JSC::VariableEnvironmentEntry::isConstant): Deleted.
(JSC::VariableEnvironmentEntry::setIsConstant): Deleted.
* runtime/Executable.cpp:
(JSC::ProgramExecutable::initializeGlobalProperties):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::defineOwnProperty):
(JSC::JSGlobalObject::addGlobalVar):
(JSC::JSGlobalObject::addFunction):
(JSC::lastInPrototypeChain):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::finishCreation):
(JSC::JSGlobalObject::addVar):
(JSC::JSGlobalObject::addConst): Deleted.
* runtime/JSLexicalEnvironment.cpp:
(JSC::JSLexicalEnvironment::symbolTablePut):
* tests/stress/const-and-with-statement.js: Added.
(truth):
(assert):
(shouldThrowInvalidConstAssignment):
(.):
* tests/stress/const-exception-handling.js: Added.
(truth):
(assert):
(.):
* tests/stress/const-loop-semantics.js: Added.
(truth):
(assert):
(shouldThrowInvalidConstAssignment):
(.):
* tests/stress/const-not-strict-mode.js: Added.
(truth):
(assert):
(shouldThrowTDZ):
(.):
* tests/stress/const-semantics.js: Added.
(truth):
(assert):
(shouldThrowInvalidConstAssignment):
(.):
* tests/stress/const-tdz.js: Added.
(truth):
(assert):
(shouldThrowTDZ):
(.):

Source/WebInspectorUI:

"const" variables do not live on the global object and are only
accessible within the "Program" they're defined in. Therefore,
the WebInspector global must be defined as "var" and not "const".

* UserInterface/Base/WebInspector.js:

LayoutTests:

"const" variables do not live on the global object. They
are only available in the "Program" (read: JavaScript file or
script tag) that they're defined in. Tests have been updated
accordingly to switch the "const" variables assumed to be globals
into "var"s. "var" declared variables in the top level scope
of a program do live on the global object.

* fast/canvas/webgl/compressed-tex-image.html:
* fast/dom/event-handler-attributes.html:
* fast/forms/listbox-visible-size.html:
* js/arguments-expected.txt:
* js/arrowfunction-syntax-errors-expected.txt:
* js/const-expected.txt:
* js/const-without-initializer-expected.txt:
* js/constant-count-expected.txt:
* js/dom/inc-const-valueOf-expected.txt:
* js/dom/script-tests/inc-const-valueOf.js:
(testPreIncConstVarWithAssign):
* js/function-toString-parentheses-expected.txt:
* js/kde/const-expected.txt:
* js/kde/resources/const.js:
* js/parser-syntax-check-expected.txt:
* js/script-tests/arguments.js:
(argumentsVarUndefined):
(argumentsConst):
(argumentCalleeInException):
(argumentsConstUndefined): Deleted.
* js/script-tests/class-syntax-declaration.js:
(A):
* js/script-tests/class-syntax-expression.js:
* js/script-tests/const-without-initializer.js:
* js/script-tests/const.js:
(shouldThrowInvalidConstAssignment):
(assert):
(f):
(tryCatch1):
(tryCatch2):
(with1):
(with2):
(.):
* js/script-tests/constant-count.js:
(f):
* js/script-tests/function-dot-arguments.js:
(assignConstInitTest2.g):
(assignConstInitTest2):
* js/script-tests/function-toString-parentheses.js:
* js/script-tests/parser-syntax-check.js:
* sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.6-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T7-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T8-expected.txt:
* sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T9-expected.txt:
* sputnik/Conformance/08_Types/8.4_The_String_Type/S8.4_A13_T3-expected.txt:
* sputnik/Conformance/08_Types/8.4_The_String_Type/S8.4_A14_T3-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T1-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T2-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T3-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T4-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T6-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T7-expected.txt:
* sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T8-expected.txt:
* transforms/3d/hit-testing/composited-hit-test.html:
* transforms/3d/hit-testing/coplanar-with-camera.html:
* transforms/3d/hit-testing/hover-rotated-negative-z.html:
* transforms/3d/hit-testing/hover-rotated-with-children-negative-z.html:
* transforms/3d/hit-testing/negative-zoffset-hit-test.html:
* transforms/3d/hit-testing/overlapping-layers-hit-test.html:
* transforms/3d/hit-testing/perspective-clipped.html:
* transforms/3d/hit-testing/rotated-hit-test-with-child.html:
* transforms/3d/hit-testing/rotated-hit-test.html:
* transforms/3d/hit-testing/rotated-hit-test2.html:
* transitions/resources/transition-test-helpers.js:
(roundNumber):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@187012 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/tests/stress/const-exception-handling.js b/Source/JavaScriptCore/tests/stress/const-exception-handling.js
new file mode 100644
index 0000000..f22ab12
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/const-exception-handling.js
@@ -0,0 +1,204 @@
+"use strict";
+
+function truth() {
+    return true;
+}
+noInline(truth);
+
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+
+// Tests
+
+
+const NUM_LOOPS = 10000;
+
+;(function () {
+function foo() {
+    const x = 20;
+    const y = "y";
+    try {
+        assert(x === 20);
+        assert(y === "y");
+        throw "error";
+    } catch(e) {
+        assert(x === 20);
+    } finally {
+        assert(x === 20);
+        assert(y === "y");
+    }
+
+    for (let i = 0; i < 1; i++) {
+        let numFinally = 0;
+        try {
+            let a = 40;
+            let capA = function() { return a; }
+            assert(capA() === 40);
+            try {
+                const b = 41;
+                const capB = function() { return b; }
+                assert(capB() === 41);
+                assert(capA() === 40);
+                try {
+                    return 20;
+                } catch(e){
+                } finally {
+                    const c = 42;
+                    const capC = function() { return c; }
+                    assert(capC() === 42);
+                    assert(capB() === 41);
+                    assert(capA() === 40);
+                    if (i === 0) {
+                        numFinally++;
+                    }
+                    return 22;
+                }
+            } catch(e) {
+            } finally {
+                if (i === 0) {
+                    numFinally++;
+                }
+                return 23;
+            }
+        } catch(e) {
+        } finally {
+            if (i === 0) {
+                numFinally++;
+            }
+            assert(numFinally === 3);
+            return 24;
+        }
+    }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    assert(foo() === 24);
+}
+
+})();
+
+
+;(function () {
+function foo() {
+    for (let i = 0; i < 1; i++) {
+        let numFinally = 0;
+        let numErrors = 0;
+        try {
+            let a = 40;
+            let capA = function() { return a; }
+            assert(capA() === 40);
+            try {
+                const b = 41;
+                const capB = function() { return b; }
+                assert(capB() === 41);
+                assert(capA() === 40);
+                try {
+                    throw "e";
+                } catch(e) {
+                    assert(i === 0);
+                    assert(capB() === 41);
+                    assert(capA() === 40);
+                    numErrors++;
+                    throw e;
+                } finally {
+                    const c = 42;
+                    const capC = function() { return c; }
+                    const local = "local";
+                    assert(local === "local");
+                    assert(capC() === 42);
+                    assert(capB() === 41);
+                    assert(capA() === 40);
+                    if (i === 0) {
+                        numFinally++;
+                    }
+                }
+            } catch(e) {
+                assert(i === 0);
+                assert(capA() === 40);
+                numErrors++;
+                const local = "local";
+                assert(local === "local");
+            } finally {
+                assert(capA() === 40);
+                if (i === 0) {
+                    numFinally++;
+                }
+                const local = "local";
+                assert(local === "local");
+                return 23;
+            }    
+        } catch(e) {
+            //assert(i === 0);
+        } finally {
+            if (i === 0) {
+                numFinally++;
+            }
+
+            assert(numFinally === 3);
+            assert(numErrors === 2);
+            return 24;
+        }
+    }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    assert(foo() === 24);
+}
+
+})();
+
+
+var d = 100;
+;(function (){
+function foo() {
+    assert(d === 100);
+    for (let i = 0; i < 1; i++) {
+        let numFinally = 0;
+        let numErrors = 0;
+        const c = 44;
+        assert(d === 100);
+        try {
+            const d = 45;
+            if (truth()) {
+                const a = 20;
+                const capA = function() { return a; }
+                assert(capA() === 20);
+                if (truth()) {
+                    const b = 21;
+                    const e = 48;
+                    const capB = function() { return b; }
+                    assert(capB() === 21);
+                    assert(d === 45);
+                    try {
+                        throw "e";
+                    } catch(e) {
+                        assert(capA() === 20);
+                        assert(a === 20);
+                        numErrors++;
+                    } finally {
+                        assert(capA() === 20);
+                        assert(e === 48);
+                        numFinally++;
+                        return 30;
+                    }
+                } 
+            }
+        } finally {
+            assert(c === 44);
+            assert(d === 100);
+            numFinally++;
+            assert(numFinally === 2);
+            assert(numErrors === 1);
+            return 40;
+        }
+    }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    assert(foo() === 40);
+}
+
+})();