[ES6] Add support for block scope const
authorsaambarati1@gmail.com <saambarati1@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 19 Jul 2015 16:57:44 +0000 (16:57 +0000)
committersaambarati1@gmail.com <saambarati1@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 19 Jul 2015 16:57:44 +0000 (16:57 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@187012 268f45cc-cd09-0410-ab3c-d52691b4dbfc

83 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/canvas/webgl/compressed-tex-image.html
LayoutTests/fast/dom/event-handler-attributes.html
LayoutTests/fast/forms/listbox-visible-size.html
LayoutTests/js/arguments-expected.txt
LayoutTests/js/arrowfunction-syntax-errors-expected.txt
LayoutTests/js/const-expected.txt
LayoutTests/js/const-without-initializer-expected.txt
LayoutTests/js/constant-count-expected.txt
LayoutTests/js/dom/inc-const-valueOf-expected.txt
LayoutTests/js/dom/script-tests/inc-const-valueOf.js
LayoutTests/js/function-toString-parentheses-expected.txt
LayoutTests/js/kde/const-expected.txt
LayoutTests/js/kde/resources/const.js
LayoutTests/js/parser-syntax-check-expected.txt
LayoutTests/js/script-tests/arguments.js
LayoutTests/js/script-tests/class-syntax-declaration.js
LayoutTests/js/script-tests/class-syntax-expression.js
LayoutTests/js/script-tests/const-without-initializer.js
LayoutTests/js/script-tests/const.js
LayoutTests/js/script-tests/constant-count.js
LayoutTests/js/script-tests/function-dot-arguments.js
LayoutTests/js/script-tests/function-toString-parentheses.js
LayoutTests/js/script-tests/parser-syntax-check.js
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.6-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T7-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T8-expected.txt
LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.8_Literals/7.8.5_Regular_Expression_Literals/S7.8.5_A3.1_T9-expected.txt
LayoutTests/sputnik/Conformance/08_Types/8.4_The_String_Type/S8.4_A13_T3-expected.txt
LayoutTests/sputnik/Conformance/08_Types/8.4_The_String_Type/S8.4_A14_T3-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T1-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T2-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T3-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T4-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T6-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T7-expected.txt
LayoutTests/sputnik/Conformance/12_Statement/12.2_Variable_Statement/S12.2_A8_T8-expected.txt
LayoutTests/transforms/3d/hit-testing/composited-hit-test.html
LayoutTests/transforms/3d/hit-testing/coplanar-with-camera.html
LayoutTests/transforms/3d/hit-testing/hover-rotated-negative-z.html
LayoutTests/transforms/3d/hit-testing/hover-rotated-with-children-negative-z.html
LayoutTests/transforms/3d/hit-testing/negative-zoffset-hit-test.html
LayoutTests/transforms/3d/hit-testing/overlapping-layers-hit-test.html
LayoutTests/transforms/3d/hit-testing/perspective-clipped.html
LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child.html
LayoutTests/transforms/3d/hit-testing/rotated-hit-test.html
LayoutTests/transforms/3d/hit-testing/rotated-hit-test2.html
LayoutTests/transitions/resources/transition-test-helpers.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/SyntaxChecker.h
Source/JavaScriptCore/parser/VariableEnvironment.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
Source/JavaScriptCore/tests/stress/const-and-with-statement.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/const-exception-handling.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/const-loop-semantics.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/const-not-strict-mode.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/const-semantics.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/const-tdz.js [new file with mode: 0644]
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/WebInspector.js

index 8896fb1..f2313df 100644 (file)
@@ -1,3 +1,83 @@
+2015-07-18  Saam barati  <saambarati1@gmail.com>
+
+        [ES6] Add support for block scope const
+        https://bugs.webkit.org/show_bug.cgi?id=31813
+
+        Reviewed by Filip Pizlo.
+
+        "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):
+
 2015-07-18  David Kilzer  <ddkilzer@apple.com>
 
         inspector/console/command-line-api.html is slow on Debug Yosemite WK2
index a15a284..1359ccf 100644 (file)
@@ -22,12 +22,12 @@ var wtu = WebGLTestUtils;
 var canvas = document.createElement("canvas");
 var gl = wtu.create3DContext(canvas);
 
-const  COMPRESSED_RGB_S3TC_DXT1_EXT        = 0x83F0;
-const  COMPRESSED_RGBA_S3TC_DXT1_EXT       = 0x83F1;
-const  COMPRESSED_RGBA_S3TC_DXT5_EXT       = 0x83F3;
-const  ETC1_RGB8_OES                       = 0x8D64;
-const  COMPRESSED_RGB_PVRTC_4BPPV1_IMG     = 0x8C00;
-const  COMPRESSED_RGBA_PVRTC_4BPPV1_IMG    = 0x8C02;
+var  COMPRESSED_RGB_S3TC_DXT1_EXT        = 0x83F0;
+var  COMPRESSED_RGBA_S3TC_DXT1_EXT       = 0x83F1;
+var  COMPRESSED_RGBA_S3TC_DXT5_EXT       = 0x83F3;
+var  ETC1_RGB8_OES                       = 0x8D64;
+var  COMPRESSED_RGB_PVRTC_4BPPV1_IMG     = 0x8C00;
+var  COMPRESSED_RGBA_PVRTC_4BPPV1_IMG    = 0x8C02;
 
 if (!gl) {
   testFailed("context does not exist");
index 20f4461..d93a5db 100644 (file)
@@ -278,14 +278,14 @@ function testArray(array, prefix, expected, sectionName)
     }
 }
 
-const nonHTMLElement = document.createElementNS("foo", "foo");
-const element = document.documentElement;
-const bodyElement = document.body;
-const audioElement = document.createElement("video");
-const framesetElement = document.createElement("frameset");
-const inputElement = document.createElement("input");
-const videoElement = document.createElement("video");
-const rectElement = document.createElementNS("http://www.w3.org/2000/svg", "rect");
+var nonHTMLElement = document.createElementNS("foo", "foo");
+var element = document.documentElement;
+var bodyElement = document.body;
+var audioElement = document.createElement("video");
+var framesetElement = document.createElement("frameset");
+var inputElement = document.createElement("input");
+var videoElement = document.createElement("video");
+var rectElement = document.createElementNS("http://www.w3.org/2000/svg", "rect");
 
 testArray(windowEvents, "testScriptAttribute(window", "window", "Event names we expect to be able to set on the window object");
 testArray(arrayDifference(allEventNames, windowEvents), "testScriptAttribute(window", "none", "Event names we expect not to be able to set on the window object");
index 9ce2db7..4ff563e 100644 (file)
@@ -21,7 +21,7 @@
         <option>Sunday</option>
     </select>
     <script>
-    const targetTop = 28;
+    var targetTop = 28;
     var select;
     function scrollSelect(newTop)
     {
index 9da1e85..9ed480b 100644 (file)
@@ -134,7 +134,7 @@ PASS access_after_delete_extra_5(1, 2, 3, 4, 5) is 5
 PASS argumentsParam(true) is true
 PASS argumentsFunctionConstructorParam(true) is true
 PASS argumentsVarUndefined() is '[object Arguments]'
-PASS argumentsConstUndefined() is '[object Arguments]'
+PASS argumentsConst() is '20'
 PASS argumentCalleeInException() is argumentCalleeInException
 PASS shadowedArgumentsApply([true]) is true
 PASS shadowedArgumentsLength([]) is 0
index 133bb5a..e19df25 100644 (file)
@@ -113,8 +113,8 @@ PASS var y = x=>} threw exception SyntaxError: Unexpected token '}'.
 PASS var t = x=>x+1; =>{} threw exception SyntaxError: Unexpected keyword '=>'.
 PASS [=>x+1] threw exception SyntaxError: Unexpected keyword '=>'.
 PASS [x=>x+1, =>x+1] threw exception SyntaxError: Unexpected keyword '=>'.
-PASS var f=>x+1; threw exception SyntaxError: Unexpected keyword '=>'. Expected ';' after var declaration..
-PASS var x, y=>y+1; threw exception SyntaxError: Unexpected keyword '=>'. Expected ';' after var declaration..
+PASS var f=>x+1; threw exception SyntaxError: Unexpected keyword '=>'. Expected ';' after variable declaration..
+PASS var x, y=>y+1; threw exception SyntaxError: Unexpected keyword '=>'. Expected ';' after variable declaration..
 PASS debug(=>x+1) threw exception SyntaxError: Unexpected keyword '=>'.
 PASS debug("xyz", =>x+1) threw exception SyntaxError: Unexpected keyword '=>'.
 PASS var af1=y
index 68a3675..7b3b681 100644 (file)
@@ -3,65 +3,59 @@ This test checks that const declarations in JavaScript work and are readonly.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-FAIL const redef='a'; const redef='a'; should throw an exception. Was undefined.
-PASS x is "RIGHT"
-PASS y is "RIGHT"
-PASS a is 1
-PASS one is 1
-PASS a is 1
-PASS one is 1
-PASS a is 2
-PASS one is 1
-PASS a is 0
-PASS one is 1
-PASS a is 3
-PASS one is 1
-PASS a is 2
-PASS one is 1
-PASS function f() { const one = 1; one++; return one; } f(); is 1
-PASS function f() { const oneString = '1'; return oneString++; } f(); is 1
-PASS function f() { const one = 1; return one++; } f(); is 1
-PASS function f() { const one = 1; one--; return one; } f(); is 1
-PASS function f() { const oneString = '1'; return oneString--; } f(); is 1
-PASS function f() { const one = 1; return one--; } f(); is 1
-PASS function f() { const one = 1; ++one; return one; } f(); is 1
-PASS function f() { const one = 1; return ++one; } f(); is 2
-PASS function f() { const one = 1; --one; return one; } f(); is 1
-PASS function f() { const one = 1; return --one; } f(); is 0
-PASS function f() { const one = 1; one += 2; return one; } f(); is 1
-PASS function f() { const one = 1; return one += 2; } f(); is 3
-PASS function f() { const one = 1; one = 2; return one; } f(); is 1
-PASS function f() { const one = 1; return one = 2; } f(); is 2
-PASS one++ is 1
-PASS one is 1
-PASS one-- is 1
-PASS one is 1
-PASS ++one is 2
-PASS one is 1
-PASS --one is 0
-PASS one is 1
-PASS one += 1 is 2
-PASS one is 1
-PASS one = 2 is 2
-PASS one is 1
-PASS object.inWith1 is 'RIGHT'
-PASS inWith2 is 'RIGHT'
-PASS (function(){ one = 2; return one; })() is 1
+PASS const redef='a'; const redef='a'; threw exception SyntaxError: Cannot declare a const variable twice: 'redef'..
+PASS function threw exception: 'function () { x = "WRONG"; }'
+PASS Assertion passed.
+PASS function threw exception: 'function () { y = "WRONG"; }'
+PASS Assertion passed.
+PASS function threw exception: 'function () { a = one++; }'
+PASS Assertion passed.
+PASS Assertion passed.
+PASS function threw exception: 'function () { a = one--; }'
+PASS Assertion passed.
+PASS Assertion passed.
+PASS function threw exception: 'function () { a = ++one; }'
+PASS Assertion passed.
+PASS Assertion passed.
+PASS function threw exception: 'function () { a = --one; }'
+PASS Assertion passed.
+PASS Assertion passed.
+PASS function threw exception: 'function () { a = one += 2; }'
+PASS Assertion passed.
+PASS Assertion passed.
+PASS function threw exception: 'function () { a = one = 2; }'
+PASS Assertion passed.
+PASS Assertion passed.
+PASS function f() { const one = 1; one++; return one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const oneString = '1'; return oneString++; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; return one++; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; one--; return one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const oneString = '1'; return oneString--; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; return one--; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; ++one; return one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; return ++one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; --one; return one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; return --one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; one += 2; return one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; return one += 2; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; one = 2; return one; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS function f() { const one = 1; return one = 2; } f(); threw exception TypeError: Attempted to assign to readonly property..
+PASS Assertion passed.
+PASS Assertion passed.
+PASS object.inWith1 is 'a'
+PASS object.inWith2 is 'b'
 PASS f() is f
-PASS const a; is undefined
-PASS tryCatch1Result is 5
-PASS tryCatch2Result is 5
-PASS with1Result is 5
-PASS with2Result is 5
-PASS PASS: ++x should be 2 and is.
-PASS PASS: --x should be 0 and is.
-PASS PASS: x should be 1 and is.
-PASS PASS: x++ should be 1 and is.
-PASS PASS: x should be 1 and is.
-PASS PASS: ++x should be 2 and is.
-PASS PASS: x should be 1 and is.
-PASS PASS: x++ should be 1 and is.
-PASS PASS: x should be 1 and is.
+PASS tryCatch1Result is null
+PASS tryCatch2Result is null
+PASS with1Result is null
+PASS with2Result is null
+PASS function threw exception: 'function () { ++x; }'
+PASS Assertion passed.
+PASS function threw exception: 'function () { x++; }'
+PASS Assertion passed.
+PASS function threw exception: 'function () { x--; }'
+PASS Assertion passed.
+PASS function threw exception: 'function () { --x; }'
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 376cf89..4d19c38 100644 (file)
@@ -3,8 +3,7 @@ Tests that declaring a const variable without initializing has the correct behav
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS f is undefined
-PASS f is undefined
+PASS const f threw exception SyntaxError: Unexpected end of script.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 41c7528..0f8a92f 100644 (file)
@@ -3,8 +3,8 @@ This test checks exceptional cases for constant counting in the parser.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS a is undefined
-PASS f() is undefined
+PASS 'a' is all good
+PASS f() is 10
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 76a4bc3..0bb92ae 100644 (file)
@@ -3,9 +3,9 @@ Test for regression against
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS testPostIncConstVarWithIgnoredResult() is true
-PASS testPreIncConstVarWithIgnoredResult() is true
-PASS testPreIncConstVarWithAssign() is true
+PASS testPostIncConstVarWithIgnoredResult() threw exception TypeError: Attempted to assign to readonly property..
+PASS testPreIncConstVarWithIgnoredResult() threw exception TypeError: Attempted to assign to readonly property..
+PASS testPreIncConstVarWithAssign() instanceof TypeError is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 463862b..68a821c 100644 (file)
@@ -49,8 +49,8 @@ function testPreIncConstVarWithAssign()
     return okay;
 }
 
-shouldBeTrue('testPostIncConstVarWithIgnoredResult()');
-shouldBeTrue('testPreIncConstVarWithIgnoredResult()');
-shouldBeTrue('testPreIncConstVarWithAssign()');
+shouldThrow('testPostIncConstVarWithIgnoredResult()');
+shouldThrow('testPreIncConstVarWithIgnoredResult()');
+shouldBeTrue('testPreIncConstVarWithAssign() instanceof TypeError');
 
 successfullyParsed = true;
index 6338f4e..9d66640 100644 (file)
@@ -489,8 +489,8 @@ PASS compileAndSerializeLeftmostTest('var a, b, c') is 'var a, b, c'
 PASS compileAndSerializeLeftmostTest('var a = 1, b = 2, c = 3') is 'var a = 1, b = 2, c = 3'
 PASS compileAndSerializeLeftmostTest('const a = 1') is 'const a = 1'
 PASS compileAndSerializeLeftmostTest('const a = (1, 2)') is 'const a = (1, 2)'
-PASS compileAndSerializeLeftmostTest('const a, b = 1') is 'const a, b = 1'
-PASS compileAndSerializeLeftmostTest('const a = 1, b') is 'const a = 1, b'
+PASS compileAndSerializeLeftmostTest('const a = 10, b = 1') is 'const a = 10, b = 1'
+PASS compileAndSerializeLeftmostTest('const a = 1, b = 2') is 'const a = 1, b = 2'
 PASS compileAndSerializeLeftmostTest('const a = 1, b = 1') is 'const a = 1, b = 1'
 PASS compileAndSerializeLeftmostTest('const a = (1, 2), b = 1') is 'const a = (1, 2), b = 1'
 PASS compileAndSerializeLeftmostTest('const a = 1, b = (1, 2)') is 'const a = 1, b = (1, 2)'
index 61cd431..abbd8bc 100644 (file)
@@ -3,8 +3,9 @@ KDE JS Test
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS c is 11
-PASS c is 11
+PASS c is eleven
+PASS cant assign to const
+PASS c is eleven
 PASS v is 1
 PASS successfullyParsed is true
 
index ed3b422..908b0f0 100644 (file)
@@ -1,10 +1,26 @@
 // constant definition
 const c = 11;
-shouldBe("c", "11");
+if (c !== 11)
+    testFailed("c is not eleven");
+else
+    testPassed("c is eleven");
 
 // attempt to redefine should have no effect
