[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);
+}
+
+})();