-c = 22;
-shouldBe("c", "11");
+var threwError = false;
+try {
+    c = 22;
+} catch(e) {
+    threwError = true;
+}
+if (threwError)
+    testPassed("cant assign to const");
+else
+    testFailed("const assignment worked but should not have");
+
+if (c !== 11)
+    testFailed("c is not eleven");
+else
+    testPassed("c is eleven");
 
 const dummy = 0;
 for (var v = 0;;) {
index 2fab1cc..3297959 100644 (file)
@@ -319,16 +319,18 @@ PASS Invalid: "function f() { throw }"
 var and const statements
 PASS Valid:   "var a, b = null"
 PASS Valid:   "function f() { var a, b = null }"
-PASS Valid:   "const a = 5, b, c"
-PASS Valid:   "function f() { const a = 5, b, c }"
+PASS Valid:   "const a = 5, b = 10, c = 20"
+PASS Valid:   "function f() { const a = 5, b = 10, c = 20 }"
 PASS Invalid: "var"
 PASS Invalid: "function f() { var }"
 PASS Invalid: "var = 7"
 PASS Invalid: "function f() { var = 7 }"
 PASS Invalid: "var c (6)"
 PASS Invalid: "function f() { var c (6) }"
-PASS Valid:   "if (a) var a,b; else { const b, c }"
-PASS Valid:   "function f() { if (a) var a,b; else { const b, c } }"
+PASS Valid:   "if (a) var a,b; else { const b = 1, c = 2; }"
+PASS Valid:   "function f() { if (a) var a,b; else { const b = 1, c = 2; } }"
+PASS Invalid: "if (a) var a,b; else { const b, c }"
+PASS Invalid: "function f() { if (a) var a,b; else { const b, c } }"
 PASS Invalid: "var 5 = 6"
 PASS Invalid: "function f() { var 5 = 6 }"
 PASS Valid:   "while (0) var a, b, c=6, d, e, f=5*6, g=f*h, h"
@@ -337,8 +339,8 @@ PASS Invalid: "var a = if (b) { c }"
 PASS Invalid: "function f() { var a = if (b) { c } }"
 PASS Invalid: "var a = var b"
 PASS Invalid: "function f() { var a = var b }"
-PASS Valid:   "const a = b += c, a, a, a = (b - f())" with ReferenceError
-PASS Valid:   "function f() { const a = b += c, a, a, a = (b - f()) }"
+PASS Invalid: "const a = b += c, a, a, a = (b - f())"
+PASS Invalid: "function f() { const a = b += c, a, a, a = (b - f()) }"
 PASS Invalid: "var a %= b | 5"
 PASS Invalid: "function f() { var a %= b | 5 }"
 PASS Invalid: "var (a) = 5"
@@ -351,8 +353,10 @@ PASS Invalid: "var var = 3"
 PASS Invalid: "function f() { var var = 3 }"
 PASS Valid:   "var varr = 3 in 1" with TypeError
 PASS Valid:   "function f() { var varr = 3 in 1 }"
-PASS Valid:   "const a, a, a = void 7 - typeof 8, a = 8"
-PASS Valid:   "function f() { const a, a, a = void 7 - typeof 8, a = 8 }"
+PASS Valid:   "const  a = void 7 - typeof 8, b = 8"
+PASS Valid:   "function f() { const  a = void 7 - typeof 8, b = 8 }"
+PASS Invalid: "const a, a, a = void 7 - typeof 8, a = 8"
+PASS Invalid: "function f() { const a, a, a = void 7 - typeof 8, a = 8 }"
 PASS Valid:   "const x_x = 6 /= 7 ? e : f" with ReferenceError
 PASS Valid:   "function f() { const x_x = 6 /= 7 ? e : f }"
 PASS Invalid: "var a = ?"
@@ -367,29 +371,29 @@ PASS Invalid: "var a = b ? c, b"
 PASS Invalid: "function f() { var a = b ? c, b }"
 PASS Invalid: "const a = b : c"
 PASS Invalid: "function f() { const a = b : c }"
-PASS Valid:   "const a = 7; eval(''); a++"
+PASS Valid:   "const a = 7; eval(''); a++" with TypeError
 PASS Valid:   "function f() { const a = 7; eval(''); a++ }"
-PASS Valid:   "const a = 7; eval(''); a--"
+PASS Valid:   "const a = 7; eval(''); a--" with TypeError
 PASS Valid:   "function f() { const a = 7; eval(''); a-- }"
-PASS Valid:   "const a = 7; with({}) a++"
+PASS Valid:   "const a = 7; with({}) a++" with TypeError
 PASS Valid:   "function f() { const a = 7; with({}) a++ }"
-PASS Valid:   "const a = 7; with({}) a--"
+PASS Valid:   "const a = 7; with({}) a--" with TypeError
 PASS Valid:   "function f() { const a = 7; with({}) a-- }"
-PASS Valid:   "const a = 7; eval(''); a+=1"
+PASS Valid:   "const a = 7; eval(''); a+=1" with TypeError
 PASS Valid:   "function f() { const a = 7; eval(''); a+=1 }"
-PASS Valid:   "const a = 7; eval(''); a-=1"
+PASS Valid:   "const a = 7; eval(''); a-=1" with TypeError
 PASS Valid:   "function f() { const a = 7; eval(''); a-=1 }"
-PASS Valid:   "const a = 7; with({}) a+=1"
+PASS Valid:   "const a = 7; with({}) a+=1" with TypeError
 PASS Valid:   "function f() { const a = 7; with({}) a+=1 }"
-PASS Valid:   "const a = 7; with({}) a-=1"
+PASS Valid:   "const a = 7; with({}) a-=1" with TypeError
 PASS Valid:   "function f() { const a = 7; with({}) a-=1 }"
-PASS Valid:   "const a = 7; eval(''); a=1"
+PASS Valid:   "const a = 7; eval(''); a=1" with TypeError
 PASS Valid:   "function f() { const a = 7; eval(''); a=1 }"
-PASS Valid:   "const a = 7; eval(''); a=1"
+PASS Valid:   "const a = 7; eval(''); a=1" with TypeError
 PASS Valid:   "function f() { const a = 7; eval(''); a=1 }"
-PASS Valid:   "const a = 7; with({}) a=1"
+PASS Valid:   "const a = 7; with({}) a=1" with TypeError
 PASS Valid:   "function f() { const a = 7; with({}) a=1 }"
-PASS Valid:   "const a = 7; with({}) a=1"
+PASS Valid:   "const a = 7; with({}) a=1" with TypeError
 PASS Valid:   "function f() { const a = 7; with({}) a=1 }"
 for statement
 PASS Valid:   "for ( ; ; ) { break }"
@@ -430,8 +434,36 @@ PASS Valid:   "for (var a = b, c, d ; ; 1 in a()) break" with ReferenceError
 PASS Valid:   "function f() { for (var a = b, c, d ; ; 1 in a()) break }"
 PASS Invalid: "for ( ; var a ; ) break"
 PASS Invalid: "function f() { for ( ; var a ; ) break }"
-PASS Invalid: "for (const a; ; ) break"
-PASS Invalid: "function f() { for (const a; ; ) break }"
+PASS Invalid: "for (const x; ; ) break"
+PASS Invalid: "function f() { for (const x; ; ) break }"
+PASS Invalid: "for (const x = 20, y; ; ) break"
+PASS Invalid: "function f() { for (const x = 20, y; ; ) break }"
+PASS Valid:   "for (const x = 20; ; ) break"
+PASS Valid:   "function f() { for (const x = 20; ; ) break }"
+PASS Valid:   "for (const x of []) break"
+PASS Valid:   "function f() { for (const x of []) break }"
+PASS Valid:   "for (const x in {}) break"
+PASS Valid:   "function f() { for (const x in {}) break }"
+PASS Invalid: "for (const x = 20, x = 30; ; ) { const x = 20; break; }"
+PASS Invalid: "function f() { for (const x = 20, x = 30; ; ) { const x = 20; break; } }"
+PASS Valid:   "for (const x = 20; ; ) { const x = 20; break; }"
+PASS Valid:   "function f() { for (const x = 20; ; ) { const x = 20; break; } }"
+PASS Valid:   "for (const x of []) { const x = 20; break; }"
+PASS Valid:   "function f() { for (const x of []) { const x = 20; break; } }"
+PASS Valid:   "for (const x in {}) { const x = 20; break; }"
+PASS Valid:   "function f() { for (const x in {}) { const x = 20; break; } }"
+PASS Invalid: "for (const let = 10; ; ) { break; }"
+PASS Invalid: "function f() { for (const let = 10; ; ) { break; } }"
+PASS Invalid: "for (const let in {}) { break; }"
+PASS Invalid: "function f() { for (const let in {}) { break; } }"
+PASS Invalid: "for (const let of []) { break; }"
+PASS Invalid: "function f() { for (const let of []) { break; } }"
+PASS Invalid: "for (let let = 10; ; ) { break; }"
+PASS Invalid: "function f() { for (let let = 10; ; ) { break; } }"
+PASS Invalid: "for (let let in {}) { break; }"
+PASS Invalid: "function f() { for (let let in {}) { break; } }"
+PASS Invalid: "for (let let of []) { break; }"
+PASS Invalid: "function f() { for (let let of []) { break; } }"
 PASS Invalid: "for ( %a ; ; ) { }"
 PASS Invalid: "function f() { for ( %a ; ; ) { } }"
 PASS Valid:   "for (a in b) break" with ReferenceError
index 8ce2517..40bf7de 100644 (file)
@@ -551,12 +551,12 @@ function argumentsVarUndefined()
 }
 shouldBe("argumentsVarUndefined()", "'[object Arguments]'");
 
-function argumentsConstUndefined()
+function argumentsConst()
 {
-    const arguments;
+    const arguments = 20;
     return String(arguments);
 }
-shouldBe("argumentsConstUndefined()", "'[object Arguments]'");
+shouldBe("argumentsConst()", "'20'");
 
 function argumentCalleeInException() {
     try {
index 479d87e..7d3b442 100644 (file)
@@ -2,9 +2,9 @@
 description('Tests for ES6 class syntax declarations');
 
 var constructorCallCount = 0;
-const staticMethodValue = [1];
-const instanceMethodValue = [2];
-const getterValue = [3];
+var staticMethodValue = [1];
+var instanceMethodValue = [2];
+var getterValue = [3];
 var setterValue = undefined;
 class A {
     constructor() { constructorCallCount++; }
index cbb8b95..29eacfa 100644 (file)
@@ -2,9 +2,9 @@
 description('Tests for ES6 class syntax expressions');
 
 var constructorCallCount = 0;
-const staticMethodValue = [1];
-const instanceMethodValue = [2];
-const getterValue = [3];
+var staticMethodValue = [1];
+var instanceMethodValue = [2];
+var getterValue = [3];
 var setterValue = undefined;
 var A = class {
     constructor() { constructorCallCount++; }
index 49b8f04..80e74c2 100644 (file)
@@ -2,10 +2,4 @@ description(
 'Tests that declaring a const variable without initializing has the correct behavior and does not crash'
 );
 
-const f;
-
-shouldBe('f', 'undefined');
-
-f = 10;
-
-shouldBe('f', 'undefined');
+shouldThrow("const f");
index 55a46c0..f087220 100644 (file)
@@ -2,119 +2,114 @@ description(
 "This test checks that const declarations in JavaScript work and are readonly."
 );
 
+function shouldThrowInvalidConstAssignment(f) {
+    var threw = false;
+    try {
+        f();
+    } catch(e) {
+        if (e.name.indexOf("TypeError") !== -1 && e.message.indexOf("readonly") !== -1)
+            threw = true;
+    }
+    if (threw)
+        testPassed("function threw exception: '" + f.toString() + "'");
+    else
+        testFailed("function did not throw: '" + f.toString() + "'");
+}
+function assert(b) {
+    if (!b)
+        testFailed("Invalid assertion.")
+    else
+        testPassed("Assertion passed.");
+}
+
 
 shouldThrow("const redef='a'; const redef='a';");
 
 const x = "RIGHT";
-x = "WRONG";
-shouldBe("x", '"RIGHT"');
+shouldThrowInvalidConstAssignment(function() { x = "WRONG"; });
+assert(x === "RIGHT");
+
 
 const z = "RIGHT", y = "RIGHT";
-y = "WRONG";
-shouldBe("y", '"RIGHT"');
+shouldThrowInvalidConstAssignment(function() { y = "WRONG"; });
+assert(y === "RIGHT");
 
 const one = 1;
 
-var a;
+var a = null;
 
 // PostIncResolveNode
-a = one++;
-shouldBe("a", "1");
-shouldBe("one", "1");
+shouldThrowInvalidConstAssignment(function() { a = one++; });
+assert(a === null);
+assert(one === 1);
 
 // PostDecResolveNode
-a = one--;
-shouldBe("a", "1");
-shouldBe("one", "1");
+shouldThrowInvalidConstAssignment(function() { a = one--; });
+assert(a === null);
+assert(one === 1);
 
 // PreIncResolveNode
-a = ++one;
-shouldBe("a", "2");
-shouldBe("one", "1");
+shouldThrowInvalidConstAssignment(function() { a = ++one; });
+assert(a === null);
+assert(one === 1);
 
 // PreDecResolveNode
-a = --one;
-shouldBe("a", "0");
-shouldBe("one", "1");
+shouldThrowInvalidConstAssignment(function() { a = --one; });
+assert(a === null);
+assert(one === 1);
 
 // ReadModifyConstNode
-a = one += 2;
-shouldBe("a", "3");
-shouldBe("one", "1");
+shouldThrowInvalidConstAssignment(function() { a = one += 2; });
+assert(a === null);
+assert(one === 1);
 
 // AssignConstNode
-a = one = 2;
-shouldBe("a", "2");
-shouldBe("one", "1");
+shouldThrowInvalidConstAssignment(function() { a = one = 2; });
+assert(a === null);
+assert(one === 1);
 
 // PostIncResolveNode
-shouldBe("function f() { const one = 1; one++; return one; } f();", "1");
-shouldBe("function f() { const oneString = '1'; return oneString++; } f();", "1");
-shouldBe("function f() { const one = 1; return one++; } f();", "1");
+shouldThrow("function f() { const one = 1; one++; return one; } f();");
+shouldThrow("function f() { const oneString = '1'; return oneString++; } f();");
+shouldThrow("function f() { const one = 1; return one++; } f();");
 
 // PostDecResolveNode
-shouldBe("function f() { const one = 1; one--; return one; } f();", "1");
-shouldBe("function f() { const oneString = '1'; return oneString--; } f();", "1");
-shouldBe("function f() { const one = 1; return one--; } f();", "1");
+shouldThrow("function f() { const one = 1; one--; return one; } f();");
+shouldThrow("function f() { const oneString = '1'; return oneString--; } f();");
+shouldThrow("function f() { const one = 1; return one--; } f();");
 
 // PreIncResolveNode
-shouldBe("function f() { const one = 1; ++one; return one; } f();", "1");
-shouldBe("function f() { const one = 1; return ++one; } f();", "2");
+shouldThrow("function f() { const one = 1; ++one; return one; } f();");
+shouldThrow("function f() { const one = 1; return ++one; } f();");
 
 // PreDecResolveNode
-shouldBe("function f() { const one = 1; --one; return one; } f();", "1");
-shouldBe("function f() { const one = 1; return --one; } f();", "0");
+shouldThrow("function f() { const one = 1; --one; return one; } f();");
+shouldThrow("function f() { const one = 1; return --one; } f();");
 
 // ReadModifyConstNode
-shouldBe("function f() { const one = 1; one += 2; return one; } f();", "1");
-shouldBe("function f() { const one = 1; return one += 2; } f();", "3");
+shouldThrow("function f() { const one = 1; one += 2; return one; } f();");
+shouldThrow("function f() { const one = 1; return one += 2; } f();");
 
 // AssignConstNode
-shouldBe("function f() { const one = 1; one = 2; return one; } f();", "1");
-shouldBe("function f() { const one = 1; return one = 2; } f();", "2");
-
-// PostIncResolveNode
-shouldBe("one++", "1");
-shouldBe("one", "1");
-
-// PostDecResolveNode
-shouldBe("one--", "1");
-shouldBe("one", "1");
-
-// PreIncResolveNode
-shouldBe("++one", "2");
-shouldBe("one", "1");
+shouldThrow("function f() { const one = 1; one = 2; return one; } f();");
+shouldThrow("function f() { const one = 1; return one = 2; } f();");
 
-// PreDecResolveNode
-shouldBe("--one", "0");
-shouldBe("one", "1");
-
-// ReadModifyConstNode
-shouldBe("one += 1", "2");
-shouldBe("one", "1");
-
-// AssignConstNode
-shouldBe("one = 2", "2");
-shouldBe("one", "1");
-
-var object = { inWith1: "RIGHT", inWith2: ""}
+var object = { inWith1: "a", inWith2: "b"}
 with (object) {
-    const inWith1 = "WRONG";
-    const inWith2 = "RIGHT";
-    inWith2 = "WRONG";
+    const inWith1 = "hello";
+    const inWith2 = "world";
+    assert(inWith1 === "hello");
+    assert(inWith2 === "world");
 }
-shouldBe("object.inWith1", "'RIGHT'");
-shouldBe("inWith2", "'RIGHT'");
+shouldBe("object.inWith1", "'a'");
+shouldBe("object.inWith2", "'b'");
 
-shouldBe("(function(){ one = 2; return one; })()", "1")
 var f = function g() { g="FAIL"; return g; };
 shouldBe("f()", "f");
 
-shouldBe("const a;", "undefined");
-
 // Make sure that dynamic scopes (catch, with) don't break const declarations
 function tryCatch1() {
-    var bar;
+    var bar = null;
     eval("try {\
         stuff();\
     } catch (e) {\
@@ -124,7 +119,7 @@ function tryCatch1() {
 }
 
 function tryCatch2() {
-    var bar;
+    var bar = null;
     try {
         stuff();
     } catch (e) {
@@ -134,51 +129,36 @@ function tryCatch2() {
 }
 
 tryCatch1Result = tryCatch1();
-shouldBe("tryCatch1Result", "5");
+shouldBe("tryCatch1Result", "null");
 tryCatch2Result = tryCatch2();
-shouldBe("tryCatch2Result", "5");
+shouldBe("tryCatch2Result", "null");
 
 function with1() {
-    var bar;
+    var bar = null;
     eval("with({foo:42}) { const bar = 5; }");
     return bar;
 }
 
 function with2() {
-    var bar;
+    var bar = null;
     with({foo:42}) { const bar = 5; }
     return bar;
 }
 
 with1Result = with1();
-shouldBe("with1Result", "5");
+shouldBe("with1Result", "null");
 with2Result = with2();
-shouldBe("with2Result", "5");
+shouldBe("with2Result", "null");
 
 (function () {
-    function shouldBe(aDescription, a, b)
-    {
-        if (a === b) {
-            testPassed("PASS: " + aDescription + " should be " + b + " and is.");
-            return;
-        }
-
-        testFailed("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
-    }
-
     (function() {
         const x = "1";
-        shouldBe("++x", ++x, 2);
-        shouldBe("--x", --x, 0);
-        shouldBe("x", x, "1");
-        shouldBe("x++", x++, 1);
-        shouldBe("x", x, "1");
-    })();
-    (function() {
-        const x = 1;
-        shouldBe("++x", ++x, 2);
-        shouldBe("x", x, 1);
-        shouldBe("x++", x++, 1);
-        shouldBe("x", x, 1);
+        shouldThrowInvalidConstAssignment(function() { ++x; });
+        assert(x === "1");
+        shouldThrowInvalidConstAssignment(function() { x++; });
+        assert(x === "1");
+        shouldThrowInvalidConstAssignment(function() { x--; });
+        assert(x === "1");
+        shouldThrowInvalidConstAssignment(function() { --x; });
     })();
 })();
index 121875d..52354e8 100644 (file)
@@ -2,21 +2,29 @@ description(
 "This test checks exceptional cases for constant counting in the parser."
 );
 
-const a;
-const b;
---a;
---b;
+const a = 15;
+const b = 25;
+try {
+    --a;
+    --b;
+} catch(e) { }
 
-shouldBe("a", "undefined");
+if (a !== 15)
+    testFailed("Unexpected result for 'a'");
+else
+    testPassed("'a' is all good");
 
 function f()
 {
-    const a;
-    const b;
-    --a;
-    --b;
+    const a = 10;
+    const b = 20;
+    try {
+    } catch(e) {
+        a--;
+        b--;
+    }
 
     return a;
 }
 
-shouldBe("f()", "undefined");
+shouldBe("f()", "10");
index e765993..7c91e99 100644 (file)
@@ -120,7 +120,7 @@ function assignConstInitTest2()
         return assignConstInitTest2.arguments;
     }
 
-    const a, arguments = true;
+    const a = 5, arguments = true;
     return g();
 }
 shouldBe("assignConstInitTest2().toString()", "'[object Arguments]'");
index 62555aa..d648b4e 100644 (file)
@@ -201,8 +201,8 @@ shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2, c = 3')", "'var a =
 
 shouldBe("compileAndSerializeLeftmostTest('const a = 1')", "'const a = 1'");
 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2)')", "'const a = (1, 2)'");
-shouldBe("compileAndSerializeLeftmostTest('const a, b = 1')", "'const a, b = 1'");
-shouldBe("compileAndSerializeLeftmostTest('const a = 1, b')", "'const a = 1, b'");
+shouldBe("compileAndSerializeLeftmostTest('const a = 10, b = 1')", "'const a = 10, b = 1'");
+shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = 2')", "'const a = 1, b = 2'");
 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = 1')", "'const a = 1, b = 1'");
 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = 1')", "'const a = (1, 2), b = 1'");
 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = (1, 2)')", "'const a = 1, b = (1, 2)'");
index b9747cc..f9b482b 100644 (file)
@@ -232,23 +232,25 @@ invalid("throw");
 debug  ("var and const statements");
 
 valid  ("var a, b = null");
-valid  ("const a = 5, b, c");
+valid  ("const a = 5, b = 10, c = 20");
 invalid("var");
 invalid("var = 7");
 invalid("var c (6)");
-valid  ("if (a) var a,b; else { const b, c }");
+valid  ("if (a) var a,b; else { const b = 1, c = 2; }");
+invalid("if (a) var a,b; else { const b, c }");
 invalid("var 5 = 6");
 valid  ("while (0) var a, b, c=6, d, e, f=5*6, g=f*h, h");
 invalid("var a = if (b) { c }");
 invalid("var a = var b");
-valid  ("const a = b += c, a, a, a = (b - f())");
+invalid("const a = b += c, a, a, a = (b - f())");
 invalid("var a %= b | 5");
 invalid("var (a) = 5");
 invalid("var a = (4, b = 6");
 invalid("const 'l' = 3");
 invalid("var var = 3");
 valid  ("var varr = 3 in 1");
-valid  ("const a, a, a = void 7 - typeof 8, a = 8");
+valid  ("const  a = void 7 - typeof 8, b = 8");
+invalid("const a, a, a = void 7 - typeof 8, a = 8");
 valid  ("const x_x = 6 /= 7 ? e : f");
 invalid("var a = ?");
 invalid("const a = *7");
@@ -291,7 +293,21 @@ valid  ("for (var a = b, b = a ; ; ) break");
 valid  ("for (var a = b, c, d, b = a ; x in b ; ) { break }");
 valid  ("for (var a = b, c, d ; ; 1 in a()) break");
 invalid("for ( ; var a ; ) break");
-invalid("for (const a; ; ) break");
+invalid("for (const x; ; ) break");
+invalid("for (const x = 20, y; ; ) break");
+valid  ("for (const x = 20; ; ) break");
+valid  ("for (const x of []) break");
+valid  ("for (const x in {}) break");
+invalid("for (const x = 20, x = 30; ; ) { const x = 20; break; }");
+valid  ("for (const x = 20; ; ) { const x = 20; break; }");
+valid  ("for (const x of []) { const x = 20; break; }");
+valid  ("for (const x in {}) { const x = 20; break; }");
+invalid("for (const let = 10; ; ) { break; }");
+invalid("for (const let in {}) { break; }");
+invalid("for (const let of []) { break; }");
+invalid("for (let let = 10; ; ) { break; }");
+invalid("for (let let in {}) { break; }");
+invalid("for (let let of []) { break; }");
 invalid("for ( %a ; ; ) { }");
 valid  ("for (a in b) break");
 valid  ("for (a() in b) break");
index 58eb24a..175b17d 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected token '='. Expected an identifier name in const declaration.
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected token '='. Expected a parameter pattern or a ')' in parameter list.
 S7.5.3_A1.6
 
 PASS Expected parsing failure
index 7414d5f..dcd60f6 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected identifier '\u0067'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected identifier '\u0067'. Expected ';' after variable declaration.
 S7.8.5_A3.1_T7
 
 FAIL successfullyParsed is not set
index a951ccc..5753629 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected identifier '\u0069'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected identifier '\u0069'. Expected ';' after variable declaration.
 S7.8.5_A3.1_T8
 
 FAIL successfullyParsed is not set
index 46dc13c..ce9b386 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected identifier '\u006D'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected identifier '\u006D'. Expected ';' after variable declaration.
 S7.8.5_A3.1_T9
 
 FAIL successfullyParsed is not set
index a34bda6..410dd5c 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected string literal ''. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected string literal ''. Expected ';' after variable declaration.
 S8.4_A13_T3
 
 PASS Expected parsing failure
index cae8ea7..fe5a9f1 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected string literal "". Expected ';' after var declaration.
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected string literal "". Expected ';' after variable declaration.
 S8.4_A14_T3
 
 PASS Expected parsing failure
index 5b430ff..8b9a28a 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '+='. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '+='. Expected ';' after variable declaration.
 S12.2_A8_T1
 
 PASS Expected parsing failure
index 4433fb7..3b3efa2 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '|'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '|'. Expected ';' after variable declaration.
 S12.2_A8_T2
 
 PASS Expected parsing failure
index b32d1a1..d05a38d 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '&&'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '&&'. Expected ';' after variable declaration.
 S12.2_A8_T3
 
 PASS Expected parsing failure
index 67e5619..7e9bb63 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '++'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '++'. Expected ';' after variable declaration.
 S12.2_A8_T4
 
 PASS Expected parsing failure
index 897b049..7704f6d 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '*'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '*'. Expected ';' after variable declaration.
 S12.2_A8_T6
 
 PASS Expected parsing failure
index 324bbcd..abaf4cc 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '>>'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '>>'. Expected ';' after variable declaration.
 S12.2_A8_T7
 
 PASS Expected parsing failure
index f0c305e..9f87d54 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 80: SyntaxError: Unexpected keyword 'in'. Expected ';' after var declaration.
+CONSOLE MESSAGE: line 80: SyntaxError: Unexpected keyword 'in'. Expected ';' after variable declaration.
 S12.2_A8_T8
 
 PASS Expected parsing failure
index c1e7ce1..de92352 100644 (file)
@@ -43,7 +43,7 @@
   </style>
   <script src="resources/hit-test-utils.js"></script>
   <script>
-    const hitTestData = [
+    var hitTestData = [
       { 'point': [48, 48], 'target' : 'container' },
       { 'point': [75, 75], 'target' : 'target' },
       { 'point': [100, 100], 'target' : 'target' },
index a6311ad..5fa7741 100644 (file)
@@ -50,7 +50,7 @@
 
   <script src="resources/hit-test-utils.js"></script>
   <script>
-    const hitTestData = [
+    var hitTestData = [
         { 'point': [98, 200], 'target' : 'background' },
         { 'point': [302, 200], 'target' : 'background' },
         { 'point': [200, 98], 'target' : 'background' },
index dd23690..b844595 100644 (file)
@@ -22,7 +22,7 @@
 
                <script src="resources/hit-test-utils.js"></script>
                <script>
-                       const hitTestData = [
+                       var hitTestData = [
                                { 'point': [70, 70], 'target' : 'transformed' },
                                { 'point': [630, 130], 'target' : 'transformed' },
                                { 'point': [40, 130], 'target' : 'transformed' },
@@ -39,4 +39,4 @@
 
                <div id="results"></div>
        </body>
-</html>
\ No newline at end of file
+</html>
index 7cf2065..1ff992e 100644 (file)
@@ -37,7 +37,7 @@
 
                <script src="resources/hit-test-utils.js"></script>
                <script>
-                       const hitTestData = [
+                       var hitTestData = [
                                { 'point': [70, 70], 'target' : 'transformed' },
                                { 'point': [630, 130], 'target' : 'transformed' },
                                { 'point': [40, 130], 'target' : 'transformed' },
@@ -62,4 +62,4 @@
 
                <div id="results"></div>
        </body>
-</html>
\ No newline at end of file
+</html>
index 927dae0..a24be6a 100644 (file)
@@ -29,7 +29,7 @@
        </style>
        <script src="resources/hit-test-utils.js"></script>
        <script>
-                       const hitTestData = [
+                       var hitTestData = [
                                { 'point': [50, 50], 'target' : 'container' },
                                { 'point': [60, 60], 'target' : 'container' },
                                { 'point': [70, 70], 'target' : 'target' },
index b3092c8..02bcfec 100644 (file)
@@ -61,7 +61,7 @@
        </style>
        <script src="resources/hit-test-utils.js"></script>
        <script>
-               const hitTestData = [
+               var hitTestData = [
 
                        { 'point': [10, 100], 'target' : 'container-nopreserve' },
                        { 'point': [20, 100], 'target' : 'target2' },
index 7001c54..04a065e 100644 (file)
@@ -60,7 +60,7 @@
   </style>
   <script src="resources/hit-test-utils.js"></script>
   <script>
-      const hitTestData = [
+      var hitTestData = [
         // Points near the corners of the top layer
         { 'point': [35, 100], 'target' : 'topLayer' },
         { 'point': [370, 100], 'target' : 'topLayer' },
index bfe5bfc..48aa033 100644 (file)
@@ -42,7 +42,7 @@
   </style>
   <script src="resources/hit-test-utils.js"></script>
   <script>
-    const hitTestData = [
+    var hitTestData = [
       { 'point': [30, 30], 'target' : 'box1' },
       { 'point': [80, 100], 'target' : 'box1' },
       { 'point': [100, 120], 'target' : 'box2' },
index 52cc7d4..5e53fbd 100644 (file)
@@ -46,7 +46,7 @@
   </style>
   <script src="resources/hit-test-utils.js"></script>
   <script>
-      const hitTestData = [
+      var hitTestData = [
         { 'point': [85, 100], 'target' : 'left' },
         { 'point': [155, 80], 'target' : 'top' },
         { 'point': [230, 80], 'target' : 'right' },
index c008bbb..ba84664 100644 (file)
@@ -51,7 +51,7 @@
   </style>
   <script src="resources/hit-test-utils.js"></script>
   <script>
-      const hitTestData = [
+      var hitTestData = [
         { 'point': [170, 250], 'target' : 'left' },
         { 'point': [260, 170], 'target' : 'top' },
         { 'point': [330, 250], 'target' : 'right' },
index 793460e..6901aca 100644 (file)
@@ -21,11 +21,11 @@ Function parameters:
 
 */
 
-const usePauseAPI = true;
-const dontUsePauseAPI = false;
+var usePauseAPI = true;
+var dontUsePauseAPI = false;
 
-const shouldBeTransitioning = true;
-const shouldNotBeTransitioning = false;
+var shouldBeTransitioning = true;
+var shouldNotBeTransitioning = false;
 
 function roundNumber(num, decimalPlaces)
 {
index dc91c1b..1334035 100644 (file)
@@ -1,5 +1,207 @@
 2015-07-18  Saam barati  <saambarati1@gmail.com>
 
+        [ES6] Add support for block scope const
+        https://bugs.webkit.org/show_bug.cgi?id=31813
+
+        Reviewed by Filip Pizlo.
+
+        '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):
+        (.):
+
+2015-07-18  Saam barati  <saambarati1@gmail.com>
+
         lexical scoping is broken with respect to "break" and "continue"
         https://bugs.webkit.org/show_bug.cgi?id=147063
 
index 6692cfb..1b6fa8d 100644 (file)
@@ -56,8 +56,6 @@
             { "name" : "op_is_object_or_null", "length" : 3 },
             { "name" : "op_is_function", "length" : 3 },
             { "name" : "op_in", "length" : 4 },
-            { "name" : "op_init_global_const_nop", "length" : 5 },
-            { "name" : "op_init_global_const", "length" : 5 },
             { "name" : "op_get_by_id", "length" : 9  },
             { "name" : "op_get_by_id_out_of_line", "length" : 9  },
             { "name" : "op_get_array_length", "length" : 9 },
index 413d84f..67c83b3 100644 (file)
@@ -116,8 +116,6 @@ void computeUsesForBytecodeOffset(
     case op_get_enumerable_length:
     case op_new_func_exp:
     case op_to_index_string:
-    case op_init_global_const_nop:
-    case op_init_global_const:
     case op_push_name_scope:
     case op_push_with_scope:
     case op_create_lexical_environment:
@@ -240,8 +238,6 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     OpcodeID opcodeID = interpreter->getOpcodeID(instruction->u.opcode);
     switch (opcodeID) {
     // These don't define anything.
-    case op_init_global_const:
-    case op_init_global_const_nop:
     case op_put_to_scope:
     case op_end:
     case op_profile_will_call:
index 00eb283..d1124a7 100644 (file)
@@ -1052,23 +1052,6 @@ void CodeBlock::dumpBytecode(
             printBinaryOp(out, exec, location, it, "in");
             break;
         }
-        case op_init_global_const_nop: {
-            printLocationAndOp(out, exec, location, it, "init_global_const_nop");
-            it++;
-            it++;
-            it++;
-            it++;
-            break;
-        }
-        case op_init_global_const: {
-            WriteBarrier<Unknown>* variablePointer = (++it)->u.variablePointer;
-            int r0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "init_global_const");
-            out.printf("g%d(%p), %s", m_globalObject->findVariableIndex(variablePointer).offset(), variablePointer, registerName(r0).data());
-            it++;
-            it++;
-            break;
-        }
         case op_get_by_id:
         case op_get_by_id_out_of_line:
         case op_get_array_length: {
@@ -1979,18 +1962,6 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
         case op_get_array_length:
             CRASH();
 
-        case op_init_global_const_nop: {
-            ASSERT(codeType() == GlobalCode);
-            Identifier ident = identifier(pc[4].u.operand);
-            SymbolTableEntry entry = m_globalObject->symbolTable()->get(ident.impl());
-            if (entry.isNull())
-                break;
-
-            instructions[i + 0] = vm()->interpreter->getOpcode(op_init_global_const);
-            instructions[i + 1] = &m_globalObject->variableAt(entry.varOffset().scopeOffset());
-            break;
-        }
-
         case op_resolve_scope: {
             const Identifier& ident = identifier(pc[3].u.operand);
             ResolveType type = static_cast<ResolveType>(pc[4].u.operand);
index 8e91d49..1940d94 100644 (file)
@@ -190,10 +190,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP
         m_functionsToInitialize.append(std::make_pair(function, GlobalFunctionVariable));
     }
     if (Options::validateBytecode()) {
-        for (auto& entry : programNode->varDeclarations()) {
-            // FIXME: When supporting ES6 spec compliant const, this should only check isVar().
-            RELEASE_ASSERT(entry.value.isVar() || entry.value.isConstant());
-        }
+        for (auto& entry : programNode->varDeclarations())
+            RELEASE_ASSERT(entry.value.isVar());
     }
     codeBlock->setVariableDeclarations(programNode->varDeclarations());
 }
@@ -411,20 +409,18 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     
     // Now declare all variables.
     for (const Identifier& ident : boundParameterProperties)
-        createVariable(ident, varKind(ident.impl()), IsVariable);
+        createVariable(ident, varKind(ident.impl()));
     for (FunctionBodyNode* function : functionNode->functionStack()) {
         const Identifier& ident = function->ident();
-        createVariable(ident, varKind(ident.impl()), IsVariable);
+        createVariable(ident, varKind(ident.impl()));
         m_functionsToInitialize.append(std::make_pair(function, NormalFunctionVariable));
     }
     for (auto& entry : functionNode->varDeclarations()) {
-        if (!entry.value.isVar())
+        ASSERT(!entry.value.isLet() && !entry.value.isConst());
+        if (!entry.value.isVar()) // This is either a parameter or callee.
             continue;
-        ConstantMode constantMode = modeForIsConstant(entry.value.isConstant());
         // Variables named "arguments" are never const.
-        if (Identifier::fromUid(m_vm, entry.key.get()) == propertyNames().arguments)
-            constantMode = IsVariable;
-        createVariable(Identifier::fromUid(m_vm, entry.key.get()), varKind(entry.key.get()), constantMode, IgnoreExisting);
+        createVariable(Identifier::fromUid(m_vm, entry.key.get()), varKind(entry.key.get()), IgnoreExisting);
     }
     
     // There are some variables that need to be preinitialized to something other than Undefined:
@@ -500,7 +496,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
         
         if (!haveParameterNamedArguments) {
             createVariable(
-                propertyNames().arguments, varKind(propertyNames().arguments.impl()), IsVariable);
+                propertyNames().arguments, varKind(propertyNames().arguments.impl()));
             m_needToInitializeArguments = true;
         }
     }
@@ -559,7 +555,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
     Vector<Identifier, 0, UnsafeVectorOverflow> variables;
     variables.reserveCapacity(numVariables);
     for (auto& entry : varDeclarations) {
-        ASSERT(entry.value.isVar() || entry.value.isConstant()); // FIXME: When supporting ES6 spec compliant const, this should only check isVar().
+        ASSERT(entry.value.isVar());
         ASSERT(entry.key->isAtomic() || entry.key->isSymbol());
         variables.append(Identifier::fromUid(m_vm, entry.key.get()));
     }
@@ -1281,7 +1277,8 @@ void BytecodeGenerator::pushLexicalScope(VariableEnvironmentNode* node, bool can
     {
         ConcurrentJITLocker locker(symbolTable->m_lock);
         for (auto entry : environment) {
-            ASSERT(entry.value.isLet() && !entry.value.isVar());
+            ASSERT(entry.value.isLet() || entry.value.isConst());
+            ASSERT(!entry.value.isVar());
             SymbolTableEntry symbolTableEntry = symbolTable->get(locker, entry.key.get());
             ASSERT(symbolTableEntry.isNull());
 
@@ -1296,8 +1293,8 @@ void BytecodeGenerator::pushLexicalScope(VariableEnvironmentNode* node, bool can
                 local->ref();
                 varOffset = VarOffset(local->virtualRegister());
             }
-            // FIXME: Make this work with 'const' variables: https://bugs.webkit.org/show_bug.cgi?id=31813 
-            SymbolTableEntry newEntry(varOffset, 0);
+
+            SymbolTableEntry newEntry(varOffset, entry.value.isConst() ? ReadOnly : 0);
             symbolTable->add(locker, entry.key.get(), newEntry);
         }
     }
@@ -1416,7 +1413,7 @@ void BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration(VariableEnvir
 
             RegisterID* transitionValue = newBlockScopeVariable();
             transitionValue->ref();
-            emitGetFromScope(transitionValue, loopScope, variableForLocalEntry(identifier, ptr->value, loopSymbolTable->index()), DoNotThrowIfNotFound);
+            emitGetFromScope(transitionValue, loopScope, variableForLocalEntry(identifier, ptr->value, loopSymbolTable->index(), true), DoNotThrowIfNotFound);
             activationValuesToCopyOver.uncheckedAppend(std::make_pair(transitionValue, identifier));
         }
     }
@@ -1445,7 +1442,7 @@ void BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration(VariableEnvir
             SymbolTableEntry entry = symbolTable->get(locker, identifier.impl());
             RELEASE_ASSERT(!entry.isNull());
             RegisterID* transitionValue = pair.first;
-            emitPutToScope(loopScope, variableForLocalEntry(identifier, entry, loopSymbolTable->index()), transitionValue, DoNotThrowIfNotFound);
+            emitPutToScope(loopScope, variableForLocalEntry(identifier, entry, loopSymbolTable->index(), true), transitionValue, DoNotThrowIfNotFound);
             transitionValue->deref();
         }
     }
@@ -1454,9 +1451,8 @@ void BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration(VariableEnvir
 Variable BytecodeGenerator::variable(const Identifier& property)
 {
     if (property == propertyNames().thisIdentifier) {
-        return Variable(
-            property, VarOffset(thisRegister()->virtualRegister()), thisRegister(),
-            ReadOnly, Variable::SpecialVariable, 0);
+        return Variable(property, VarOffset(thisRegister()->virtualRegister()), thisRegister(),
+            ReadOnly, Variable::SpecialVariable, 0, false);
     }
     
     // We can optimize lookups if the lexical variable is found before a "with" or "catch"
@@ -1487,25 +1483,14 @@ Variable BytecodeGenerator::variable(const Identifier& property)
         if (symbolTableEntry.isNull())
             continue;
         
-        return variableForLocalEntry(property, symbolTableEntry, stackEntry.m_symbolTableConstantIndex);
+        return variableForLocalEntry(property, symbolTableEntry, stackEntry.m_symbolTableConstantIndex, symbolTable->correspondsToLexicalScope());
     }
 
     return Variable(property);
 }
 
-Variable BytecodeGenerator::variablePerSymbolTable(const Identifier& property)
-{
-    RELEASE_ASSERT(m_symbolTableStack.size());
-    SymbolTableStackEntry& baseActivationEntry = m_symbolTableStack.first();
-    SymbolTableEntry entry = baseActivationEntry.m_symbolTable->get(property.impl());
-    if (entry.isNull())
-        return Variable(property);
-    
-    return variableForLocalEntry(property, entry, baseActivationEntry.m_symbolTableConstantIndex);
-}
-
 Variable BytecodeGenerator::variableForLocalEntry(
-    const Identifier& property, const SymbolTableEntry& entry, int symbolTableConstantIndex)
+    const Identifier& property, const SymbolTableEntry& entry, int symbolTableConstantIndex, bool isLexicallyScoped)
 {
     VarOffset offset = entry.varOffset();
     
@@ -1515,12 +1500,11 @@ Variable BytecodeGenerator::variableForLocalEntry(
     else
         local = nullptr;
     
-    return Variable(property, offset, local, entry.getAttributes(), Variable::NormalVariable, symbolTableConstantIndex);
+    return Variable(property, offset, local, entry.getAttributes(), Variable::NormalVariable, symbolTableConstantIndex, isLexicallyScoped);
 }
 
 void BytecodeGenerator::createVariable(
-    const Identifier& property, VarKind varKind, ConstantMode constantMode,
-    ExistingVariableMode existingVariableMode)
+    const Identifier& property, VarKind varKind, ExistingVariableMode existingVariableMode)
 {
     ASSERT(property != propertyNames().thisIdentifier);
     ConcurrentJITLocker locker(symbolTable().m_lock);
@@ -1536,10 +1520,10 @@ void BytecodeGenerator::createVariable(
         VarOffset offset = entry.varOffset();
         
         // We can't change our minds about whether it's captured.
-        if (offset.kind() != varKind || constantMode != entry.constantMode()) {
+        if (offset.kind() != varKind) {
             dataLog(
-                "Trying to add variable called ", property, " as ", varKind, "/", constantMode,
-                " but it was already added as ", offset, "/", entry.constantMode(), ".\n");
+                "Trying to add variable called ", property, " as ", varKind,
+                " but it was already added as ", offset, ".\n");
             RELEASE_ASSERT_NOT_REACHED();
         }
 
@@ -1553,7 +1537,7 @@ void BytecodeGenerator::createVariable(
         ASSERT(varKind == VarKind::Stack);
         varOffset = VarOffset(virtualRegisterForLocal(m_calleeRegisters.size()));
     }
-    SymbolTableEntry newEntry(varOffset, constantMode == IsConstant ? ReadOnly : 0);
+    SymbolTableEntry newEntry(varOffset, 0);
     symbolTable().add(locker, property.impl(), newEntry);
     
     if (varKind == VarKind::Stack) {
@@ -1606,18 +1590,12 @@ RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Variable&
             SymbolTableStackEntry& stackEntry = m_symbolTableStack[i];
             // We should not resolve a variable to VarKind::Scope if a "with" or "catch" scope lies in between the current
             // scope and the resolved scope.
-            // We'd like to say: RELEASE_ASSERT(!stackEntry.m_isWithOrCatch);
-            // But, our current implementation 'const' is a pile of crap and uses variablePerSymbolTable
-            // which recklessly ignores the scope stack.
-            // FIXME: When implementing const the proper way ensure we add this assert in.
-            // https://bugs.webkit.org/show_bug.cgi?id=143654
-            if (stackEntry.m_isWithOrCatch)
-                continue;
+            RELEASE_ASSERT(!stackEntry.m_isWithOrCatch);
 
             if (stackEntry.m_symbolTable->get(variable.ident().impl()).isNull())
                 continue;
             
-            RegisterID* scope = stackEntry.m_scope; 
+            RegisterID* scope = stackEntry.m_scope;
             RELEASE_ASSERT(scope);
             return scope;
         }
@@ -1738,17 +1716,6 @@ RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitInitGlobalConst(const Identifier& identifier, RegisterID* value)
-{
-    ASSERT(m_codeType == GlobalCode);
-    emitOpcode(op_init_global_const_nop);
-    instructions().append(0);
-    instructions().append(value->index());
-    instructions().append(0);
-    instructions().append(addConstant(identifier));
-    return value;
-}
-
 RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
 {
     m_codeBlock->addPropertyAccessInstruction(instructions().size());
@@ -3085,13 +3052,15 @@ bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNu
     return registerID->index() == CallFrame::argumentOffset(argumentNumber);
 }
 
-void BytecodeGenerator::emitReadOnlyExceptionIfNeeded()
+bool BytecodeGenerator::emitReadOnlyExceptionIfNeeded(const Variable& variable)
 {
-    if (!isStrictMode())
-        return;
-    emitOpcode(op_throw_static_error);
-    instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, StrictModeReadonlyPropertyWriteError)))->index());
-    instructions().append(false);
+    if (isStrictMode() || variable.isConst()) {
+        emitOpcode(op_throw_static_error);
+        instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, StrictModeReadonlyPropertyWriteError)))->index());
+        instructions().append(false);
+        return true;
+    }
+    return false;
 }
     
 void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack, VariableEnvironmentNode* forLoopNode, RegisterID* forLoopSymbolTable)
index 69a5811..e3a9397 100644 (file)
@@ -194,6 +194,7 @@ namespace JSC {
             , m_attributes(0)
             , m_kind(NormalVariable)
             , m_symbolTableConstantIndex(0) // This is meaningless here for this kind of Variable.
+            , m_isLexicallyScoped(false)
         {
         }
         
@@ -203,16 +204,18 @@ namespace JSC {
             , m_attributes(0)
             , m_kind(NormalVariable) // This is somewhat meaningless here for this kind of Variable.
             , m_symbolTableConstantIndex(0) // This is meaningless here for this kind of Variable.
+            , m_isLexicallyScoped(false)
         {
         }
 
-        Variable(const Identifier& ident, VarOffset offset, RegisterID* local, unsigned attributes, VariableKind kind, int symbolTableConstantIndex)
+        Variable(const Identifier& ident, VarOffset offset, RegisterID* local, unsigned attributes, VariableKind kind, int symbolTableConstantIndex, bool isLexicallyScoped)
             : m_ident(ident)
             , m_offset(offset)
             , m_local(local)
             , m_attributes(attributes)
             , m_kind(kind)
             , m_symbolTableConstantIndex(symbolTableConstantIndex)
+            , m_isLexicallyScoped(isLexicallyScoped)
         {
         }
 
@@ -230,6 +233,7 @@ namespace JSC {
 
         bool isReadOnly() const { return m_attributes & ReadOnly; }
         bool isSpecial() const { return m_kind != NormalVariable; }
+        bool isConst() const { return isReadOnly() && m_isLexicallyScoped; }
 
     private:
         Identifier m_ident;
@@ -238,6 +242,7 @@ namespace JSC {
         unsigned m_attributes;
         VariableKind m_kind;
         int m_symbolTableConstantIndex;
+        bool m_isLexicallyScoped;
     };
 
     struct TryRange {
@@ -286,11 +291,8 @@ namespace JSC {
 
         Variable variable(const Identifier&);
         
-        // Ignores the possibility of intervening scopes.
-        Variable variablePerSymbolTable(const Identifier&);
-        
         enum ExistingVariableMode { VerifyExisting, IgnoreExisting };
-        void createVariable(const Identifier&, VarKind, ConstantMode, ExistingVariableMode = VerifyExisting); // Creates the variable, or asserts that the already-created variable is sufficiently compatible.
+        void createVariable(const Identifier&, VarKind, ExistingVariableMode = VerifyExisting); // Creates the variable, or asserts that the already-created variable is sufficiently compatible.
         
         // Returns the register storing "this"
         RegisterID* thisRegister() { return &m_thisRegister; }
@@ -488,8 +490,6 @@ namespace JSC {
         RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); }
         RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); }
 
-        RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value);
-
         RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
         RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
         RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType);
@@ -564,7 +564,7 @@ namespace JSC {
         RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node);
         void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node);
 
-        void emitReadOnlyExceptionIfNeeded();
+        bool emitReadOnlyExceptionIfNeeded(const Variable&);
 
         // Start a try block. 'start' must have been emitted.
         TryData* pushTry(Label* start);
@@ -628,7 +628,7 @@ namespace JSC {
 
     private:
         void reclaimFreeRegisters();
-        Variable variableForLocalEntry(const Identifier&, const SymbolTableEntry&, int);
+        Variable variableForLocalEntry(const Identifier&, const SymbolTableEntry&, int symbolTableConstantIndex, bool isLexicallyScoped);
 
         void emitOpcode(OpcodeID);
         UnlinkedArrayAllocationProfile newArrayAllocationProfile();
index bab8d7d..27a8468 100644 (file)
@@ -1065,7 +1065,7 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
         generator.emitTDZCheckIfNecessary(var, local, nullptr);
         RefPtr<RegisterID> localReg = local;
         if (var.isReadOnly()) {
-            generator.emitReadOnlyExceptionIfNeeded();
+            generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.emitMove(generator.tempDestination(dst), local);
         } else if (generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.finalDestination(dst);
@@ -1086,6 +1086,11 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
     RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
     RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     generator.emitTDZCheckIfNecessary(var, value.get(), nullptr);
+    if (var.isReadOnly()) {
+        bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+        if (threwException)
+            return value.get();
+    }
     RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
     generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
     if (generator.vm()->typeProfiler()) {
@@ -1269,7 +1274,7 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
         generator.emitTDZCheckIfNecessary(var, local, nullptr);
         RefPtr<RegisterID> localReg = local;
         if (var.isReadOnly()) {
-            generator.emitReadOnlyExceptionIfNeeded();
+            generator.emitReadOnlyExceptionIfNeeded(var);
             localReg = generator.emitMove(generator.tempDestination(dst), localReg.get());
         } else if (generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
@@ -1288,6 +1293,11 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
     RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var);
     RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     generator.emitTDZCheckIfNecessary(var, value.get(), nullptr);
+    if (var.isReadOnly()) {
+        bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+        if (threwException)
+            return value.get();
+    }
 
     emitIncOrDec(generator, value.get(), m_operator);
     generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
@@ -1788,7 +1798,7 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
     if (RegisterID* local = var.local()) {
         generator.emitTDZCheckIfNecessary(var, local, nullptr);
         if (var.isReadOnly()) {
-            generator.emitReadOnlyExceptionIfNeeded();
+            generator.emitReadOnlyExceptionIfNeeded(var);
             return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
         }
         
@@ -1813,6 +1823,11 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
     RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
     RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound);
     generator.emitTDZCheckIfNecessary(var, value.get(), nullptr);
+    if (var.isReadOnly()) {
+        bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+        if (threwException)
+            return value.get();
+    }
     RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
     RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound);
     if (generator.vm()->typeProfiler()) {
@@ -1831,8 +1846,9 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
         RegisterID* result = nullptr;
         if (m_assignmentContext == AssignmentContext::AssignmentExpression)
             generator.emitTDZCheckIfNecessary(var, local, nullptr);
-        if (var.isReadOnly()) {
-            generator.emitReadOnlyExceptionIfNeeded();
+
+        if (var.isReadOnly() && m_assignmentContext != AssignmentContext::ConstDeclarationStatement) {
+            generator.emitReadOnlyExceptionIfNeeded(var);
             result = generator.emitNode(dst, m_right);
         } else if (var.isSpecial() || generator.vm()->typeProfiler()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
@@ -1848,7 +1864,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
             result = generator.moveToDestinationIfNeeded(dst, right);
         }
 
-        if (m_assignmentContext == AssignmentContext::DeclarationStatement)
+        if (m_assignmentContext == AssignmentContext::DeclarationStatement || m_assignmentContext == AssignmentContext::ConstDeclarationStatement)
             generator.liftTDZCheckIfPossible(var);
         return result;
     }
@@ -1861,6 +1877,11 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
     if (dst == generator.ignoredResult())
         dst = 0;
     RefPtr<RegisterID> result = generator.emitNode(dst, m_right);
+    if (var.isReadOnly() && m_assignmentContext != AssignmentContext::ConstDeclarationStatement) {
+        bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+        if (threwException)
+            return generator.emitNode(dst, m_right);
+    }
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
     if (generator.vm()->typeProfiler()) {
@@ -1868,7 +1889,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     }
 
-    if (m_assignmentContext == AssignmentContext::DeclarationStatement)
+    if (m_assignmentContext == AssignmentContext::DeclarationStatement || m_assignmentContext == AssignmentContext::ConstDeclarationStatement)
         generator.liftTDZCheckIfPossible(var);
     return returnResult;
 }
@@ -1971,68 +1992,6 @@ RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     return generator.emitNode(dst, node->m_expr);
 }
 
-// ------------------------------ ConstDeclNode ------------------------------------
-
-RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator)
-{
-    // FIXME: This code does not match the behavior of const in Firefox.
-    Variable var = generator.variable(m_ident);
-    if (RegisterID* local = var.local()) {
-        if (!m_init)
-            return local;
-
-        // FIXME: Maybe call emitExpressionInfo here.
-        if (var.isSpecial() || generator.vm()->typeProfiler()) {
-            RefPtr<RegisterID> tempDst = generator.newTemporary();
-            generator.emitNode(tempDst.get(), m_init);
-            return generator.emitMove(local, tempDst.get());
-        }
-        
-        return generator.emitNode(local, m_init);
-    }
-
-    RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
-
-    if (generator.codeType() == GlobalCode)
-        return generator.emitInitGlobalConst(m_ident, value.get());
-
-    if (generator.codeType() != EvalCode) {
-        // Do a special kind of resolution. If anything fails, then don't perform the assignment. This is
-        // pretty shady - particularly how negligent it is with inteleaving scopes - but it's the
-        // behavior that JSC has had for a long time.
-        
-        ASSERT(generator.codeType() == FunctionCode);
-        
-        var = generator.variablePerSymbolTable(m_ident);
-        if (!var.isResolved())
-            return value.get();
-        
-        RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), var);
-        return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound);
-    }
-
-    // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
-    RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
-    return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound);
-}
-
-RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
-{
-    RegisterID* result = 0;
-    for (ConstDeclNode* n = this; n; n = n->m_next)
-        result = n->emitCodeSingle(generator);
-
-    return result;
-}
-
-// ------------------------------ ConstStatementNode -----------------------------
-
-void ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
-{
-    generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
-    generator.emitNode(m_next);
-}
-
 // ------------------------------ SourceElements -------------------------------
 
 
@@ -3391,14 +3350,15 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
     if (RegisterID* local = var.local()) {
         if (m_bindingContext == AssignmentContext::AssignmentExpression)
             generator.emitTDZCheckIfNecessary(var, local, nullptr);
-        if (var.isReadOnly()) {
-            generator.emitReadOnlyExceptionIfNeeded();
-            return;
+        if (var.isReadOnly() && m_bindingContext != AssignmentContext::ConstDeclarationStatement) {
+            bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+            if (threwException)
+                return;
         }
         generator.emitMove(local, value);
         if (generator.vm()->typeProfiler())
             generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
-        if (m_bindingContext == AssignmentContext::DeclarationStatement)
+        if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
             generator.liftTDZCheckIfPossible(var);
         return;
     }
@@ -3408,12 +3368,17 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
     generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
     if (m_bindingContext == AssignmentContext::AssignmentExpression)
         generator.emitTDZCheckIfNecessary(var, nullptr, scope);
+    if (var.isReadOnly() && m_bindingContext != AssignmentContext::ConstDeclarationStatement) {
+        bool threwException = generator.emitReadOnlyExceptionIfNeeded(var);
+        if (threwException)
+            return;
+    }
     generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
     if (generator.vm()->typeProfiler()) {
         generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_boundProperty);
         generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd());
     }
-    if (m_bindingContext == AssignmentContext::DeclarationStatement)
+    if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
         generator.liftTDZCheckIfPossible(var);
     return;
 }
index ecedc5d..99a34b9 100644 (file)
@@ -3152,20 +3152,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_put_by_id);
         }
 
-        case op_init_global_const_nop: {
-            NEXT_OPCODE(op_init_global_const_nop);
-        }
-
-        case op_init_global_const: {
-            Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
-            JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
-            addToGraph(
-                PutGlobalVar,
-                OpInfo(globalObject->assertVariableIsInThisObject(currentInstruction[1].u.variablePointer)),
-                weakJSConstant(globalObject), value);
-            NEXT_OPCODE(op_init_global_const);
-        }
-
         case op_profile_type: {
             Node* valueToProfile = get(VirtualRegister(currentInstruction[1].u.operand));
             addToGraph(ProfileType, OpInfo(currentInstruction[2].u.location), valueToProfile);
index bd39381..f9b5e77 100644 (file)
@@ -152,8 +152,6 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_put_by_id_transition_direct_out_of_line:
     case op_put_by_id_transition_normal:
     case op_put_by_id_transition_normal_out_of_line:
-    case op_init_global_const_nop:
-    case op_init_global_const:
     case op_jmp:
     case op_jtrue:
     case op_jfalse:
index d7693b1..9af332e 100644 (file)
@@ -285,9 +285,6 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_put_getter_by_id)
         DEFINE_OP(op_put_setter_by_id)
         DEFINE_OP(op_put_getter_setter)
-        case op_init_global_const_nop:
-            NEXT_OPCODE(op_init_global_const_nop);
-        DEFINE_OP(op_init_global_const)
 
         DEFINE_OP(op_ret)
         DEFINE_OP(op_rshift)
index fdafd6e..0213963 100644 (file)
@@ -540,7 +540,6 @@ namespace JSC {
         void emit_op_put_getter_by_id(Instruction*);
         void emit_op_put_setter_by_id(Instruction*);
         void emit_op_put_getter_setter(Instruction*);
-        void emit_op_init_global_const(Instruction*);
         void emit_op_ret(Instruction*);
         void emit_op_rshift(Instruction*);
         void emit_op_strcat(Instruction*);
index 12390af..c0a54b7 100644 (file)
@@ -828,14 +828,6 @@ void JIT::emit_op_put_to_arguments(Instruction* currentInstruction)
     store64(regT1, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>)));
 }
 
-void JIT::emit_op_init_global_const(Instruction* currentInstruction)
-{
-    JSGlobalObject* globalObject = m_codeBlock->globalObject();
-    emitWriteBarrier(globalObject, currentInstruction[2].u.operand, ShouldFilterValue);
-    emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
-    store64(regT0, currentInstruction[1].u.variablePointer);
-}
-
 #endif // USE(JSVALUE64)
 
 #if USE(JSVALUE64)
index 1bebb92..148d76c 100644 (file)
@@ -861,21 +861,6 @@ void JIT::emit_op_put_to_arguments(Instruction* currentInstruction)
     store32(regT2, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset));
 }
 
-void JIT::emit_op_init_global_const(Instruction* currentInstruction)
-{
-    WriteBarrier<Unknown>* variablePointer = currentInstruction[1].u.variablePointer;
-    int value = currentInstruction[2].u.operand;
-
-    JSGlobalObject* globalObject = m_codeBlock->globalObject();
-
-    emitWriteBarrier(globalObject, value, ShouldFilterValue);
-
-    emitLoad(value, regT1, regT0);
-    
-    store32(regT1, variablePointer->tagPointer());
-    store32(regT0, variablePointer->payloadPointer());
-}
-
 } // namespace JSC
 
 #endif // USE(JSVALUE32_64)
index 7391b13..52785b2 100644 (file)
@@ -1418,6 +1418,3 @@ macro notSupported()
         break
     end
 end
-
-_llint_op_init_global_const_nop:
-    dispatch(5)
index 4738d28..b66a99d 100644 (file)
@@ -1369,17 +1369,6 @@ macro storePropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, tag,
 end
 
 
-_llint_op_init_global_const:
-    traceExecution()
-    writeBarrierOnGlobalObject(2)
-    loadi 8[PC], t1
-    loadi 4[PC], t0
-    loadConstantOrVariable(t1, t2, t3)
-    storei t2, TagOffset[t0]
-    storei t3, PayloadOffset[t0]
-    dispatch(5)
-
-
 # We only do monomorphic get_by_id caching for now, and we do not modify the
 # opcode. We do, however, allow for the cache to change anytime if fails, since
 # ping-ponging is free. At best we get lucky and the get_by_id will continue
index f8e4ed1..f5af818 100644 (file)
@@ -1236,16 +1236,6 @@ macro storePropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value
     storeq value, (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
 end
 
-_llint_op_init_global_const:
-    traceExecution()
-    writeBarrierOnGlobalObject(2)
-    loadisFromInstruction(2, t1)
-    loadpFromInstruction(1, t0)
-    loadConstantOrVariable(t1, t2)
-    storeq t2, [t0]
-    dispatch(5)
-
-
 macro getById(getPropertyStorage)
     traceExecution()
     # We only do monomorphic get_by_id caching for now, and we do not modify the
index c75d811..b0c9978 100644 (file)
@@ -116,7 +116,6 @@ public:
     typedef StatementNode* Statement;
     typedef ClauseListNode* ClauseList;
     typedef CaseClauseNode* Clause;
-    typedef ConstDeclNode* ConstDeclList;
     typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
     typedef DestructuringPatternNode* DestructuringPattern;
     typedef ArrayPatternNode* ArrayPattern;
@@ -515,16 +514,6 @@ public:
         return result;
     }
 
-    StatementNode* createVarStatement(const JSTokenLocation& location, ExpressionNode* expr, int start, int end)
-    {
-        return createDeclarationStatement(location, expr, start, end);
-    }
-
-    StatementNode* createLetStatement(const JSTokenLocation& location, ExpressionNode* expr, int start, int end)
-    {
-        return createDeclarationStatement(location, expr, start, end);
-    }
-
     ExpressionNode* createEmptyVarExpression(const JSTokenLocation& location, const Identifier& identifier)
     {
         return new (m_parserArena) EmptyVarExpression(location, identifier);
@@ -620,21 +609,6 @@ public:
         return result;
     }
     
-    StatementNode* createConstStatement(const JSTokenLocation& location, ConstDeclNode* decls, int startLine, int endLine)
-    {
-        ConstStatementNode* result = new (m_parserArena) ConstStatementNode(location, decls);
-        result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
-        return result;
-    }
-
-    ConstDeclNode* appendConstDecl(const JSTokenLocation& location, ConstDeclNode* tail, const Identifier* name, ExpressionNode* initializer)
-    {
-        ConstDeclNode* result = new (m_parserArena) ConstDeclNode(location, *name, initializer);
-        if (tail)
-            tail->m_next = result;
-        return result;
-    }
-
     void appendStatement(JSC::SourceElements* elements, JSC::StatementNode* statement)
     {
         elements->append(statement);
index 1be563d..1167e82 100644 (file)
@@ -700,12 +700,6 @@ namespace JSC {
     {
     }
 
-    inline ConstStatementNode::ConstStatementNode(const JSTokenLocation& location, ConstDeclNode* next)
-        : StatementNode(location)
-        , m_next(next)
-    {
-    }
-
     inline SourceElements::SourceElements()
         : m_head(nullptr)
         , m_tail(nullptr)
@@ -898,14 +892,6 @@ namespace JSC {
     {
     }
 
-    inline ConstDeclNode::ConstDeclNode(const JSTokenLocation& location, const Identifier& ident, ExpressionNode* init)
-        : ExpressionNode(location)
-        , m_ident(ident)
-        , m_next(0)
-        , m_init(init)
-    {
-    }
-
     inline BlockNode::BlockNode(const JSTokenLocation& location, SourceElements* statements, VariableEnvironment& lexicalVariables)
         : StatementNode(location)
         , VariableEnvironmentNode(lexicalVariables)
index 7f3f05d..7265c8c 100644 (file)
@@ -90,7 +90,11 @@ namespace JSC {
         SwitchType switchType;
     };
 
-    enum class AssignmentContext { DeclarationStatement, AssignmentExpression };
+    enum class AssignmentContext { 
+        DeclarationStatement, 
+        ConstDeclarationStatement, 
+        AssignmentExpression 
+    };
 
     class ParserArenaFreeable {
     public:
@@ -1254,36 +1258,6 @@ namespace JSC {
         CommaNode* m_next;
     };
     
-    class ConstDeclNode : public ExpressionNode {
-    public:
-        ConstDeclNode(const JSTokenLocation&, const Identifier&, ExpressionNode*);
-
-        bool hasInitializer() const { return m_init; }
-        const Identifier& ident() { return m_ident; }
-
-    private:
-        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
-        virtual RegisterID* emitCodeSingle(BytecodeGenerator&);
-
-        const Identifier& m_ident;
-
-    public:
-        ConstDeclNode* m_next;
-
-    private:
-        ExpressionNode* m_init;
-    };
-
-    class ConstStatementNode : public StatementNode {
-    public:
-        ConstStatementNode(const JSTokenLocation&, ConstDeclNode* next);
-
-    private:
-        virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
-
-        ConstDeclNode* m_next;
-    };
-
     class SourceElements final : public ParserArenaFreeable {
     public:
         SourceElements();
@@ -1958,11 +1932,6 @@ namespace JSC {
         ArgumentListNode* tail;
     };
 
-    struct ConstDeclList {
-        ConstDeclNode* head;
-        ConstDeclNode* tail;
-    };
-
     struct ClauseList {
         ClauseListNode* head;
         ClauseListNode* tail;
index 222bd61..797e45f 100644 (file)
@@ -414,7 +414,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
     bool shouldSetEndOffset = true;
     switch (m_token.m_type) {
     case CONSTTOKEN:
-        result = parseConstDeclaration(context);
+        result = parseVariableDeclaration(context, DeclarationType::ConstDeclaration);
         break;
     case LET: {
         bool shouldParseVariableDeclaration = true;
@@ -426,7 +426,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
             restoreSavePoint(savePoint);
         }
         if (shouldParseVariableDeclaration)
-            result = parseVariableDeclaration(context, DeclarationType::LexicalDeclaration);
+            result = parseVariableDeclaration(context, DeclarationType::LetDeclaration);
         else
             result = parseExpressionOrLabelStatement(context); // Treat this as an IDENT. This is how ::parseStatement() handles IDENT.
 
@@ -453,7 +453,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementList
 template <typename LexerType>
 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDeclaration(TreeBuilder& context, DeclarationType declarationType)
 {
-    ASSERT(match(VAR) || match(LET));
+    ASSERT(match(VAR) || match(LET) || match(CONSTTOKEN));
     JSTokenLocation location(tokenLocation());
     int start = tokenLine();
     int end = 0;
@@ -461,28 +461,12 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDecla
     TreeDestructuringPattern scratch1 = 0;
     TreeExpression scratch2 = 0;
     JSTextPosition scratch3;
-    TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType);
+    bool scratchBool;
+    TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType, scratchBool);
     propagateError();
-    failIfFalse(autoSemiColon(), "Expected ';' after var declaration");
+    failIfFalse(autoSemiColon(), "Expected ';' after variable declaration");
     
-    if (declarationType == DeclarationType::VarDeclaration)
-        return context.createVarStatement(location, variableDecls, start, end);
-    ASSERT(declarationType == DeclarationType::LexicalDeclaration);
-    return context.createLetStatement(location, variableDecls, start, end);
-}
-
-template <typename LexerType>
-template <class TreeBuilder> TreeStatement Parser<LexerType>::parseConstDeclaration(TreeBuilder& context)
-{
-    ASSERT(match(CONSTTOKEN));
-    JSTokenLocation location(tokenLocation());
-    int start = tokenLine();
-    int end = 0;
-    TreeConstDeclList constDecls = parseConstDeclarationList(context);
-    propagateError();
-    failIfFalse(autoSemiColon(), "Expected ';' after const declaration");
-    
-    return context.createConstStatement(location, constDecls, start, end);
+    return context.createDeclarationStatement(location, variableDecls, start, end);
 }
 
 template <typename LexerType>
@@ -533,13 +517,14 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWhileStatemen
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext, DeclarationType declarationType)
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext, DeclarationType declarationType, bool& forLoopConstDoesNotHaveInitializer)
 {
-    ASSERT(declarationType == DeclarationType::LexicalDeclaration || declarationType == DeclarationType::VarDeclaration);
+    ASSERT(declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::VarDeclaration || declarationType == DeclarationType::ConstDeclaration);
     TreeExpression head = 0;
     TreeExpression tail = 0;
     const Identifier* lastIdent;
     JSToken lastIdentToken; 
+    AssignmentContext assignmentContext = assignmentContextFromDeclarationType(declarationType);
     do {
         lastIdent = 0;
         lastPattern = TreeDestructuringPattern(0);
@@ -549,7 +534,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
         declarations++;
         bool hasInitializer = false;
         if (match(IDENT) || isLETMaskedAsIDENT()) {
-            failIfTrue(isLETMaskedAsIDENT() && declarationType == DeclarationType::LexicalDeclaration, "Can't use 'let' as an identifier name for a LexicalDeclaration");
+            failIfTrue(match(LET) && (declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::ConstDeclaration), 
+                "Can't use 'let' as an identifier name for a LexicalDeclaration");
             JSTextPosition varStart = tokenStartPosition();
             JSTokenLocation varStartLocation(tokenLocation());
             identStart = varStart;
@@ -558,11 +544,16 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
             lastIdentToken = m_token;
             next();
             hasInitializer = match(EQUAL);
-            if (!declareVariable(name, declarationType)) {
-                if (declarationType == DeclarationType::LexicalDeclaration)
-                    internalFailWithMessage(false, "Cannot declare a lexical variable twice: '", name->impl(), "'");
-                else if (strictMode())
-                    internalFailWithMessage(false, "Cannot declare a variable named ", name->impl(), " in strict mode");
+            DeclarationResultMask declarationResult = declareVariable(name, declarationType);
+            if (declarationResult != DeclarationResult::Valid) {
+                failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named ", name->impl(), " in strict mode");
+                if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
+                    if (declarationType == DeclarationType::LetDeclaration) 
+                        internalFailWithMessage(false, "Cannot declare a let variable twice: '", name->impl(), "'");
+                    if (declarationType == DeclarationType::ConstDeclaration)
+                        internalFailWithMessage(false, "Cannot declare a const variable twice: '", name->impl(), "'");
+                    RELEASE_ASSERT_NOT_REACHED();
+                }
             }
             if (hasInitializer) {
                 JSTextPosition varDivot = tokenStartPosition() + 1;
@@ -573,8 +564,11 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
                 lastInitializer = initializer;
                 failIfFalse(initializer, "Expected expression as the intializer for the variable '", name->impl(), "'");
                 
-                node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition(), AssignmentContext::DeclarationStatement);
+                node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition(), assignmentContext);
             } else {
+                if (declarationListContext == ForLoopContext && declarationType == DeclarationType::ConstDeclaration)
+                    forLoopConstDoesNotHaveInitializer = true;
+                failIfTrue(declarationListContext != ForLoopContext && declarationType == DeclarationType::ConstDeclaration, "const declared variable '", name->impl(), "'", " must have an initializer");
                 if (declarationType == DeclarationType::VarDeclaration)
                     node = context.createEmptyVarExpression(varStartLocation, *name);
                 else
@@ -582,7 +576,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
             }
         } else {
             lastIdent = 0;
-            auto pattern = parseDestructuringPattern(context, declarationType == DeclarationType::VarDeclaration ? DestructureToVariables : DestructureToLexicalVariables, AssignmentContext::DeclarationStatement);
+            auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), assignmentContext);
             failIfFalse(pattern, "Cannot parse this destructuring pattern");
             hasInitializer = match(EQUAL);
             failIfTrue(declarationListContext == VarDeclarationContext && !hasInitializer, "Expected an initializer in destructuring variable declaration");
@@ -604,7 +598,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
             tail = context.appendToCommaExpr(location, head, tail, node);
     } while (match(COMMA));
     if (lastIdent)
-        lastPattern = context.createBindingLocation(lastIdentToken.m_location, *lastIdent, lastIdentToken.m_startPosition, lastIdentToken.m_endPosition, AssignmentContext::DeclarationStatement);
+        lastPattern = context.createBindingLocation(lastIdentToken.m_location, *lastIdent, lastIdentToken.m_startPosition, lastIdentToken.m_endPosition, assignmentContext);
 
     return head;
 }
@@ -617,13 +611,17 @@ template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createB
     ASSERT(name.impl()->isAtomic() || name.impl()->isSymbol());
     if (depth) {
         if (kind == DestructureToVariables)
-            failIfFalseIfStrict(declareVariable(&name), "Cannot deconstruct to a variable named '", name.impl(), "' in strict mode");
-        else if (kind == DestructureToLexicalVariables)
-            semanticFailIfFalse(declareVariable(&name, DeclarationType::LexicalDeclaration), "Cannot declare a lexical variable twice: '", name.impl(), "'");
-        else if (kind == DestructureToParameters) {
+            failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot deconstruct to a variable named '", name.impl(), "' in strict mode");
+        else if (kind == DestructureToLet || kind == DestructureToConst) {
+            DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
+            if (declarationResult != DeclarationResult::Valid) {
+                failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
+                failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
+            }
+        } else if (kind == DestructureToParameters) {
             auto bindingResult = declareBoundParameter(&name);
             if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
-                semanticFailIfTrue(m_vm->propertyNames->arguments == name || m_vm->propertyNames->eval == name, "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
+                semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
                 if (m_lastFunctionName && name == *m_lastFunctionName)
                     semanticFail("Cannot destructure to '", name.impl(), "' as it shadows the name of a strict mode function");
                 semanticFailureDueToKeyword("bound parameter name");
@@ -641,13 +639,17 @@ template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createB
 
     } else {
         if (kind == DestructureToVariables)
-            failIfFalseIfStrict(declareVariable(&name), "Cannot declare a variable named '", name.impl(), "' in strict mode");
-        else if (kind == DestructureToLexicalVariables)
-            semanticFailIfFalse(declareVariable(&name, DeclarationType::LexicalDeclaration), "Cannot declare a lexical variable twice: '", name.impl(), "'");
-        else if (kind == DestructureToParameters) {
-            bool declarationResult = declareParameter(&name);
-            if (!declarationResult && strictMode()) {
-                semanticFailIfTrue(m_vm->propertyNames->arguments == name || m_vm->propertyNames->eval == name, "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
+            failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
+        else if (kind == DestructureToLet || kind == DestructureToConst) {
+            DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
+            if (declarationResult != DeclarationResult::Valid) {
+                failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
+                failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
+            }
+        } else if (kind == DestructureToParameters) {
+            DeclarationResultMask declarationResult = declareParameter(&name);
+            if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
+                semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
                 if (m_lastFunctionName && name == *m_lastFunctionName)
                     semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
                 semanticFailureDueToKeyword("parameter name");
@@ -765,7 +767,7 @@ template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDe
             TreeDestructuringPattern innerPattern = 0;
             JSTokenLocation location = m_token.m_location;
             if (match(IDENT) || isLETMaskedAsIDENT()) {
-                failIfTrue(isLETMaskedAsIDENT() && kind == DestructureToLexicalVariables, "Can't use 'let' as an identifier name for a LexicalDeclaration");
+                failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
                 propertyName = *m_token.m_data.ident;
                 JSToken identifierToken = m_token;
                 next();
@@ -827,7 +829,7 @@ template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDe
             semanticFailureDueToKeyword("variable name");
             failWithMessage("Expected a parameter pattern or a ')' in parameter list");
         }
-        failIfTrue(isLETMaskedAsIDENT() && kind == DestructureToLexicalVariables, "Can't use 'let' as an identifier name for a LexicalDeclaration");
+        failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
         pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token, bindingContext);
         next();
         break;
@@ -848,34 +850,6 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseDefaultValue
 }
 
 template <typename LexerType>
-template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
-{
-    failIfTrue(strictMode(), "Const declarations are not supported in strict mode");
-    TreeConstDeclList constDecls = 0;
-    TreeConstDeclList tail = 0;
-    do {
-        JSTokenLocation location(tokenLocation());
-        next();
-        failIfFalse(match(IDENT), "Expected an identifier name in const declaration");
-        const Identifier* name = m_token.m_data.ident;
-        next();
-        bool hasInitializer = match(EQUAL);
-        // FIXME: This should be LexicalVariable when we support proper ES6 const semantics.
-        declareVariable(name, DeclarationType::VarDeclaration, true);
-        TreeExpression initializer = 0;
-        if (hasInitializer) {
-            next(TreeBuilder::DontBuildStrings); // consume '='
-            initializer = parseAssignmentExpression(context);
-            failIfFalse(!!initializer, "Unable to parse initializer");
-        }
-        tail = context.appendConstDecl(location, tail, name, initializer);
-        if (!constDecls)
-            constDecls = tail;
-    } while (match(COMMA));
-    return constDecls;
-}
-
-template <typename LexerType>
 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(TreeBuilder& context)
 {
     ASSERT(match(FOR));
@@ -891,13 +865,15 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
     TreeDestructuringPattern pattern = 0;
     bool isVarDeclaraton = match(VAR);
     bool isLetDeclaration = match(LET);
+    bool isConstDeclaration = match(CONSTTOKEN);
+    bool forLoopConstDoesNotHaveInitializer = false;
 
     VariableEnvironment dummySet;
     VariableEnvironment* lexicalVariables = nullptr;
     AutoCleanupLexicalScope lexicalScope;
 
     auto gatherLexicalVariablesIfNecessary = [&] {
-        if (isLetDeclaration) {
+        if (isLetDeclaration || isConstDeclaration) {
             ScopeRef scope = lexicalScope.scope();
             lexicalVariables = &scope->finalizeLexicalEnvironment();
         } else
@@ -905,16 +881,16 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
     };
 
     auto popLexicalScopeIfNecessary = [&] {
-        if (isLetDeclaration)
+        if (isLetDeclaration || isConstDeclaration)
             popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
     };
 
-    if (isVarDeclaraton || isLetDeclaration) {
+    if (isVarDeclaraton || isLetDeclaration || isConstDeclaration) {
         /*
-         for (var/let IDENT in expression) statement
-         for (var/let varDeclarationList; expressionOpt; expressionOpt)
+         for (var/let/const IDENT in/of expression) statement
+         for (var/let/const varDeclarationList; expressionOpt; expressionOpt)
          */
-        if (isLetDeclaration) {
+        if (isLetDeclaration || isConstDeclaration) {
             ScopeRef newScope = pushScope();
             newScope->setIsLexicalScope();
             newScope->preventVarDeclarations();
@@ -926,7 +902,16 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
         m_allowsIn = false;
         JSTextPosition initStart;
         JSTextPosition initEnd;
-        decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, isVarDeclaraton ? DeclarationType::VarDeclaration : DeclarationType::LexicalDeclaration);
+        DeclarationType declarationType;
+        if (isVarDeclaraton)
+            declarationType = DeclarationType::VarDeclaration;
+        else if (isLetDeclaration)
+            declarationType = DeclarationType::LetDeclaration;
+        else if (isConstDeclaration)
+            declarationType = DeclarationType::ConstDeclaration;
+        else
+            RELEASE_ASSERT_NOT_REACHED();
+        decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, declarationType, forLoopConstDoesNotHaveInitializer);
         m_allowsIn = true;
         propagateError();
 
@@ -996,6 +981,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
         // Standard for loop
         next();
         TreeExpression condition = 0;
+        failIfTrue(forLoopConstDoesNotHaveInitializer && isConstDeclaration, "const variables in for loops must have initializers");
         
         if (!match(SEMICOLON)) {
             condition = parseExpression(context);
@@ -1286,7 +1272,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement(
         ident = m_token.m_data.ident;
         next();
         AutoPopScopeRef catchScope(this, pushScope());
-        failIfFalseIfStrict(declareVariable(ident), "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
+        failIfTrueIfStrict(declareVariable(ident) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
         catchScope->preventAllVariableDeclarations();
         handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
         matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
@@ -1600,7 +1586,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             m_lastFunctionName = functionInfo.name;
             next();
             if (!nameIsInContainingScope)
-                failIfFalseIfStrict(functionScope->declareVariable(functionInfo.name), "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
+                failIfTrueIfStrict(functionScope->declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
         } else if (requirements == FunctionNeedsName) {
             if (match(OPENPAREN) && mode == NormalFunctionMode)
                 semanticFail("Function statements must have a name");
@@ -1796,7 +1782,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDecla
     failIfFalse((parseFunctionInfo(context, FunctionNeedsName, NormalFunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded,
         functionKeywordStart, functionInfo, StandardFunctionParseType)), "Cannot parse this function");
     failIfFalse(functionInfo.name, "Function statements must have a name");
-    failIfFalseIfStrict(declareVariable(functionInfo.name), "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
+    failIfTrueIfStrict(declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
     return context.createFuncDeclStatement(location, functionInfo);
 }
 
@@ -1836,7 +1822,7 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
         className = m_token.m_data.ident;
         info.className = className;
         next();
-        failIfFalse(classScope->declareVariable(className), "'", className->impl(), "' is not a valid class name");
+        failIfTrue(classScope->declareVariable(className) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
     } else if (requirements == FunctionNeedsName) {
         if (match(OPENBRACE))
             semanticFail("Class statements must have a name");
@@ -1912,7 +1898,7 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
             ParserFunctionInfo<TreeBuilder> methodInfo;
             bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
             failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, isStaticMethod ? NormalFunctionMode : MethodMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method");
-            failIfFalse(ident && declareVariable(ident), "Cannot declare a method named '", methodInfo.name->impl(), "'");
+            failIfTrue(!ident || (declareVariable(ident) & DeclarationResult::InvalidStrictMode), "Cannot declare a method named '", methodInfo.name->impl(), "'");
             methodInfo.name = isConstructor ? className : ident;
 
             TreeExpression method = context.createFunctionExpr(methodLocation, methodInfo);
index 23387ef..97acd47 100644 (file)
@@ -67,7 +67,6 @@ class SourceCode;
 #define TreeSourceElements typename TreeBuilder::SourceElements
 #define TreeClause typename TreeBuilder::Clause
 #define TreeClauseList typename TreeBuilder::ClauseList
-#define TreeConstDeclList typename TreeBuilder::ConstDeclList
 #define TreeArguments typename TreeBuilder::Arguments
 #define TreeArgumentsList typename TreeBuilder::ArgumentsList
 #define TreeFunctionBody typename TreeBuilder::FunctionBody
@@ -84,13 +83,30 @@ enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
 enum FunctionParseType { StandardFunctionParseType, ArrowFunctionParseType };
 enum FunctionBodyType { ArrowFunctionBodyExpression, ArrowFunctionBodyBlock, StandardFunctionBodyBlock };
 enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+
 enum DestructuringKind {
     DestructureToVariables,
-    DestructureToLexicalVariables,
+    DestructureToLet,
+    DestructureToConst,
     DestructureToParameters,
     DestructureToExpressions
 };
 
+enum class DeclarationType { 
+    VarDeclaration, 
+    LetDeclaration,
+    ConstDeclaration
+};
+
+enum DeclarationResult {
+    Valid = 0,
+    InvalidStrictMode = 1 << 0,
+    InvalidDuplicateDeclaration = 1 << 1
+};
+
+typedef uint8_t DeclarationResultMask;
+
+
 template <typename T> inline bool isEvalNode() { return false; }
 template <> inline bool isEvalNode<EvalNode>() { return true; }
 
@@ -99,6 +115,19 @@ struct ScopeLabelInfo {
     bool isLoop;
 };
 
+ALWAYS_INLINE static bool isArguments(const VM* vm, const Identifier* ident)
+{
+    return vm->propertyNames->arguments == *ident;
+}
+ALWAYS_INLINE static bool isEval(const VM* vm, const Identifier* ident)
+{
+    return vm->propertyNames->eval == *ident;
+}
+ALWAYS_INLINE static bool isEvalOrArgumentsIdentifier(const VM* vm, const Identifier* ident)
+{
+    return isEval(vm, ident) || isArguments(vm, ident);
+}
+
 struct Scope {
     Scope(const VM* vm, bool isFunction, bool strictMode)
         : m_vm(vm)
@@ -236,28 +265,37 @@ struct Scope {
         addResult.iterator->value.clearIsVar();
     }
 
-    bool declareVariable(const Identifier* ident, bool isConstant = false)
+    DeclarationResultMask declareVariable(const Identifier* ident)
     {
         ASSERT(m_allowsVarDeclarations);
-        bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident;
+        DeclarationResultMask result = DeclarationResult::Valid;
+        bool isValidStrictMode = !isEvalOrArgumentsIdentifier(m_vm, ident);
         m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
         auto addResult = m_declaredVariables.add(ident->impl());
         addResult.iterator->value.setIsVar();
-        if (isConstant)
-            addResult.iterator->value.setIsConstant();
-
-        return isValidStrictMode;
+        if (!isValidStrictMode)
+            result |= DeclarationResult::InvalidStrictMode;
+        return result;
     }
 
-    bool declareLexicalVariable(const Identifier* ident)
+    DeclarationResultMask declareLexicalVariable(const Identifier* ident, bool isConstant)
     {
         ASSERT(m_allowsLexicalDeclarations);
-        bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident;
+        DeclarationResultMask result = DeclarationResult::Valid;
+        bool isValidStrictMode = !isEvalOrArgumentsIdentifier(m_vm, ident);
         m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
         auto addResult = m_lexicalVariables.add(ident->impl());
-        addResult.iterator->value.setIsLet();
-        bool successfulDeclaration = addResult.isNewEntry && isValidStrictMode;
-        return successfulDeclaration;
+        if (isConstant)
+            addResult.iterator->value.setIsConst();
+        else
+            addResult.iterator->value.setIsLet();
+
+        if (!addResult.isNewEntry)
+            result |= DeclarationResult::InvalidDuplicateDeclaration;
+        if (!isValidStrictMode)
+            result |= DeclarationResult::InvalidStrictMode;
+
+        return result;
     }
 
     bool hasDeclaredVariable(const Identifier& ident)
@@ -300,19 +338,22 @@ struct Scope {
     bool allowsVarDeclarations() const { return m_allowsVarDeclarations; }
     bool allowsLexicalDeclarations() const { return m_allowsLexicalDeclarations; }
 
-    bool declareParameter(const Identifier* ident)
+    DeclarationResultMask declareParameter(const Identifier* ident)
     {
         ASSERT(m_allowsVarDeclarations);
-        bool isArguments = m_vm->propertyNames->arguments == *ident;
+        DeclarationResultMask result = DeclarationResult::Valid;
+        bool isArgumentsIdent = isArguments(m_vm, ident);
         auto addResult = m_declaredVariables.add(ident->impl());
         addResult.iterator->value.clearIsVar();
-        bool isValidStrictMode = addResult.isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
+        bool isValidStrictMode = addResult.isNewEntry && m_vm->propertyNames->eval != *ident && !isArgumentsIdent;
         m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
         m_declaredParameters.add(ident->impl());
-
-        if (isArguments)
+        if (!isValidStrictMode)
+            result |= DeclarationResult::InvalidStrictMode;
+        if (isArgumentsIdent)
             m_shadowsArguments = true;
-        return isValidStrictMode;
+
+        return result;
     }
     
     enum BindingResult {
@@ -322,13 +363,13 @@ struct Scope {
     };
     BindingResult declareBoundParameter(const Identifier* ident)
     {
-        bool isArguments = m_vm->propertyNames->arguments == *ident;
+        bool isArgumentsIdent = isArguments(m_vm, ident);
         auto addResult = m_declaredVariables.add(ident->impl());
         addResult.iterator->value.setIsVar(); // Treat destructuring parameters as "var"s.
-        bool isValidStrictMode = addResult.isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
+        bool isValidStrictMode = addResult.isNewEntry && !isEval(m_vm, ident) && !isArgumentsIdent;
         m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
     
-        if (isArguments)
+        if (isArgumentsIdent)
             m_shadowsArguments = true;
         if (!addResult.isNewEntry)
             return BindingFailed;
@@ -615,6 +656,33 @@ private:
         Parser* m_parser;
     };
 
+    ALWAYS_INLINE DestructuringKind destructuringKindFromDeclarationType(DeclarationType type)
+    {
+        switch (type) {
+        case DeclarationType::VarDeclaration:
+            return DestructureToVariables;
+        case DeclarationType::LetDeclaration:
+            return DestructureToLet;
+        case DeclarationType::ConstDeclaration:
+            return DestructureToConst;
+        }
+
+        RELEASE_ASSERT_NOT_REACHED();
+        return DestructureToVariables;
+    }
+
+    ALWAYS_INLINE AssignmentContext assignmentContextFromDeclarationType(DeclarationType type)
+    {
+        switch (type) {
+        case DeclarationType::ConstDeclaration:
+            return AssignmentContext::ConstDeclarationStatement;
+        default:
+            return AssignmentContext::DeclarationStatement;
+        }
+    }
+
+    ALWAYS_INLINE bool isEvalOrArguments(const Identifier* ident) { return isEvalOrArgumentsIdentifier(m_vm, ident); }
+
     ScopeRef currentScope()
     {
         return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
@@ -661,8 +729,7 @@ private:
         popScopeInternal(scope, shouldTrackClosedVariables);
     }
     
-    enum class DeclarationType { VarDeclaration, LexicalDeclaration };
-    bool declareVariable(const Identifier* ident, typename Parser::DeclarationType type = DeclarationType::VarDeclaration, bool isConstant = false)
+    DeclarationResultMask declareVariable(const Identifier* ident, DeclarationType type = DeclarationType::VarDeclaration)
     {
         unsigned i = m_scopeStack.size() - 1;
         ASSERT(i < m_scopeStack.size());
@@ -673,21 +740,21 @@ private:
                 ASSERT(i < m_scopeStack.size());
             }
 
-            return m_scopeStack[i].declareVariable(ident, isConstant);
+            return m_scopeStack[i].declareVariable(ident);
         }
 
-        ASSERT(type == DeclarationType::LexicalDeclaration);
+        ASSERT(type == DeclarationType::LetDeclaration || type == DeclarationType::ConstDeclaration);
 
         // Lexical variables declared at a top level scope that shadow arguments or vars are not allowed.
         if (m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident)))
-            return false;
+            return DeclarationResult::InvalidDuplicateDeclaration;
 
         while (!m_scopeStack[i].allowsLexicalDeclarations()) {
             i--;
             ASSERT(i < m_scopeStack.size());
         }
 
-        return m_scopeStack[i].declareLexicalVariable(ident);
+        return m_scopeStack[i].declareLexicalVariable(ident, type == DeclarationType::ConstDeclaration);
     }
     
     NEVER_INLINE bool hasDeclaredVariable(const Identifier& ident)
@@ -894,7 +961,7 @@ private:
     void setStrictMode() { currentScope()->setStrictMode(); }
     bool strictMode() { return currentScope()->strictMode(); }
     bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
-    bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+    DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
     Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
     bool breakIsValid()
     {
@@ -943,7 +1010,6 @@ private:
 #endif
     template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseVariableDeclaration(TreeBuilder&, DeclarationType);
-    template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
@@ -979,8 +1045,7 @@ private:
     template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionBodyType, unsigned, FunctionParseMode);
     template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, unsigned&);
     enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
-    template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType);
-    template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
+    template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, bool& forLoopConstDoesNotHaveInitializer);
     template <class TreeBuilder> TreeSourceElements parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder&);
     template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
     template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken, AssignmentContext);
index c6d3563..ee0e558 100644 (file)
@@ -127,7 +127,6 @@ public:
     typedef int Statement;
     typedef int ClauseList;
     typedef int Clause;
-    typedef int ConstDeclList;
     typedef int BinaryOperand;
     typedef int DestructuringPattern;
     typedef DestructuringPattern ArrayPattern;
@@ -236,8 +235,7 @@ public:
     int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     int createEmptyStatement(const JSTokenLocation&) { return StatementResult; }
-    int createVarStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
-    int createLetStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+    int createDeclarationStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
     int createReturnStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
     int createBreakStatement(const JSTokenLocation&, int, int) { return StatementResult; }
     int createBreakStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
index 446027c..738e651 100644 (file)
@@ -35,12 +35,12 @@ namespace JSC {
 struct VariableEnvironmentEntry {
 public:
     ALWAYS_INLINE bool isCaptured() const { return m_bits & IsCaptured; }
-    ALWAYS_INLINE bool isConstant() const { return m_bits & IsConstant; }
+    ALWAYS_INLINE bool isConst() const { return m_bits & IsConst; }
     ALWAYS_INLINE bool isVar() const { return m_bits & IsVar; }
     ALWAYS_INLINE bool isLet() const { return m_bits & IsLet; }
 
     ALWAYS_INLINE void setIsCaptured() { m_bits |= IsCaptured; }
-    ALWAYS_INLINE void setIsConstant() { m_bits |= IsConstant; }
+    ALWAYS_INLINE void setIsConst() { m_bits |= IsConst; }
     ALWAYS_INLINE void setIsVar() { m_bits |= IsVar; }
     ALWAYS_INLINE void setIsLet() { m_bits |= IsLet; }
 
@@ -49,7 +49,7 @@ public:
 private:
     enum Traits {
         IsCaptured = 1 << 0,
-        IsConstant = 1 << 1,
+        IsConst = 1 << 1,
         IsVar = 1 << 2,
         IsLet = 1 << 3
     };
index eca763f..e117ab6 100644 (file)
@@ -522,10 +522,8 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF
 
     const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
     for (auto& entry : variableDeclarations) {
-        if (entry.value.isConstant())
-            globalObject->addConst(callFrame, Identifier::fromUid(&vm, entry.key.get()));
-        else
-            globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get()));
+        ASSERT(entry.value.isVar());
+        globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get()));
     }
     return 0;
 }
index f3c8f86..419c1b2 100644 (file)
@@ -570,7 +570,7 @@ bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, Proper
     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
 }
 
-void JSGlobalObject::addGlobalVar(const Identifier& ident, ConstantMode constantMode)
+void JSGlobalObject::addGlobalVar(const Identifier& ident)
 {
     ConcurrentJITLocker locker(symbolTable()->m_lock);
     SymbolTableEntry entry = symbolTable()->get(locker, ident.impl());
@@ -578,11 +578,8 @@ void JSGlobalObject::addGlobalVar(const Identifier& ident, ConstantMode constant
         return;
     
     ScopeOffset offset = symbolTable()->takeNextScopeOffset(locker);
-    SymbolTableEntry newEntry(VarOffset(offset), (constantMode == IsConstant) ? ReadOnly : 0);
-    if (constantMode == IsVariable)
-        newEntry.prepareToWatch();
-    else
-        newEntry.disableWatching();
+    SymbolTableEntry newEntry(VarOffset(offset), 0);
+    newEntry.prepareToWatch();
     symbolTable()->add(locker, ident.impl(), newEntry);
     
     ScopeOffset offsetForAssert = addVariables(1);
@@ -593,7 +590,7 @@ void JSGlobalObject::addFunction(ExecState* exec, const Identifier& propertyName
 {
     VM& vm = exec->vm();
     removeDirect(vm, propertyName); // Newly declared functions overwrite existing properties.
-    addGlobalVar(propertyName, IsVariable);
+    addGlobalVar(propertyName);
 }
 
 static inline JSObject* lastInPrototypeChain(JSObject* object)
index 81bbca7..337bb74 100644 (file)
@@ -23,7 +23,6 @@
 #define JSGlobalObject_h
 
 #include "ArrayAllocationProfile.h"
-#include "ConstantMode.h"
 #include "JSArray.h"
 #include "JSArrayBufferPrototype.h"
 #include "JSClassRef.h"
@@ -357,7 +356,7 @@ protected:
         setGlobalThis(vm, thisValue);
     }
 
-    void addGlobalVar(const Identifier&, ConstantMode);
+    void addGlobalVar(const Identifier&);
 
 public:
     JS_EXPORT_PRIVATE ~JSGlobalObject();
@@ -382,12 +381,7 @@ public:
     void addVar(ExecState* exec, const Identifier& propertyName)
     {
         if (!hasProperty(exec, propertyName))
-            addGlobalVar(propertyName, IsVariable);
-    }
-    void addConst(ExecState* exec, const Identifier& propertyName)
-    {
-        if (!hasProperty(exec, propertyName))
-            addGlobalVar(propertyName, IsConstant);
+            addGlobalVar(propertyName);
     }
     void addFunction(ExecState*, const Identifier&);
 
index 6d333f6..6076874 100644 (file)
@@ -70,7 +70,7 @@ inline bool JSLexicalEnvironment::symbolTablePut(ExecState* exec, PropertyName p
             return false;
         ASSERT(!iter->value.isNull());
         if (iter->value.isReadOnly()) {
-            if (shouldThrow)
+            if (shouldThrow || isLexicalScope())
                 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
             return true;
         }
diff --git a/Source/JavaScriptCore/tests/stress/const-and-with-statement.js b/Source/JavaScriptCore/tests/stress/const-and-with-statement.js
new file mode 100644 (file)
index 0000000..a847794
--- /dev/null
@@ -0,0 +1,115 @@
+function truth() {
+    return true;
+}
+noInline(truth);
+
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+
+function shouldThrowInvalidConstAssignment(f) {
+    var threw = false;
+    try {
+        f();
+    } catch(e) {
+        if (e.name.indexOf("TypeError") !== -1 && e.message.indexOf("readonly") !== -1)
+            threw = true;
+    }
+    assert(threw);
+}
+noInline(shouldThrowInvalidConstAssignment);
+
+
+// Tests
+
+const NUM_LOOPS = 10000;
+
+;(function() {
+    function foo() {
+        const x = 40;
+        with ({x : 100}) {
+            assert(x === 100);
+        }
+        with ({y : 100}) {
+            assert(x === 40);
+        }
+    }
+    noInline(foo);
+
+    function bar() {
+        const x = 40;
+        function capX() { return x; }
+        with ({x : 100}) {
+            if (truth()) {
+                const x = 50;
+                const capX = function() { return x; }
+                assert(x === 50);
+                assert(capX() === x);
+            }
+            assert(x === 100);
+            assert(capX() === 40);
+        }
+        with ({y : 100}) {
+            if (truth()) {
+                const x = 50;
+                const capX = function() { return x; }
+                assert(x === 50);
+                assert(capX() === x);
+            }
+            assert(x === 40);
+            assert(capX() === 40);
+        }
+    }
+    noInline(bar);
+
+    function baz() {
+        const x = 40;
+        function capX() { return x; }
+        with ({x : 100}) {
+            if (truth()) {
+                const x = 50;
+                assert(x === 50);
+            }
+            assert(x === 100);
+            assert(capX() === 40);
+        }
+        with ({y : 100}) {
+            if (truth()) {
+                const x = 50;
+                assert(x === 50);
+            }
+            assert(x === 40);
+            assert(capX() === 40);
+        }
+    }
+    noInline(baz);
+
+    for (let i = 0; i < NUM_LOOPS; i++) {
+        foo();
+        bar();
+        baz();
+    }
+})();
+
+
+;(function() {
+    function foo() {
+        const x = 40;
+        with ({x : 100}) {
+            assert(x === 100);
+            x = 20;
+            assert(x === 20);
+        }
+        assert(x === 40);
+        with ({y : 100}) {
+            assert(x === 40);
+            x = 100;
+        }
+    }
+    for (let i = 0; i < NUM_LOOPS; ++i) {
+        shouldThrowInvalidConstAssignment(foo);
+    }
+
+})();
diff --git a/Source/JavaScriptCore/tests/stress/const-exception-handling.js b/Source/JavaScriptCore/tests/stress/const-exception-handling.js
new file mode 100644 (file)
index 0000000..f22ab12
--- /dev/null
@@ -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);
+}
+
+})();
diff --git a/Source/JavaScriptCore/tests/stress/const-loop-semantics.js b/Source/JavaScriptCore/tests/stress/const-loop-semantics.js
new file mode 100644 (file)
index 0000000..18e0cfe
--- /dev/null
@@ -0,0 +1,130 @@
+"use strict";
+function truth() {
+    return true;
+}
+noInline(truth);
+
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+function shouldThrowInvalidConstAssignment(f) {
+    var threw = false;
+    try {
+        f();
+    } catch(e) {
+        if (e.name.indexOf("TypeError") !== -1 && e.message.indexOf("readonly") !== -1)
+            threw = true;
+    }
+    assert(threw);
+}
+noInline(shouldThrowInvalidConstAssignment);
+
+
+// ========== tests below ===========
+
+const NUM_LOOPS = 10000;
+
+;(function() {
+    function foo() {
+        const obj = {a: 20, b: 40, c: 50};
+        const props = [];
+        for (const p in obj)
+            props.push(p);
+        assert(props.length === 3);
+        for (const p of props)
+            assert(!!obj[p]);
+        assert(props.indexOf("a") !== -1);
+        assert(props.indexOf("b") !== -1);
+        assert(props.indexOf("c") !== -1);
+    }
+
+    function bar() {
+        const funcs = [];
+        for (const item of [1, 2, 3])
+            funcs.push(function() { return item; });
+        let i = 1;
+        assert(funcs.length === 3);
+        for (const f of funcs) {
+            assert(f() === i);
+            i++;
+        }
+    }
+    function baz() {
+        const funcs = [];
+        const obj = {a:1, b:2, c:3};
+        for (const p in obj)
+            funcs.push(function() { return p; });
+        let i = 1;
+        assert(funcs.length === 3);
+        for (const f of funcs) {
+            assert(obj[f()] === i);
+            i++;
+        }
+    }
+    function taz() {
+        for (const item of [1,2,3]) {
+            const item = 20;
+            assert(item === 20);
+        }
+    }
+    function jaz() {
+        let i = 0;
+        for (const x = 40; i < 10; i++) {
+            assert(x === 40);
+        }
+    }
+    for (var i = 0; i < NUM_LOOPS; i++) {
+        foo();
+        bar();
+        baz();
+        taz();
+        jaz();
+    }
+})();
+
+;(function() {
+    function foo() {
+        for (const item of [1,2,3])
+            item = 20;
+    }
+    function bar() {
+        for (const item of [1,2,3])
+            eval("item = 20")
+    }
+    function baz() {
+        for (const p in {a: 20, b: 40})
+            p = 20;
+    }
+    function taz() {
+        for (const p in {a: 20, b: 40})
+            eval("p = 20")
+    }
+    function jaz() {
+        for (const x = 0; x < 10; x++) { }
+    }
+    function raz() {
+        for (const x = 0; x < 10; ++x) { }
+    }
+    function paz() {
+        for (const x = 0; x < 10; x++) { 
+            let f = function() { return x; }
+        }
+    }
+    function maz() {
+        for (const x = 0; x < 10; ++x) { 
+            let f = function() { return x; } 
+        }
+    }
+    for (var i = 0; i < NUM_LOOPS; i++) {
+        shouldThrowInvalidConstAssignment(foo);
+        shouldThrowInvalidConstAssignment(bar);
+        shouldThrowInvalidConstAssignment(baz);
+        shouldThrowInvalidConstAssignment(taz);
+        shouldThrowInvalidConstAssignment(jaz);
+        shouldThrowInvalidConstAssignment(raz);
+        shouldThrowInvalidConstAssignment(paz);
+        shouldThrowInvalidConstAssignment(maz);
+    }
+})();
diff --git a/Source/JavaScriptCore/tests/stress/const-not-strict-mode.js b/Source/JavaScriptCore/tests/stress/const-not-strict-mode.js
new file mode 100644 (file)
index 0000000..894d571
--- /dev/null
@@ -0,0 +1,147 @@
+function truth() {
+    return true;
+}
+noInline(truth);
+
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+
+function shouldThrowTDZ(func) {
+    var hasThrown = false;
+    try {
+        func();
+    } catch(e) {
+        if (e.name.indexOf("ReferenceError") !== -1)
+            hasThrown = true;
+    }
+    assert(hasThrown);
+}
+noInline(shouldThrowTDZ);
+
+
+// Tests
+
+
+const NUM_LOOPS = 10000;
+
+;(function() {
+function foo() {
+    delete x;
+    const x = 20;
+}
+function bar() {
+    delete x;
+    const x = 20;
+    function capX() { return x; }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+}
+
+})();
+
+
+;(function() {
+
+function foo() {
+    var hadError = false;
+    try {
+        x;
+    } catch(e) {
+        hadError = true;
+    }
+    assert(hadError);
+
+    if (truth()) {
+        // This eval is enterpreted as follows:
+        // eval("var x; x = 20");
+        // We first assign undefined to the "var x".
+        // Then, we interperet an assignment expression
+        // into the resolved variable x. x resolves to the lexical "const x;"
+        // Look at ECMA section 13.3.2.4 of the ES6 spec:
+        // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-variable-statement-runtime-semantics-evaluation
+        // And also look at section 8.3.1 ResolveBinding:
+        // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-resolvebinding
+        const x = 40;
+        let threw = false;
+        try {
+            eval("var x = 20;");
+        } catch(e) {
+            if (e.name.indexOf("TypeError") !== -1 && e.message.indexOf("readonly") !== -1)
+                threw = true;
+        }
+        assert(threw);
+        assert(x === 40);
+    }
+    assert(x === undefined);
+}
+
+function bar() {
+    var hadError = false;
+    try {
+        x;
+    } catch(e) {
+        hadError = true;
+    }
+    assert(hadError);
+
+    if (truth()) {
+        const x = 40;
+        function capX() { return x; }
+        let threw = false;
+        try {
+            eval("var x = 20;");
+        } catch(e) {
+            if (e.name.indexOf("TypeError") !== -1 && e.message.indexOf("readonly") !== -1)
+                threw = true;
+        }
+        assert(threw);
+        assert(x === 40);
+    }
+    assert(x === undefined);
+}
+
+function baz() {
+    if (truth()) {
+        const x = 40;
+        eval("const x = 20; assert(x === 20);");
+        assert(x === 40);
+    }
+    if (truth()) {
+        const x = 40;
+        function capX() { return x; }
+        eval("const x = 20; assert(x === 20);");
+        assert(x === 40);
+    }
+}
+
+function baz() {
+    // Test eval() caching.
+    const x = 20;
+    const evalString = "x;";
+
+    assert(eval(evalString) === 20);
+    if (truth()) {
+        const y = 60;
+        assert(eval(evalString) === 20);
+        assert(y === 60);
+        if (truth()) {
+            const y = 50, z = 70, x = 40;
+            assert(eval(evalString) === 40);
+            assert(y === 50 && z === 70);
+        }
+    }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    foo();
+    bar();
+    baz();
+}
+
+})();
diff --git a/Source/JavaScriptCore/tests/stress/const-semantics.js b/Source/JavaScriptCore/tests/stress/const-semantics.js
new file mode 100644 (file)
index 0000000..6f4263e
--- /dev/null
@@ -0,0 +1,262 @@
+"use strict";
+function truth() {
+    return true;
+}
+noInline(truth);
+
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+function shouldThrowInvalidConstAssignment(f) {
+    var threw = false;
+    try {
+        f();
+    } catch(e) {
+        if (e.name.indexOf("TypeError") !== -1 && e.message.indexOf("readonly") !== -1)
+            threw = true;
+    }
+    assert(threw);
+}
+noInline(shouldThrowInvalidConstAssignment);
+
+
+// ========== tests below ===========
+
+const NUM_LOOPS = 10000;
+
+
+;(function() {
+    function foo() {
+        const x = 40;
+        const {y} = {y: 50}, [z] = [60];
+        assert(x === 40);
+        assert(y === 50);
+        assert(z === 60);
+    }
+    function bar() {
+        const x = 40;
+        const {y} = {y: 50}, [z] = [60];
+        function capture() { return x + y + z; }
+        assert(x === 40);
+        assert(y === 50);
+        assert(z === 60);
+        assert(capture() === 150);
+        if (truth()) {
+            const x = "x";
+            assert(x === "x");
+            if (truth()) {
+                let x = 100;
+                const y = 200;
+                assert(x === 100);
+                assert(y === 200);
+
+                x = 10;
+                assert(x === 10);
+            }
+            assert(x === "x");
+        }
+        assert(x === 40);
+    }
+    function baz() {
+        let y = 10;
+        function sideEffects() {
+            y = 20;
+        }
+
+        const x = 10;
+        try {
+            x = sideEffects();
+        } catch(e) {}
+        assert(y === 20);
+        assert(x === 10);
+
+        try {
+            x = y = 30;
+        } catch(e) {}
+        assert(y === 30);
+        assert(x === 10);
+    }
+    function taz() {
+        let y = 10;
+        let z;
+        function sideEffects() {
+            y = 20;
+            return ["hello", "world"];
+        }
+
+        const x = 10;
+        try {
+            [z, x] = sideEffects();
+        } catch(e) {}
+        assert(y === 20);
+        assert(x === 10);
+        assert(z === "hello");
+    }
+    function jaz() {
+        const x = "x";
+        function capX() { return x; }
+        assert(x === "x");
+        assert(capX() === "x");
+        if (truth()) {
+            let y = 40;
+            let capY = function() { return y; }
+            assert(x === "x");
+            assert(capX() === "x");
+        }
+        assert(x === "x");
+        assert(capX() === "x");
+    }
+    for (var i = 0; i < NUM_LOOPS; i++) {
+        foo();
+        bar();
+        baz();
+        jaz();
+    }
+})();
+
+
+;(function() {
+    function foo() {
+        const x = 40;
+        x = 30;
+    }
+    function bar() {
+        const x = 40;
+        function capX() { return x; }
+        x = 30;
+    }
+    function baz() {
+        const x = 40;
+        assert(x === 40);
+        function bad() { x = 10; }
+        bad();
+    }
+    function jaz() {
+        const x = 40;
+        assert(x === 40);
+        function bad() { eval("x = 10"); }
+        bad();
+    }
+    function faz() {
+        const x = 40;
+        assert(x === 40);
+        eval("x = 10");
+    }
+    function raz() {
+        const x = 40;
+        assert(x === 40);
+        ;({x} = {x: 20});
+    }
+    function taz() {
+        const x = 40;
+        function capX() { return x; }
+        assert(capX() === 40);
+        ;({x} = {x: 20});
+    }
+    function paz() {
+        const x = 20;
+        const y = x = 20;
+    }
+    for (var i = 0; i < NUM_LOOPS; i++) {
+        shouldThrowInvalidConstAssignment(foo);
+        shouldThrowInvalidConstAssignment(bar);
+        shouldThrowInvalidConstAssignment(baz);
+        shouldThrowInvalidConstAssignment(jaz);
+        shouldThrowInvalidConstAssignment(faz);
+        shouldThrowInvalidConstAssignment(raz);
+        shouldThrowInvalidConstAssignment(taz);
+        shouldThrowInvalidConstAssignment(paz);
+    }
+})();
+
+
+;(function() {
+    function foo() {
+        const x = 40;
+        eval("x = 30;");
+    }
+    function bar() {
+        const x = 20;
+        x += 20;
+    }
+    function baz() {
+        const x = 20;
+        x -= 20;
+    }
+    function taz() {
+        const x = 20;
+        shouldThrowInvalidConstAssignment(function() { x = 20; });
+        shouldThrowInvalidConstAssignment(function() { x += 20; });
+        shouldThrowInvalidConstAssignment(function() { x -= 20; });
+        shouldThrowInvalidConstAssignment(function() { x *= 20; });
+        shouldThrowInvalidConstAssignment(function() { x /= 20; });
+        shouldThrowInvalidConstAssignment(function() { x >>= 20; });
+        shouldThrowInvalidConstAssignment(function() { x <<= 20; });
+        shouldThrowInvalidConstAssignment(function() { x ^= 20; });
+        shouldThrowInvalidConstAssignment(function() { x++; });
+        shouldThrowInvalidConstAssignment(function() { x--; });
+        shouldThrowInvalidConstAssignment(function() { ++x; });
+        shouldThrowInvalidConstAssignment(function() { --x; });
+    }
+    function jaz() {
+        const x = 20;
+        let threw = false;
+        try { x = 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x += 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x -= 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x *= 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x /= 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x >>= 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x <<= 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x ^= 20; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { x++; } catch(e) { threw = true}
+        assert(threw);
+
+
+        threw = false;
+        try { x--; } catch(e) { threw = true}
+        assert(threw);
+
+
+        threw = false;
+        try { ++x; } catch(e) { threw = true}
+        assert(threw);
+
+        threw = false;
+        try { --x; } catch(e) { threw = true};
+        assert(threw);
+    }
+    for (var i = 0; i < NUM_LOOPS; i++) {
+        shouldThrowInvalidConstAssignment(foo);
+        shouldThrowInvalidConstAssignment(bar);
+        shouldThrowInvalidConstAssignment(baz);
+        taz();
+        jaz();
+    }
+})();
diff --git a/Source/JavaScriptCore/tests/stress/const-tdz.js b/Source/JavaScriptCore/tests/stress/const-tdz.js
new file mode 100644 (file)
index 0000000..a2c390c
--- /dev/null
@@ -0,0 +1,449 @@
+"use strict";
+
+function truth() {
+    return true;
+}
+noInline(truth);
+
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+
+function shouldThrowTDZ(func) {
+    var hasThrown = false;
+    try {
+        func();
+    } catch(e) {
+        if (e.name.indexOf("ReferenceError") !== -1)
+            hasThrown = true;
+    }
+    assert(hasThrown);
+}
+noInline(shouldThrowTDZ);
+
+// Test cases
+
+const NUM_LOOPS = 10000;
+
+;(function() {
+function foo() {
+    x;
+    const x = 20;
+}
+function bar() {
+    const x = x;
+}
+function baz() {
+    const {x: prop, y: prop2} = {x: prop};
+}
+function jaz() {
+    const {x: prop, y: prop2} = {x: 20, y: prop};
+}
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+    shouldThrowTDZ(baz);
+    shouldThrowTDZ(jaz);
+}
+})();
+
+
+;(function() {
+function foo() {
+    x;
+    const x = 20;
+    function captureX() { return x; }
+}
+function bar() {
+    captureX();
+    const x = 20;
+    function captureX() { return x; }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+}
+})();
+
+
+;(function() {
+function foo() {
+    if (truth()) {
+        const x = 20;
+        assert(x === 20);
+    }
+    x;
+    const x = 20;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+
+;(function() {
+function foo() {
+    if (truth()) {
+        const y = 20;
+        const captureY = function() { return y; }
+        assert(y === 20);
+        x;
+    }
+    const x = 20;
+    const y = 40;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+;(function() {
+function foo() {
+    if (truth()) {
+        const y = 20;
+        const x = 40;
+        const captureAll = function() { return x + y; }
+        assert(y === 20);
+        assert(x === 40);
+        assert(captureAll() === 60);
+    }
+    tdz;
+    const tdz = 20;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+;(function() {
+function foo() {
+    if (truth()) {
+        const y = 20;
+        const x = 40;
+        const captureAll = function() { return x + y + tdz; }
+        assert(y === 20);
+        assert(x === 40);
+    }
+    tdz;
+    const tdz = 20;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+;(function() {
+function foo() {
+    x = 10;
+    const x = 20;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+;(function() {
+function foo() {
+    x = 10;
+    const x = 20;
+    function cap() { return x; }
+}
+function bar() {
+    captureX();
+    const x = 20;
+    function captureX() { return x; }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+}
+})();
+
+
+;(function() {
+function foo() {
+    if (!truth()) {
+        y;
+        assert(false);
+    }
+    const y = undefined;
+    assert(y === undefined);
+    if (truth()) {
+        x;
+    }
+    const x = undefined;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+;(function() {
+function foo() {
+    eval("x;");
+    const x = 20;
+}
+function bar() {
+    function captureX() { return x; }
+    eval("captureX();");
+    const x = 20;
+}
+function baz() {
+    function captureX() { return x; }
+    function other() { return captureX; }
+    other()();
+    const x = 20;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+    shouldThrowTDZ(baz);
+}
+})();
+
+
+;(function() {
+function foo() {
+    const y = 40;
+    eval("y; x;");
+    const x = 20;
+}
+
+for (var i = 0; i < 1; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+;(function() {
+function foo() {
+    const x = 20;
+    const y = 40;
+    assert(eval("x;") === 20);
+    if (truth()) {
+        assert(eval("eval('y');") === 40);
+        eval("eval('x');");
+        const x = 40;
+    }
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+}
+})();
+
+
+// FunctionResolveNode
+;(function() {
+function foo() {
+    function captureX() { return x; }
+    x();
+    const x = function() { return 20; };
+}
+
+function bar() {
+    x();
+    let x = function() { return 20; };
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+}
+})();
+
+
+// TypeofResolveNode
+;(function() {
+function foo() {
+    function captureX() { return x; }
+    typeof x;
+    const x = function() { return 20; };
+}
+
+function bar() {
+    typeof x;
+    const x = function() { return 20; };
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+}
+})();
+
+
+// ReadModifyResolveNode
+;(function() {
+function foo() {
+    function captureX() { return x; }
+    x++;
+    const x = 20;
+}
+
+function bar() {
+    x--;
+    const x = 30;
+}
+
+function baz() {
+    x *= 40;
+    const x = 30;
+}
+
+function kaz() {
+    function captureX() { return x; }
+    x /= 20;
+    const x = 20;
+}
+
+function haz() {
+    function captureX() { return x; }
+    --x;
+    const x = 20;
+}
+
+function jaz() {
+    --x;
+    const x = 30;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(bar);
+    shouldThrowTDZ(baz);
+    shouldThrowTDZ(kaz);
+    shouldThrowTDZ(haz);
+    shouldThrowTDZ(jaz);
+}
+})();
+
+
+;(function() {
+function foo(x) {
+    const y = 50;
+    let result = null;
+    switch(x) {
+        case 10:
+            const y = 40;
+            assert(y === 40);
+        case 20:
+            y += 1;
+            assert(y === 41);
+            result = y;
+            break;
+        default:
+            result = x;
+            break;
+    }
+    assert(y === 50);
+    return result;
+}
+function bar(x) {
+    const y = 50;
+    let result = null;
+    switch(x) {
+        case 10:
+            const y = 40;
+            assert(y === 40);
+        case 20:
+            const capY = function() { return y; }
+            y += 1;
+            assert(y === 41);
+            result = y;
+            break;
+        default:
+            result = x;
+            break;
+    }
+    assert(y === 50);
+    return result;
+}
+function baz(x) {
+    const y = 50;
+    let result = null;
+    switch(x) {
+        case 10:
+            const y = 40;
+            assert(y === 40);
+        case 20:
+            let inc = function() { y += 1; }
+            inc();
+            assert(y === 41);
+            result = y;
+            break;
+        default:
+            result = x;
+            break;
+    }
+    assert(y === 50);
+    return result;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(function() { foo(20); });
+    shouldThrowTDZ(function() { bar(20); });
+    shouldThrowTDZ(function() { baz(20); });
+}
+})();
+
+
+;(function() {
+function foo() {
+    [x] = [1];
+    const x = null;
+}
+
+function boo() {
+    [x] = [1];
+    const x = 20;
+    function capX() { return x; }
+}
+
+function bar() {
+    ({a, p: y} = {a: 100, p: 40});
+    const y = 40;
+}
+
+function zar() {
+    ({a, p: y} = {a: 100, p: 40});
+    const y = 10;
+    function capY() { return y; }
+}
+
+function baz() {
+    ({a, p: {y}} = {a: 100, p: {p: {y: 40}}});
+    const y = 100;
+}
+
+function jaz() {
+    ({y} = {});
+    const y = null;
+}
+
+for (var i = 0; i < NUM_LOOPS; i++) {
+    shouldThrowTDZ(foo);
+    shouldThrowTDZ(boo);
+    shouldThrowTDZ(bar);
+    shouldThrowTDZ(zar);
+    shouldThrowTDZ(baz);
+    shouldThrowTDZ(jaz);
+}
+})();
index ba8e40d..d60d183 100644 (file)
@@ -1,3 +1,16 @@
+2015-07-18  Saam barati  <saambarati1@gmail.com>
+
+        [ES6] Add support for block scope const
+        https://bugs.webkit.org/show_bug.cgi?id=31813
+
+        Reviewed by Filip Pizlo.
+
+        "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:
+
 2015-07-16  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: REGRESSION (r186218) ScriptTimelineRecord attempts to access null property
index 5519e35..15460bb 100644 (file)
@@ -23,4 +23,4 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-const WebInspector = {}; // Namespace
+var WebInspector = {}; // Namespace