Block scoped variables should be visible across scripts
authorsaambarati1@gmail.com <saambarati1@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Sep 2015 19:45:44 +0000 (19:45 +0000)
committersaambarati1@gmail.com <saambarati1@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Sep 2015 19:45:44 +0000 (19:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147813

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch properly implements the global lexical tier described in
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation.
The sepcification mandates that there is a global lexical environment
that wrtaps all program execution. This global lexical environment
holds let/const/class variables defined at the top-level scope
inside a program. These variables can never shadow other program-level
"var"s, global object properties, or other global lexical environment
declarations. Doing so is a SyntaxError.

This patch adds new ResolveTypes that describe the global lexical environment:
GlobalLexicalVar and GlobalLexiclaVarWithInjectionChecks. Resolving to
these means we're doing a load/store from the JSGlobalLexicalEnvironment.
This patch also addes new ResolveTypes: UnresolvedProperty and
UnresolvedPropertyWithVarInjectionChecks. Before, we used GlobalProperty
to encompass this category because if JSScope::abstractAccess didn't
resolve to anything, we could safely assume that this property is
on the global object. Such an assumption is no longer true in ES6.
When we have a resolve_scope/put_to_scope/get_from_scope with this
ResolveType, we try to transition it to either a GlobalProperty
ResolveType or a GlobalLexicalVar resolve type.

JSGlobalLexicalEnvironment is a subclass of JSSegmentedVariableObject.
This means get_from_scopes are direct pointer reads and
put_to_scopes are direct pointer stores.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/EvalCodeCache.h:
(JSC::EvalCodeCache::clear):
(JSC::EvalCodeCache::isCacheableScope):
(JSC::EvalCodeCache::isCacheable):
* bytecode/SpeculatedType.h:
* bytecode/UnlinkedCodeBlock.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
(JSC::BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration):
(JSC::BytecodeGenerator::emitGetFromScope):
(JSC::BytecodeGenerator::emitPutToScope):
(JSC::BytecodeGenerator::initializeVariable):
(JSC::BytecodeGenerator::emitInstanceOf):
(JSC::BytecodeGenerator::emitPushFunctionNameScope):
(JSC::BytecodeGenerator::pushScopedControlFlowContext):
(JSC::BytecodeGenerator::emitPushCatchScope):
(JSC::BytecodeGenerator::emitPopCatchScope):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::EmptyLetExpression::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::BindingNode::bindValue):
* debugger/DebuggerScope.cpp:
(JSC::DebuggerScope::isGlobalScope):
(JSC::DebuggerScope::isGlobalLexicalEnvironment):
(JSC::DebuggerScope::isClosureScope):
(JSC::DebuggerScope::caughtValue):
(JSC::DebuggerScope::isFunctionOrEvalScope): Deleted.
* debugger/DebuggerScope.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasRegisterPointer):
(JSC::DFG::Node::variablePointer):
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStoreBarrierInsertionPhase.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
(JSC::FTL::DFG::LowerDFGToLLVM::compileMultiPutByOffset):
(JSC::FTL::DFG::LowerDFGToLLVM::compileGetGlobalVariable):
(JSC::FTL::DFG::LowerDFGToLLVM::compilePutGlobalVariable):
(JSC::FTL::DFG::LowerDFGToLLVM::compileGetGlobalVar): Deleted.
(JSC::FTL::DFG::LowerDFGToLLVM::compilePutGlobalVar): Deleted.
* inspector/JSJavaScriptCallFrame.cpp:
(Inspector::JSJavaScriptCallFrame::scopeType):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
* jit/JIT.h:
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emitSlow_op_resolve_scope):
(JSC::JIT::emitLoadWithStructureCheck):
(JSC::JIT::emitGetGlobalProperty):
(JSC::JIT::emitGetVarFromPointer):
(JSC::JIT::emitGetClosureVar):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitSlow_op_get_from_scope):
(JSC::JIT::emitPutGlobalProperty):
(JSC::JIT::emitPutGlobalVariable):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
(JSC::JIT::emitGetGlobalVar): Deleted.
(JSC::JIT::emitPutGlobalVar): Deleted.
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_resolve_scope):
(JSC::JIT::emitSlow_op_resolve_scope):
(JSC::JIT::emitLoadWithStructureCheck):
(JSC::JIT::emitGetGlobalProperty):
(JSC::JIT::emitGetVarFromPointer):
(JSC::JIT::emitGetClosureVar):
(JSC::JIT::emit_op_get_from_scope):
(JSC::JIT::emitSlow_op_get_from_scope):
(JSC::JIT::emitPutGlobalProperty):
(JSC::JIT::emitPutGlobalVariable):
(JSC::JIT::emit_op_put_to_scope):
(JSC::JIT::emitSlow_op_put_to_scope):
(JSC::JIT::emitGetGlobalVar): Deleted.
(JSC::JIT::emitPutGlobalVar): Deleted.
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::tryCachePutToScopeGlobal):
(JSC::CommonSlowPaths::tryCacheGetFromScopeGlobal):
* runtime/Executable.cpp:
(JSC::ProgramExecutable::initializeGlobalProperties):
* runtime/GetPutInfo.h: Added.
(JSC::resolveModeName):
(JSC::resolveTypeName):
(JSC::initializationModeName):
(JSC::makeType):
(JSC::needsVarInjectionChecks):
(JSC::ResolveOp::ResolveOp):
(JSC::GetPutInfo::GetPutInfo):
(JSC::GetPutInfo::resolveType):
(JSC::GetPutInfo::initializationMode):
(JSC::GetPutInfo::resolveMode):
(JSC::GetPutInfo::operand):
* runtime/JSGlobalLexicalEnvironment.cpp: Added.
(JSC::JSGlobalLexicalEnvironment::getOwnPropertySlot):
(JSC::JSGlobalLexicalEnvironment::put):
* runtime/JSGlobalLexicalEnvironment.h: Added.
(JSC::JSGlobalLexicalEnvironment::create):
(JSC::JSGlobalLexicalEnvironment::isEmpty):
(JSC::JSGlobalLexicalEnvironment::createStructure):
(JSC::JSGlobalLexicalEnvironment::JSGlobalLexicalEnvironment):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::put):
(JSC::JSGlobalObject::addGlobalVar):
(JSC::JSGlobalObject::visitChildren):
(JSC::JSGlobalObject::addStaticGlobals):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::addVar):
(JSC::JSGlobalObject::globalScope):
(JSC::JSGlobalObject::globalLexicalEnvironment):
(JSC::JSGlobalObject::hasOwnPropertyForWrite):
(JSC::constructEmptyArray):
(JSC::JSGlobalObject::symbolTableHasProperty): Deleted.
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncEval):
(JSC::globalFuncParseInt):
* runtime/JSLexicalEnvironment.h:
(JSC::JSLexicalEnvironment::createStructure):
* runtime/JSObject.h:
(JSC::JSObject::isGlobalObject):
(JSC::JSObject::isErrorInstance):
(JSC::JSObject::isVariableObject): Deleted.
(JSC::JSObject::isStaticScopeObject): Deleted.
(JSC::JSObject::isNameScopeObject): Deleted.
(JSC::JSObject::isActivationObject): Deleted.
* runtime/JSScope.cpp:
(JSC::JSScope::visitChildren):
(JSC::abstractAccess):
(JSC::JSScope::resolve):
(JSC::JSScope::abstractResolve):
(JSC::JSScope::collectVariablesUnderTDZ):
(JSC::isScopeType):
(JSC::JSScope::isVarScope):
(JSC::JSScope::isLexicalScope):
(JSC::JSScope::isCatchScope):
(JSC::JSScope::isFunctionNameScopeObject):
(JSC::JSScope::isGlobalLexicalEnvironment):
(JSC::JSScope::constantScopeForCodeBlock):
(JSC::resolveModeName): Deleted.
(JSC::resolveTypeName): Deleted.
* runtime/JSScope.h:
(JSC::makeType): Deleted.
(JSC::needsVarInjectionChecks): Deleted.
(JSC::ResolveOp::ResolveOp): Deleted.
(JSC::ResolveModeAndType::ResolveModeAndType): Deleted.
(JSC::ResolveModeAndType::mode): Deleted.
(JSC::ResolveModeAndType::type): Deleted.
(JSC::ResolveModeAndType::operand): Deleted.
* runtime/JSSegmentedVariableObject.cpp:
(JSC::JSSegmentedVariableObject::findVariableIndex):
(JSC::JSSegmentedVariableObject::addVariables):
* runtime/JSSegmentedVariableObject.h:
* runtime/JSSymbolTableObject.h:
(JSC::symbolTablePut):
* runtime/JSType.h:
* runtime/PutPropertySlot.h:
(JSC::PutPropertySlot::PutPropertySlot):
(JSC::PutPropertySlot::isCacheablePut):
(JSC::PutPropertySlot::isCacheableSetter):
(JSC::PutPropertySlot::isCacheableCustom):
(JSC::PutPropertySlot::isInitialization):
(JSC::PutPropertySlot::cachedOffset):
* runtime/SymbolTable.h:
* tests/stress/global-lexical-let-no-rhs.js: Added.
(assert):
(foo):
* tests/stress/global-lexical-redeclare-variable.js: Added.
(globalFunction):
(globalClass):
(assert):
(assertExpectations):
(assertProperError):
* tests/stress/global-lexical-redefine-const.js: Added.
* tests/stress/global-lexical-var-injection.js: Added.
(assert):
(baz):
* tests/stress/global-lexical-variable-tdz.js: Added.
* tests/stress/global-lexical-variable-unresolved-property.js: Added.
* tests/stress/global-lexical-variable-with-statement.js: Added.
(assert):
(shouldThrowInvalidConstAssignment):
(makeObj):
* tests/stress/multiple-files-tests: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fifth.js: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable/first.js: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fourth.js: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable/second.js: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable/sixth.js: Added.
* tests/stress/multiple-files-tests/global-lexical-redeclare-variable/third.js: Added.
* tests/stress/multiple-files-tests/global-lexical-redefine-const: Added.
* tests/stress/multiple-files-tests/global-lexical-redefine-const/first.js: Added.
(assert):
(shouldThrowInvalidConstAssignment):
* tests/stress/multiple-files-tests/global-lexical-redefine-const/second.js: Added.
(foo):
(bar):
(baz):
* tests/stress/multiple-files-tests/global-lexical-variable-tdz: Added.
* tests/stress/multiple-files-tests/global-lexical-variable-tdz/first.js: Added.
(assert):
(shouldThrowTDZ):
(foo):
(bar):
* tests/stress/multiple-files-tests/global-lexical-variable-tdz/second.js: Added.
* tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property: Added.
* tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/first.js: Added.
(assert):
(shouldThrowTDZ):
(foo):
* tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/second.js: Added.

LayoutTests:

* js/dom/const-expected.txt:
* js/dom/const.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@189279 268f45cc-cd09-0410-ab3c-d52691b4dbfc

84 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/const-expected.txt
LayoutTests/js/dom/const.html
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/EvalCodeCache.h
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/debugger/DebuggerScope.cpp
Source/JavaScriptCore/debugger/DebuggerScope.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/inspector/JSJavaScriptCallFrame.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/llint/LLIntData.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/GetPutInfo.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
Source/JavaScriptCore/runtime/JSLexicalEnvironment.h
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSScope.cpp
Source/JavaScriptCore/runtime/JSScope.h
Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp
Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h
Source/JavaScriptCore/runtime/JSSymbolTableObject.h
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/PutPropertySlot.h
Source/JavaScriptCore/runtime/SymbolTable.h
Source/JavaScriptCore/tests/stress/global-lexical-let-no-rhs.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/global-lexical-redeclare-variable.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/global-lexical-redefine-const.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/global-lexical-var-injection.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/global-lexical-variable-tdz.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/global-lexical-variable-unresolved-property.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/global-lexical-variable-with-statement.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fifth.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/first.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fourth.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/second.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/sixth.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/third.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redefine-const/first.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redefine-const/second.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-tdz/first.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-tdz/second.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/first.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/second.js [new file with mode: 0644]

index 4fa4967..f735d34 100644 (file)
@@ -1,3 +1,13 @@
+2015-09-03  Saam barati  <sbarati@apple.com>
+
+        Block scoped variables should be visible across scripts
+        https://bugs.webkit.org/show_bug.cgi?id=147813
+
+        Reviewed by Filip Pizlo.
+
+        * js/dom/const-expected.txt:
+        * js/dom/const.html:
+
 2015-09-02  Ryosuke Niwa  <rniwa@webkit.org>
 
         MutationObserver should accept attributeFilter, attributeOldValue, and characterDataOldValue on their own
index fee9af0..79245e7 100644 (file)
@@ -1,10 +1,8 @@
-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".
-
+CONSOLE MESSAGE: SyntaxError: Can't create duplicate variable that shadows a global property: 'bodyId'
+This test checks that const variables can't shadow global object properties. Note that this test expects SyntaxErrors in below
 
+PASS sentinel is "__s__"
 PASS bodyId is document.getElementById('bodyId')
-PASS ranConstInitialiser is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 6e1271a..8e0fac0 100644 (file)
@@ -5,17 +5,28 @@
 <script src="../../resources/js-test-pre.js"></script>
 </head>
 <body id="bodyId">
+
 <script>
+
 description(
-"This test checks that const declarations in JavaScript work and are readonly."
+    "This test checks that const variables can't shadow global object properties.  Note that this test expects SyntaxErrors in below <script>"
 );
 
-// Make sure we don't override properties placed on the global object
-var ranConstInitialiser = false;
-const bodyId = (ranConstInitialiser = true, "Const initialiser overwrote existing property");
+let sentinel = "__s__";
+</script>
+
+<script>
+// Make sure we can't override properties placed on the global object
+const bodyId = "lah la lah la lah, I should never execute.";
+sentinel = "bad";
+</script>
+
+<script>
+shouldBe("sentinel", '"__s__"');
 shouldBe("bodyId", "document.getElementById('bodyId')");
-shouldBeTrue("ranConstInitialiser");
+successfullyParsed = true;
 </script>
+
 <script src="../../resources/js-test-post.js"></script>
 </body>
 </html>
index 68060a6..2d30bb9 100644 (file)
@@ -525,6 +525,7 @@ set(JavaScriptCore_RUNTIME_SOURCES
     runtime/JSDateMath.cpp
     runtime/JSEnvironmentRecord.cpp
     runtime/JSFunction.cpp
+    runtime/JSGlobalLexicalEnvironment.cpp
     runtime/JSGlobalObject.cpp
     runtime/JSGlobalObjectDebuggable.cpp
     runtime/JSGlobalObjectFunctions.cpp
index 5c3345f..26c847a 100644 (file)
@@ -1,3 +1,300 @@
+2015-09-03  Saam barati  <sbarati@apple.com>
+
+        Block scoped variables should be visible across scripts
+        https://bugs.webkit.org/show_bug.cgi?id=147813
+
+        Reviewed by Filip Pizlo.
+
+        This patch properly implements the global lexical tier described in
+        http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation.
+        The sepcification mandates that there is a global lexical environment
+        that wrtaps all program execution. This global lexical environment
+        holds let/const/class variables defined at the top-level scope
+        inside a program. These variables can never shadow other program-level
+        "var"s, global object properties, or other global lexical environment
+        declarations. Doing so is a SyntaxError.
+
+        This patch adds new ResolveTypes that describe the global lexical environment:
+        GlobalLexicalVar and GlobalLexiclaVarWithInjectionChecks. Resolving to
+        these means we're doing a load/store from the JSGlobalLexicalEnvironment.
+        This patch also addes new ResolveTypes: UnresolvedProperty and
+        UnresolvedPropertyWithVarInjectionChecks. Before, we used GlobalProperty
+        to encompass this category because if JSScope::abstractAccess didn't
+        resolve to anything, we could safely assume that this property is
+        on the global object. Such an assumption is no longer true in ES6.
+        When we have a resolve_scope/put_to_scope/get_from_scope with this
+        ResolveType, we try to transition it to either a GlobalProperty
+        ResolveType or a GlobalLexicalVar resolve type.
+
+        JSGlobalLexicalEnvironment is a subclass of JSSegmentedVariableObject.
+        This means get_from_scopes are direct pointer reads and
+        put_to_scopes are direct pointer stores.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::finalizeUnconditionally):
+        * bytecode/EvalCodeCache.h:
+        (JSC::EvalCodeCache::clear):
+        (JSC::EvalCodeCache::isCacheableScope):
+        (JSC::EvalCodeCache::isCacheable):
+        * bytecode/SpeculatedType.h:
+        * bytecode/UnlinkedCodeBlock.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
+        (JSC::BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration):
+        (JSC::BytecodeGenerator::emitGetFromScope):
+        (JSC::BytecodeGenerator::emitPutToScope):
+        (JSC::BytecodeGenerator::initializeVariable):
+        (JSC::BytecodeGenerator::emitInstanceOf):
+        (JSC::BytecodeGenerator::emitPushFunctionNameScope):
+        (JSC::BytecodeGenerator::pushScopedControlFlowContext):
+        (JSC::BytecodeGenerator::emitPushCatchScope):
+        (JSC::BytecodeGenerator::emitPopCatchScope):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::PostfixNode::emitResolve):
+        (JSC::PrefixNode::emitResolve):
+        (JSC::ReadModifyResolveNode::emitBytecode):
+        (JSC::AssignResolveNode::emitBytecode):
+        (JSC::EmptyLetExpression::emitBytecode):
+        (JSC::ForInNode::emitLoopHeader):
+        (JSC::ForOfNode::emitBytecode):
+        (JSC::BindingNode::bindValue):
+        * debugger/DebuggerScope.cpp:
+        (JSC::DebuggerScope::isGlobalScope):
+        (JSC::DebuggerScope::isGlobalLexicalEnvironment):
+        (JSC::DebuggerScope::isClosureScope):
+        (JSC::DebuggerScope::caughtValue):
+        (JSC::DebuggerScope::isFunctionOrEvalScope): Deleted.
+        * debugger/DebuggerScope.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasRegisterPointer):
+        (JSC::DFG::Node::variablePointer):
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStoreBarrierInsertionPhase.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileMultiPutByOffset):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileGetGlobalVariable):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compilePutGlobalVariable):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileGetGlobalVar): Deleted.
+        (JSC::FTL::DFG::LowerDFGToLLVM::compilePutGlobalVar): Deleted.
+        * inspector/JSJavaScriptCallFrame.cpp:
+        (Inspector::JSJavaScriptCallFrame::scopeType):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::execute):
+        * jit/JIT.h:
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_resolve_scope):
+        (JSC::JIT::emitSlow_op_resolve_scope):
+        (JSC::JIT::emitLoadWithStructureCheck):
+        (JSC::JIT::emitGetGlobalProperty):
+        (JSC::JIT::emitGetVarFromPointer):
+        (JSC::JIT::emitGetClosureVar):
+        (JSC::JIT::emit_op_get_from_scope):
+        (JSC::JIT::emitSlow_op_get_from_scope):
+        (JSC::JIT::emitPutGlobalProperty):
+        (JSC::JIT::emitPutGlobalVariable):
+        (JSC::JIT::emit_op_put_to_scope):
+        (JSC::JIT::emitSlow_op_put_to_scope):
+        (JSC::JIT::emitGetGlobalVar): Deleted.
+        (JSC::JIT::emitPutGlobalVar): Deleted.
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_resolve_scope):
+        (JSC::JIT::emitSlow_op_resolve_scope):
+        (JSC::JIT::emitLoadWithStructureCheck):
+        (JSC::JIT::emitGetGlobalProperty):
+        (JSC::JIT::emitGetVarFromPointer):
+        (JSC::JIT::emitGetClosureVar):
+        (JSC::JIT::emit_op_get_from_scope):
+        (JSC::JIT::emitSlow_op_get_from_scope):
+        (JSC::JIT::emitPutGlobalProperty):
+        (JSC::JIT::emitPutGlobalVariable):
+        (JSC::JIT::emit_op_put_to_scope):
+        (JSC::JIT::emitSlow_op_put_to_scope):
+        (JSC::JIT::emitGetGlobalVar): Deleted.
+        (JSC::JIT::emitPutGlobalVar): Deleted.
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        (JSC::CommonSlowPaths::tryCachePutToScopeGlobal):
+        (JSC::CommonSlowPaths::tryCacheGetFromScopeGlobal):
+        * runtime/Executable.cpp:
+        (JSC::ProgramExecutable::initializeGlobalProperties):
+        * runtime/GetPutInfo.h: Added.
+        (JSC::resolveModeName):
+        (JSC::resolveTypeName):
+        (JSC::initializationModeName):
+        (JSC::makeType):
+        (JSC::needsVarInjectionChecks):
+        (JSC::ResolveOp::ResolveOp):
+        (JSC::GetPutInfo::GetPutInfo):
+        (JSC::GetPutInfo::resolveType):
+        (JSC::GetPutInfo::initializationMode):
+        (JSC::GetPutInfo::resolveMode):
+        (JSC::GetPutInfo::operand):
+        * runtime/JSGlobalLexicalEnvironment.cpp: Added.
+        (JSC::JSGlobalLexicalEnvironment::getOwnPropertySlot):
+        (JSC::JSGlobalLexicalEnvironment::put):
+        * runtime/JSGlobalLexicalEnvironment.h: Added.
+        (JSC::JSGlobalLexicalEnvironment::create):
+        (JSC::JSGlobalLexicalEnvironment::isEmpty):
+        (JSC::JSGlobalLexicalEnvironment::createStructure):
+        (JSC::JSGlobalLexicalEnvironment::JSGlobalLexicalEnvironment):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::put):
+        (JSC::JSGlobalObject::addGlobalVar):
+        (JSC::JSGlobalObject::visitChildren):
+        (JSC::JSGlobalObject::addStaticGlobals):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::addVar):
+        (JSC::JSGlobalObject::globalScope):
+        (JSC::JSGlobalObject::globalLexicalEnvironment):
+        (JSC::JSGlobalObject::hasOwnPropertyForWrite):
+        (JSC::constructEmptyArray):
+        (JSC::JSGlobalObject::symbolTableHasProperty): Deleted.
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncEval):
+        (JSC::globalFuncParseInt):
+        * runtime/JSLexicalEnvironment.h:
+        (JSC::JSLexicalEnvironment::createStructure):
+        * runtime/JSObject.h:
+        (JSC::JSObject::isGlobalObject):
+        (JSC::JSObject::isErrorInstance):
+        (JSC::JSObject::isVariableObject): Deleted.
+        (JSC::JSObject::isStaticScopeObject): Deleted.
+        (JSC::JSObject::isNameScopeObject): Deleted.
+        (JSC::JSObject::isActivationObject): Deleted.
+        * runtime/JSScope.cpp:
+        (JSC::JSScope::visitChildren):
+        (JSC::abstractAccess):
+        (JSC::JSScope::resolve):
+        (JSC::JSScope::abstractResolve):
+        (JSC::JSScope::collectVariablesUnderTDZ):
+        (JSC::isScopeType):
+        (JSC::JSScope::isVarScope):
+        (JSC::JSScope::isLexicalScope):
+        (JSC::JSScope::isCatchScope):
+        (JSC::JSScope::isFunctionNameScopeObject):
+        (JSC::JSScope::isGlobalLexicalEnvironment):
+        (JSC::JSScope::constantScopeForCodeBlock):
+        (JSC::resolveModeName): Deleted.
+        (JSC::resolveTypeName): Deleted.
+        * runtime/JSScope.h:
+        (JSC::makeType): Deleted.
+        (JSC::needsVarInjectionChecks): Deleted.
+        (JSC::ResolveOp::ResolveOp): Deleted.
+        (JSC::ResolveModeAndType::ResolveModeAndType): Deleted.
+        (JSC::ResolveModeAndType::mode): Deleted.
+        (JSC::ResolveModeAndType::type): Deleted.
+        (JSC::ResolveModeAndType::operand): Deleted.
+        * runtime/JSSegmentedVariableObject.cpp:
+        (JSC::JSSegmentedVariableObject::findVariableIndex):
+        (JSC::JSSegmentedVariableObject::addVariables):
+        * runtime/JSSegmentedVariableObject.h:
+        * runtime/JSSymbolTableObject.h:
+        (JSC::symbolTablePut):
+        * runtime/JSType.h:
+        * runtime/PutPropertySlot.h:
+        (JSC::PutPropertySlot::PutPropertySlot):
+        (JSC::PutPropertySlot::isCacheablePut):
+        (JSC::PutPropertySlot::isCacheableSetter):
+        (JSC::PutPropertySlot::isCacheableCustom):
+        (JSC::PutPropertySlot::isInitialization):
+        (JSC::PutPropertySlot::cachedOffset):
+        * runtime/SymbolTable.h:
+        * tests/stress/global-lexical-let-no-rhs.js: Added.
+        (assert):
+        (foo):
+        * tests/stress/global-lexical-redeclare-variable.js: Added.
+        (globalFunction):
+        (globalClass):
+        (assert):
+        (assertExpectations):
+        (assertProperError):
+        * tests/stress/global-lexical-redefine-const.js: Added.
+        * tests/stress/global-lexical-var-injection.js: Added.
+        (assert):
+        (baz):
+        * tests/stress/global-lexical-variable-tdz.js: Added.
+        * tests/stress/global-lexical-variable-unresolved-property.js: Added.
+        * tests/stress/global-lexical-variable-with-statement.js: Added.
+        (assert):
+        (shouldThrowInvalidConstAssignment):
+        (makeObj):
+        * tests/stress/multiple-files-tests: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fifth.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable/first.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fourth.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable/second.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable/sixth.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redeclare-variable/third.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redefine-const: Added.
+        * tests/stress/multiple-files-tests/global-lexical-redefine-const/first.js: Added.
+        (assert):
+        (shouldThrowInvalidConstAssignment):
+        * tests/stress/multiple-files-tests/global-lexical-redefine-const/second.js: Added.
+        (foo):
+        (bar):
+        (baz):
+        * tests/stress/multiple-files-tests/global-lexical-variable-tdz: Added.
+        * tests/stress/multiple-files-tests/global-lexical-variable-tdz/first.js: Added.
+        (assert):
+        (shouldThrowTDZ):
+        (foo):
+        (bar):
+        * tests/stress/multiple-files-tests/global-lexical-variable-tdz/second.js: Added.
+        * tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property: Added.
+        * tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/first.js: Added.
+        (assert):
+        (shouldThrowTDZ):
+        (foo):
+        * tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/second.js: Added.
+
 2015-09-03  Filip Pizlo  <fpizlo@apple.com>
 
         RepatchBuffer should be stateless
index 39963b4..42cc5f5 100644 (file)
     <ClCompile Include="..\runtime\JSFunction.cpp" />
     <ClCompile Include="..\runtime\JSGlobalObject.cpp" />
     <ClCompile Include="..\runtime\JSGlobalObjectFunctions.cpp" />
+    <ClCompile Include="..\runtime\JSGlobalLexicalEnvironment.cpp" />
     <ClCompile Include="..\runtime\JSInternalPromise.cpp" />
     <ClCompile Include="..\runtime\JSInternalPromiseConstructor.cpp" />
     <ClCompile Include="..\runtime\JSInternalPromiseDeferred.cpp" />
     <ClInclude Include="..\runtime\GenericOffset.h" />
     <ClInclude Include="..\runtime\GenericTypedArrayView.h" />
     <ClInclude Include="..\runtime\GenericTypedArrayViewInlines.h" />
+    <ClInclude Include="..\runtime\GetPutInfo.h" />
     <ClInclude Include="..\runtime\GetterSetter.h" />
     <ClInclude Include="..\runtime\Identifier.h" />
     <ClInclude Include="..\runtime\IndexingHeader.h" />
     <ClInclude Include="..\runtime\JSGenericTypedArrayViewPrototypeInlines.h" />
     <ClInclude Include="..\runtime\JSGlobalObject.h" />
     <ClInclude Include="..\runtime\JSGlobalObjectFunctions.h" />
+    <ClInclude Include="..\runtime\JSGlobalLexicalEnvironment.h" />
     <ClInclude Include="..\runtime\JSJob.h" />
     <ClInclude Include="..\runtime\JSInt16Array.h" />
     <ClInclude Include="..\runtime\JSInt32Array.h" />
index 2bf7180..5da4fe3 100644 (file)
     <ClCompile Include="..\runtime\JSGlobalObjectFunctions.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
+    <ClCompile Include="..\runtime\JSGlobalLexicalEnvironment.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
     <ClCompile Include="..\runtime\JSJob.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
     <ClInclude Include="..\runtime\FunctionRareData.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\GetPutInfo.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\GetterSetter.h">
       <Filter>runtime</Filter>
     </ClInclude>
     <ClInclude Include="..\runtime\JSGlobalObjectFunctions.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\JSGlobalLexicalEnvironment.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\JSJob.h">
       <Filter>runtime</Filter>
     </ClInclude>
index f22e716..f1fd3b5 100644 (file)
                70ECA6071AFDBEA200449739 /* TemplateRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70ECA6021AFDBEA200449739 /* TemplateRegistry.cpp */; };
                70ECA6081AFDBEA200449739 /* TemplateRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6031AFDBEA200449739 /* TemplateRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70ECA6091AFDBEA200449739 /* TemplateRegistryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6041AFDBEA200449739 /* TemplateRegistryKey.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */; };
+               797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
                79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */; };
                79EE0C001B4AFB85000385C9 /* VariableEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7B0247551B8682DD00542440 /* WASMConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B0247521B8682D500542440 /* WASMConstants.h */; settings = {ATTRIBUTES = (Private, ); }; };
                70ECA6021AFDBEA200449739 /* TemplateRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateRegistry.cpp; sourceTree = "<group>"; };
                70ECA6031AFDBEA200449739 /* TemplateRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateRegistry.h; sourceTree = "<group>"; };
                70ECA6041AFDBEA200449739 /* TemplateRegistryKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateRegistryKey.h; sourceTree = "<group>"; };
+               796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; };
+               797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalLexicalEnvironment.cpp; sourceTree = "<group>"; };
+               797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalLexicalEnvironment.h; sourceTree = "<group>"; };
                79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableEnvironment.cpp; sourceTree = "<group>"; };
                79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableEnvironment.h; sourceTree = "<group>"; };
                7B0247521B8682D500542440 /* WASMConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMConstants.h; sourceTree = "<group>"; };
                                0FE050131AA9091100D33B33 /* GenericOffset.h */,
                                0F2B66B217B6B5AB00A7AE3F /* GenericTypedArrayView.h */,
                                0F2B66B317B6B5AB00A7AE3F /* GenericTypedArrayViewInlines.h */,
+                               796465681B952FF0003059EE /* GetPutInfo.h */,
                                BC02E9B80E184545000F9297 /* GetterSetter.cpp */,
                                BC337BDE0E1AF0B80076918A /* GetterSetter.h */,
                                933A349D038AE80F008635CE /* Identifier.cpp */,
                                0F2B66C817B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototypeInlines.h */,
                                14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */,
                                A8E894330CD0603F00367179 /* JSGlobalObject.h */,
+                               797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */,
+                               797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */,
                                A59455901824744700CC3843 /* JSGlobalObjectDebuggable.cpp */,
                                A59455911824744700CC3843 /* JSGlobalObjectDebuggable.h */,
                                BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */,
                                A1A009C11831A26E00CF8711 /* ARM64Assembler.h in Headers */,
                                0F898F321B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h in Headers */,
                                86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
+                               7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */,
+                               797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */,
                                0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */,
                                52C0611F1AA51E1C00B4ADBA /* RuntimeType.h in Headers */,
                                FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */,
                                0F55F0F414D1063900AC7649 /* AbstractPC.cpp in Sources */,
                                147F39BD107EC37600427A48 /* ArgList.cpp in Sources */,
                                0F6B1CC918641DF800845D97 /* ArityCheckFailReturnThunks.cpp in Sources */,
+                               797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */,
                                E3794E751B77EB97005543AE /* ModuleAnalyzer.cpp in Sources */,
                                0F743BAA16B88249009F9277 /* ARM64Disassembler.cpp in Sources */,
                                86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */,
index f68f304..f12046c 100644 (file)
@@ -41,6 +41,7 @@
 #include "DFGWorklist.h"
 #include "Debugger.h"
 #include "FunctionExecutableDump.h"
+#include "GetPutInfo.h"
 #include "InlineCallFrame.h"
 #include "Interpreter.h"
 #include "JIT.h"
@@ -1518,20 +1519,18 @@ void CodeBlock::dumpBytecode(
             int r0 = (++it)->u.operand;
             int scope = (++it)->u.operand;
             int id0 = (++it)->u.operand;
-            ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
+            ResolveType resolveType = static_cast<ResolveType>((++it)->u.operand);
             int depth = (++it)->u.operand;
+            void* pointer = (++it)->u.pointer;
             printLocationAndOp(out, exec, location, it, "resolve_scope");
-            out.printf("%s, %s, %s, %u<%s|%s>, %d", registerName(r0).data(), registerName(scope).data(), idName(id0, identifier(id0)).data(),
-                modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
-                depth);
-            ++it;
+            out.printf("%s, %s, %s, <%s>, %d, %p", registerName(r0).data(), registerName(scope).data(), idName(id0, identifier(id0)).data(), resolveTypeName(resolveType), depth, pointer);
             break;
         }
         case op_get_from_scope: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
-            ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
+            GetPutInfo getPutInfo = GetPutInfo((++it)->u.operand);
             ++it; // Structure
             int operand = (++it)->u.operand; // Operand
             printLocationAndOp(out, exec, location, it, "get_from_scope");
@@ -1540,7 +1539,7 @@ void CodeBlock::dumpBytecode(
                 out.print(", anonymous");
             else
                 out.print(", ", idName(id0, identifier(id0)));
-            out.print(", ", modeAndType.operand(), "<", resolveModeName(modeAndType.mode()), "|", resolveTypeName(modeAndType.type()), ">, ", operand);
+            out.print(", ", getPutInfo.operand(), "<", resolveModeName(getPutInfo.resolveMode()), "|", resolveTypeName(getPutInfo.resolveType()), "|", initializationModeName(getPutInfo.initializationMode()), ">, ", operand);
             dumpValueProfiling(out, it, hasPrintedProfiling);
             break;
         }
@@ -1548,7 +1547,7 @@ void CodeBlock::dumpBytecode(
             int r0 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
-            ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
+            GetPutInfo getPutInfo = GetPutInfo((++it)->u.operand);
             ++it; // Structure
             int operand = (++it)->u.operand; // Operand
             printLocationAndOp(out, exec, location, it, "put_to_scope");
@@ -1557,7 +1556,7 @@ void CodeBlock::dumpBytecode(
                 out.print(", anonymous");
             else
                 out.print(", ", idName(id0, identifier(id0)));
-            out.print(", ", registerName(r1), ", ", modeAndType.operand(), "<", resolveModeName(modeAndType.mode()), "|", resolveTypeName(modeAndType.type()), ">, <structure>, ", operand);
+            out.print(", ", registerName(r1), ", ", getPutInfo.operand(), "<", resolveModeName(getPutInfo.resolveMode()), "|", resolveTypeName(getPutInfo.resolveType()), "|", initializationModeName(getPutInfo.initializationMode()), ">, <structure>, ", operand);
             break;
         }
         case op_get_from_arguments: {
@@ -1971,11 +1970,13 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             RELEASE_ASSERT(type != LocalClosureVar);
             int localScopeDepth = pc[5].u.operand;
 
-            ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, type);
+            ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, type, NotInitialization);
             instructions[i + 4].u.operand = op.type;
             instructions[i + 5].u.operand = op.depth;
             if (op.lexicalEnvironment)
                 instructions[i + 6].u.symbolTable.set(*vm(), ownerExecutable, op.lexicalEnvironment->symbolTable());
+            else if (JSScope* constantScope = JSScope::constantScopeForCodeBlock(op.type, this))
+                instructions[i + 6].u.jsCell.set(*vm(), ownerExecutable, constantScope);
             else
                 instructions[i + 6].u.pointer = nullptr;
             break;
@@ -1987,22 +1988,23 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             profile->m_bytecodeOffset = i;
             instructions[i + opLength - 1] = profile;
 
-            // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand
+            // get_from_scope dst, scope, id, GetPutInfo, Structure, Operand
 
             int localScopeDepth = pc[5].u.operand;
             instructions[i + 5].u.pointer = nullptr;
 
-            ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
-            if (modeAndType.type() == LocalClosureVar) {
-                instructions[i + 4] = ResolveModeAndType(modeAndType.mode(), ClosureVar).operand();
+            GetPutInfo getPutInfo = GetPutInfo(pc[4].u.operand);
+            ASSERT(getPutInfo.initializationMode() == NotInitialization);
+            if (getPutInfo.resolveType() == LocalClosureVar) {
+                instructions[i + 4] = GetPutInfo(getPutInfo.resolveMode(), ClosureVar, getPutInfo.initializationMode()).operand();
                 break;
             }
 
             const Identifier& ident = identifier(pc[3].u.operand);
-            ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, modeAndType.type());
+            ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, getPutInfo.resolveType(), NotInitialization);
 
-            instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
-            if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
+            instructions[i + 4].u.operand = GetPutInfo(getPutInfo.resolveMode(), op.type, getPutInfo.initializationMode()).operand();
+            if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks || op.type == GlobalLexicalVar || op.type == GlobalLexicalVarWithVarInjectionChecks)
                 instructions[i + 5].u.watchpointSet = op.watchpointSet;
             else if (op.structure)
                 instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
@@ -2011,9 +2013,9 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
         }
 
         case op_put_to_scope: {
-            // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
-            ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
-            if (modeAndType.type() == LocalClosureVar) {
+            // put_to_scope scope, id, value, GetPutInfo, Structure, Operand
+            GetPutInfo getPutInfo = GetPutInfo(pc[4].u.operand);
+            if (getPutInfo.resolveType() == LocalClosureVar) {
                 // Only do watching if the property we're putting to is not anonymous.
                 if (static_cast<unsigned>(pc[2].u.operand) != UINT_MAX) {
                     int symbolTableIndex = pc[5].u.operand;
@@ -2033,10 +2035,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
             const Identifier& ident = identifier(pc[2].u.operand);
             int localScopeDepth = pc[5].u.operand;
             instructions[i + 5].u.pointer = nullptr;
-            ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Put, modeAndType.type());
+            ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Put, getPutInfo.resolveType(), getPutInfo.initializationMode());
 
-            instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
-            if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
+            instructions[i + 4].u.operand = GetPutInfo(getPutInfo.resolveMode(), op.type, getPutInfo.initializationMode()).operand();
+            if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks || op.type == GlobalLexicalVar || op.type == GlobalLexicalVarWithVarInjectionChecks)
                 instructions[i + 5].u.watchpointSet = op.watchpointSet;
             else if (op.type == ClosureVar || op.type == ClosureVarWithVarInjectionChecks) {
                 if (op.watchpointSet)
@@ -2067,7 +2069,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
                 ResolveType type = static_cast<ResolveType>(pc[5].u.operand);
                 // Even though type profiling may be profiling either a Get or a Put, we can always claim a Get because
                 // we're abstractly "read"ing from a JSScope.
-                ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, type);
+                ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), localScopeDepth, scope, ident, Get, type, NotInitialization);
 
                 if (op.type == ClosureVar)
                     symbolTable = op.lexicalEnvironment->symbolTable();
@@ -2621,9 +2623,9 @@ void CodeBlock::finalizeUnconditionally()
             }
             case op_get_from_scope:
             case op_put_to_scope: {
-                ResolveModeAndType modeAndType =
-                    ResolveModeAndType(curInstruction[4].u.operand);
-                if (modeAndType.type() == GlobalVar || modeAndType.type() == GlobalVarWithVarInjectionChecks || modeAndType.type() == LocalClosureVar)
+                GetPutInfo getPutInfo = GetPutInfo(curInstruction[4].u.operand);
+                if (getPutInfo.resolveType() == GlobalVar || getPutInfo.resolveType() == GlobalVarWithVarInjectionChecks 
+                    || getPutInfo.resolveType() == LocalClosureVar || getPutInfo.resolveType() == GlobalLexicalVar || getPutInfo.resolveType() == GlobalLexicalVarWithVarInjectionChecks)
                     continue;
                 WriteBarrierBase<Structure>& structure = curInstruction[5].u.structure;
                 if (!structure || Heap::isMarked(structure.get()))
index 4d59093..7a89898 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "Executable.h"
 #include "JSGlobalObject.h"
+#include "JSScope.h"
 #include "Options.h"
 #include "SourceCode.h"
 #include <wtf/HashMap.h>
@@ -74,15 +75,18 @@ namespace JSC {
         }
 
     private:
-        ALWAYS_INLINE bool isCacheable(bool inStrictContext, const String& evalSource, JSScope* scope) const
+        ALWAYS_INLINE bool isCacheableScope(JSScope* scope)
+        {
+            return scope->isGlobalLexicalEnvironment() || scope->isFunctionNameScopeObject() || scope->isVarScope();
+        }
+
+        ALWAYS_INLINE bool isCacheable(bool inStrictContext, const String& evalSource, JSScope* scope)
         {
             // If eval() is called and it has access to a lexical scope, we can't soundly cache it.
             // If the eval() only has access to the "var" scope, then we can cache it.
             return !inStrictContext 
                 && evalSource.length() < Options::maximumEvalCacheableSourceLength() 
-                && scope->begin()->isVariableObject()
-                && !scope->isLexicalScope()
-                && !scope->isCatchScope();
+                && isCacheableScope(scope);
         }
         static const int maxCacheEntries = 64;
 
index bd045c3..e695d79 100644 (file)
@@ -86,7 +86,7 @@ static const SpeculatedType SpecOther              = 0x20000000; // It's definit
 static const SpeculatedType SpecMisc               = 0x30000000; // It's definitely either a boolean, Null, or Undefined.
 static const SpeculatedType SpecHeapTop            = 0x3bbfffff; // It can be any of the above, except for SpecInt52.
 static const SpeculatedType SpecEmpty              = 0x40000000; // It's definitely an empty value marker.
-static const SpeculatedType SpecBytecodeTop        = 0x7bbfffff; // It can be any of the above, except for SpecInt52.
+static const SpeculatedType SpecBytecodeTop        = 0x7bbfffff; // It can be any of the above, except for SpecInt52. This is (SpecHeapTop | SpecEmpty).
 static const SpeculatedType SpecFullTop            = 0x7fffffff; // It can be any of the above plus anything the DFG chooses.
 
 typedef bool (*SpeculatedTypeChecker)(SpeculatedType);
index 4095a90..f749bb0 100644 (file)
@@ -490,6 +490,9 @@ public:
     void setVariableDeclarations(const VariableEnvironment& environment) { m_varDeclarations = environment; }
     const VariableEnvironment& variableDeclarations() const { return m_varDeclarations; }
 
+    void setLexicalDeclarations(const VariableEnvironment& environment) { m_lexicalDeclarations = environment; }
+    const VariableEnvironment& lexicalDeclarations() const { return m_lexicalDeclarations; }
+
     static void visitChildren(JSCell*, SlotVisitor&);
 
 private:
@@ -499,6 +502,7 @@ private:
     }
 
     VariableEnvironment m_varDeclarations;
+    VariableEnvironment m_lexicalDeclarations;
 
 public:
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
index 783b215..5089f56 100644 (file)
@@ -70,22 +70,25 @@ ParserError BytecodeGenerator::generate()
     if (m_needToInitializeArguments)
         initializeVariable(variable(propertyNames().arguments), m_argumentsRegister);
 
-    // For ModuleCode, we already instantiated the environment for the lexical variables.
-    if (m_codeType != ModuleCode)
-        pushLexicalScope(m_scopeNode, true);
-
     {
         RefPtr<RegisterID> temp = newTemporary();
-        RefPtr<RegisterID> globalScope = m_topMostScope;
+        RefPtr<RegisterID> globalScope;
         for (auto functionPair : m_functionsToInitialize) {
             FunctionMetadataNode* metadata = functionPair.first;
             FunctionVariableType functionType = functionPair.second;
             emitNewFunction(temp.get(), metadata);
             if (functionType == NormalFunctionVariable)
-                initializeVariable(variable(metadata->ident()) , temp.get());
-            else if (functionType == GlobalFunctionVariable)
-                emitPutToScope(globalScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound);
-            else
+                initializeVariable(variable(metadata->ident()), temp.get());
+            else if (functionType == GlobalFunctionVariable) {
+                if (!globalScope) {
+                    // We know this will resolve to the global object because our parser/global initialization code 
+                    // doesn't allow let/const/class variables to have the same names as functions.
+                    RefPtr<RegisterID> globalObjectScope = emitResolveScope(nullptr, Variable(metadata->ident())); 
+                    globalScope = newBlockScopeVariable(); 
+                    emitMove(globalScope.get(), globalObjectScope.get());
+                }
+                emitPutToScope(globalScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound, NotInitialization);
+            } else
                 RELEASE_ASSERT_NOT_REACHED();
         }
     }
@@ -172,6 +175,11 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP
             RELEASE_ASSERT(entry.value.isVar());
     }
     codeBlock->setVariableDeclarations(programNode->varDeclarations());
+    codeBlock->setLexicalDeclarations(programNode->lexicalVariables());
+    // Even though this program may have lexical variables that go under TDZ, when linking the get_from_scope/put_to_scope
+    // operations we emit we will have ResolveTypes that implictly do TDZ checks. Therefore, we don't need
+    // additional TDZ checks on top of those. This is why we can omit pushing programNode->lexicalVariables()
+    // to the TDZ stack.
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables)
@@ -318,7 +326,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
                 instructions().append(m_lexicalEnvironmentRegister->index());
                 instructions().append(UINT_MAX);
                 instructions().append(virtualRegisterForArgument(1 + i).offset());
-                instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand());
+                instructions().append(GetPutInfo(ThrowIfNotFound, LocalClosureVar, NotInitialization).operand());
                 instructions().append(symbolTableConstantIndex);
                 instructions().append(offset.offset());
             }
@@ -365,7 +373,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             instructions().append(m_lexicalEnvironmentRegister->index());
             instructions().append(addConstant(ident));
             instructions().append(virtualRegisterForArgument(1 + i).offset());
-            instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand());
+            instructions().append(GetPutInfo(ThrowIfNotFound, LocalClosureVar, NotInitialization).operand());
             instructions().append(symbolTableConstantIndex);
             instructions().append(offset.offset());
         }
@@ -467,6 +475,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     // because a function's default parameter ExpressionNodes will use temporary registers.
     m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false));
     initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, functionNode, functionSymbolTable, symbolTableConstantIndex, captures);
+
+    pushLexicalScope(m_scopeNode, true);
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables)
@@ -504,6 +514,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
     codeBlock->adoptVariables(variables);
 
     m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false));
+
+    pushLexicalScope(m_scopeNode, true);
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables)
@@ -725,7 +737,7 @@ void BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeSta
         ASSERT(parameters.hasDefaultParameterValues());
         Variable var = variable(valuesToMoveIntoVars[i].first);
         RegisterID* scope = emitResolveScope(nullptr, var);
-        emitPutToScope(scope, var, valuesToMoveIntoVars[i].second.get(), DoNotThrowIfNotFound);
+        emitPutToScope(scope, var, valuesToMoveIntoVars[i].second.get(), DoNotThrowIfNotFound, NotInitialization);
     }
 
     if (!parameters.hasDefaultParameterValues()) {
@@ -1760,7 +1772,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(), true), transitionValue, DoNotThrowIfNotFound);
+            emitPutToScope(loopScope, variableForLocalEntry(identifier, entry, loopSymbolTable->index(), true), transitionValue, DoNotThrowIfNotFound, NotInitialization);
             transitionValue->deref();
         }
     }
@@ -1979,12 +1991,12 @@ RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* sco
     case VarKind::Invalid: {
         m_codeBlock->addPropertyAccessInstruction(instructions().size());
         
-        // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand
+        // get_from_scope dst, scope, id, GetPutInfo, Structure, Operand
         UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_scope);
         instructions().append(kill(dst));
         instructions().append(scope->index());
         instructions().append(addConstant(variable.ident()));
-        instructions().append(ResolveModeAndType(resolveMode, variable.offset().isScope() ? LocalClosureVar : resolveType()).operand());
+        instructions().append(GetPutInfo(resolveMode, variable.offset().isScope() ? LocalClosureVar : resolveType(), NotInitialization).operand());
         instructions().append(localScopeDepth());
         instructions().append(variable.offset().isScope() ? variable.offset().scopeOffset().offset() : 0);
         instructions().append(profile);
@@ -1994,7 +2006,7 @@ RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* sco
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Variable& variable, RegisterID* value, ResolveMode resolveMode)
+RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Variable& variable, RegisterID* value, ResolveMode resolveMode, InitializationMode initializationMode)
 {
     switch (variable.offset().kind()) {
     case VarKind::Stack:
@@ -2012,7 +2024,7 @@ RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Variable&
     case VarKind::Invalid: {
         m_codeBlock->addPropertyAccessInstruction(instructions().size());
         
-        // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
+        // put_to_scope scope, id, value, GetPutInfo, Structure, Operand
         emitOpcode(op_put_to_scope);
         instructions().append(scope->index());
         instructions().append(addConstant(variable.ident()));
@@ -2020,11 +2032,11 @@ RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Variable&
         ScopeOffset offset;
         if (variable.offset().isScope()) {
             offset = variable.offset().scopeOffset();
-            instructions().append(ResolveModeAndType(resolveMode, LocalClosureVar).operand());
+            instructions().append(GetPutInfo(resolveMode, LocalClosureVar, initializationMode).operand());
             instructions().append(variable.symbolTableConstantIndex());
         } else {
             ASSERT(resolveType() != LocalClosureVar);
-            instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
+            instructions().append(GetPutInfo(resolveMode, resolveType(), initializationMode).operand());
             instructions().append(localScopeDepth());
         }
         instructions().append(!!offset ? offset.offset() : 0);
@@ -2038,7 +2050,7 @@ RegisterID* BytecodeGenerator::initializeVariable(const Variable& variable, Regi
 {
     RELEASE_ASSERT(variable.offset().kind() != VarKind::Invalid);
     RegisterID* scope = emitResolveScope(nullptr, variable);
-    return emitPutToScope(scope, variable, value, ThrowIfNotFound);
+    return emitPutToScope(scope, variable, value, ThrowIfNotFound, NotInitialization);
 }
 
 RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype)
@@ -3277,7 +3289,7 @@ void BytecodeGenerator::emitPushFunctionNameScope(const Identifier& property, Re
     ASSERT_UNUSED(numVars, m_codeBlock->m_numVars == static_cast<int>(numVars + 1)); // Should have only created one new "var" for the function name scope.
     bool shouldTreatAsLexicalVariable = isStrictMode();
     Variable functionVar = variableForLocalEntry(property, m_symbolTableStack.last().m_symbolTable->get(property.impl()), m_symbolTableStack.last().m_symbolTableConstantIndex, shouldTreatAsLexicalVariable);
-    emitPutToScope(m_symbolTableStack.last().m_scope, functionVar, callee, ThrowIfNotFound);
+    emitPutToScope(m_symbolTableStack.last().m_scope, functionVar, callee, ThrowIfNotFound, NotInitialization);
 }
 
 void BytecodeGenerator::pushScopedControlFlowContext()
@@ -3303,7 +3315,7 @@ void BytecodeGenerator::emitPushCatchScope(const Identifier& property, RegisterI
     Variable exceptionVar = variable(property);
     RELEASE_ASSERT(exceptionVar.isResolved());
     RefPtr<RegisterID> scope = emitResolveScope(nullptr, exceptionVar);
-    emitPutToScope(scope.get(), exceptionVar, exceptionValue, ThrowIfNotFound);
+    emitPutToScope(scope.get(), exceptionVar, exceptionValue, ThrowIfNotFound, NotInitialization);
 }
 
 void BytecodeGenerator::emitPopCatchScope(VariableEnvironment& environment) 
index ebf7d17..9060a58 100644 (file)
@@ -546,7 +546,7 @@ namespace JSC {
         RegisterID* emitResolveConstantLocal(RegisterID* dst, const Variable&);
         RegisterID* emitResolveScope(RegisterID* dst, const Variable&);
         RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Variable&, ResolveMode);
-        RegisterID* emitPutToScope(RegisterID* scope, const Variable&, RegisterID* value, ResolveMode);
+        RegisterID* emitPutToScope(RegisterID* scope, const Variable&, RegisterID* value, ResolveMode, InitializationMode);
         RegisterID* initializeVariable(const Variable&, RegisterID* value);
 
         PassRefPtr<Label> emitLabel(Label*);
index d328778..6a25923 100644 (file)
@@ -1053,7 +1053,7 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
     }
     RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
     if (!var.isReadOnly()) {
-        generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
+        generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound, NotInitialization);
         generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
     }
 
@@ -1253,7 +1253,7 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
 
     emitIncOrDec(generator, value.get(), m_operator);
     if (!var.isReadOnly()) {
-        generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound);
+        generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound, NotInitialization);
         generator.emitProfileType(value.get(), var, divotStart(), divotEnd());
     }
     return generator.moveToDestinationIfNeeded(dst, value.get());
@@ -1777,7 +1777,7 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re
     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 = result.get();
     if (!var.isReadOnly()) {
-        returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound);
+        returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound, NotInitialization);
         generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
     }
     return returnResult;
@@ -1834,7 +1834,8 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* returnResult = result.get();
     if (!isReadOnly) {
-        returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+        returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, 
+            m_assignmentContext == AssignmentContext::ConstDeclarationStatement || m_assignmentContext == AssignmentContext::DeclarationStatement  ? Initialization : NotInitialization);
         generator.emitProfileType(result.get(), var, divotStart(), divotEnd());
     }
 
@@ -2029,7 +2030,7 @@ RegisterID* EmptyLetExpression::emitBytecode(BytecodeGenerator& generator, Regis
     } else {
         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
         RefPtr<RegisterID> value = generator.emitLoad(nullptr, jsUndefined());
-        generator.emitPutToScope(scope.get(), var, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+        generator.emitPutToScope(scope.get(), var, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, Initialization);
         generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); 
     }
 
@@ -2235,7 +2236,7 @@ void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propert
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
             RegisterID* scope = generator.emitResolveScope(nullptr, var);
             generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-            generator.emitPutToScope(scope, var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+            generator.emitPutToScope(scope, var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, NotInitialization);
         }
         generator.emitProfileType(propertyName, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
         return;
@@ -2456,7 +2457,7 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
                     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
                 RegisterID* scope = generator.emitResolveScope(nullptr, var);
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-                generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+                generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, NotInitialization);
             }
             generator.emitProfileType(value, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
         } else if (m_lexpr->isDotAccessorNode()) {
@@ -3330,7 +3331,8 @@ void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) con
         generator.emitReadOnlyExceptionIfNeeded(var);
         return;
     }
-    generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+    generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, 
+        m_bindingContext == AssignmentContext::ConstDeclarationStatement || m_bindingContext == AssignmentContext::DeclarationStatement ? Initialization : NotInitialization);
     generator.emitProfileType(value, var, divotStart(), divotEnd());
     if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
         generator.liftTDZCheckIfPossible(var);
index c6eba4e..3b6ee88 100644 (file)
@@ -184,12 +184,17 @@ bool DebuggerScope::isGlobalScope() const
     return m_scope->isGlobalObject();
 }
 
-bool DebuggerScope::isFunctionOrEvalScope() const
+bool DebuggerScope::isGlobalLexicalEnvironment() const
+{
+    return m_scope->isGlobalLexicalEnvironment();
+}
+
+bool DebuggerScope::isClosureScope() const
 {
     // In the current debugger implementation, every function or eval will create an
     // lexical environment object. Hence, a lexical environment object implies a
     // function or eval scope.
-    return m_scope->isActivationObject() && !isCatchScope();
+    return m_scope->isVarScope() || m_scope->isLexicalScope();
 }
 
 JSValue DebuggerScope::caughtValue(ExecState* exec) const
index e1edb92..8994fcf 100644 (file)
@@ -89,7 +89,8 @@ public:
     bool isFunctionNameScope() const;
     bool isWithScope() const;
     bool isGlobalScope() const;
-    bool isFunctionOrEvalScope() const;
+    bool isClosureScope() const;
+    bool isGlobalLexicalEnvironment() const;
 
     JSValue caughtValue(ExecState*) const;
 
index 076dc48..f6e43c0 100644 (file)
@@ -2365,9 +2365,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case GetGlobalVar:
         forNode(node).makeHeapTop();
         break;
+    case GetGlobalLexicalVariable:
+        forNode(node).makeBytecodeTop();
+        break;
         
     case VarInjectionWatchpoint:
-    case PutGlobalVar:
+    case PutGlobalVariable:
     case NotifyWrite:
         break;
             
index 7f65052..2b89e3a 100644 (file)
@@ -3819,6 +3819,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             int dst = currentInstruction[1].u.operand;
             ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
             unsigned depth = currentInstruction[5].u.operand;
+            int scope = currentInstruction[2].u.operand;
 
             // get_from_scope and put_to_scope depend on this watchpoint forcing OSR exit, so they don't add their own watchpoints.
             if (needsVarInjectionChecks(resolveType))
@@ -3829,14 +3830,19 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             case GlobalVar:
             case GlobalPropertyWithVarInjectionChecks:
             case GlobalVarWithVarInjectionChecks:
-                set(VirtualRegister(dst), weakJSConstant(m_inlineStackTop->m_codeBlock->globalObject()));
-                if (resolveType == GlobalPropertyWithVarInjectionChecks || resolveType == GlobalVarWithVarInjectionChecks)
-                    addToGraph(Phantom, getDirect(m_inlineStackTop->remapOperand(VirtualRegister(currentInstruction[2].u.operand))));
+            case GlobalLexicalVar:
+            case GlobalLexicalVarWithVarInjectionChecks: {
+                JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_inlineStackTop->m_codeBlock);
+                RELEASE_ASSERT(constantScope);
+                RELEASE_ASSERT(static_cast<JSScope*>(currentInstruction[6].u.pointer) == constantScope);
+                set(VirtualRegister(dst), weakJSConstant(constantScope));
+                addToGraph(Phantom, get(VirtualRegister(scope)));
                 break;
+            }
             case LocalClosureVar:
             case ClosureVar:
             case ClosureVarWithVarInjectionChecks: {
-                Node* localBase = get(VirtualRegister(currentInstruction[2].u.operand));
+                Node* localBase = get(VirtualRegister(scope));
                 addToGraph(Phantom, localBase); // OSR exit cannot handle resolve_scope on a DCE'd scope.
                 
                 // We have various forms of constant folding here. This is necessary to avoid
@@ -3860,6 +3866,13 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 set(VirtualRegister(dst), localBase);
                 break;
             }
+            case UnresolvedProperty:
+            case UnresolvedPropertyWithVarInjectionChecks: {
+                addToGraph(Phantom, get(VirtualRegister(scope)));
+                addToGraph(ForceOSRExit);
+                set(VirtualRegister(dst), addToGraph(JSConstant, OpInfo(m_constantNull)));
+                break;
+            }
             case Dynamic:
                 RELEASE_ASSERT_NOT_REACHED();
                 break;
@@ -3872,16 +3885,16 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             int scope = currentInstruction[2].u.operand;
             unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
             UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber];
-            ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+            ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
 
             Structure* structure = 0;
             WatchpointSet* watchpoints = 0;
             uintptr_t operand;
             {
                 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
-                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
+                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
                     watchpoints = currentInstruction[5].u.watchpointSet;
-                else
+                else if (resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
                     structure = currentInstruction[5].u.structure.get();
                 operand = reinterpret_cast<uintptr_t>(currentInstruction[6].u.pointer);
             }
@@ -3910,13 +3923,16 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 break;
             }
             case GlobalVar:
-            case GlobalVarWithVarInjectionChecks: {
+            case GlobalVarWithVarInjectionChecks:
+            case GlobalLexicalVar:
+            case GlobalLexicalVarWithVarInjectionChecks: {
                 addToGraph(Phantom, get(VirtualRegister(scope)));
                 WatchpointSet* watchpointSet;
                 ScopeOffset offset;
+                JSSegmentedVariableObject* scopeObject = jsCast<JSSegmentedVariableObject*>(JSScope::constantScopeForCodeBlock(resolveType, m_inlineStackTop->m_codeBlock));
                 {
-                    ConcurrentJITLocker locker(globalObject->symbolTable()->m_lock);
-                    SymbolTableEntry entry = globalObject->symbolTable()->get(locker, uid);
+                    ConcurrentJITLocker locker(scopeObject->symbolTable()->m_lock);
+                    SymbolTableEntry entry = scopeObject->symbolTable()->get(locker, uid);
                     watchpointSet = entry.watchpointSet();
                     offset = entry.scopeOffset();
                 }
@@ -3961,7 +3977,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     // reading are added, we might access freed memory if we do variableAt().
                     WriteBarrier<Unknown>* pointer = bitwise_cast<WriteBarrier<Unknown>*>(operand);
                     
-                    ASSERT(globalObject->findVariableIndex(pointer) == offset);
+                    ASSERT(scopeObject->findVariableIndex(pointer) == offset);
                     
                     JSValue value = pointer->get();
                     if (value) {
@@ -3972,7 +3988,15 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 }
                 
                 SpeculatedType prediction = getPrediction();
-                set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction)));
+                NodeType nodeType;
+                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks)
+                    nodeType = GetGlobalVar;
+                else
+                    nodeType = GetGlobalLexicalVariable;
+                Node* value = addToGraph(nodeType, OpInfo(operand), OpInfo(prediction));
+                if (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
+                    addToGraph(CheckNotEmpty, value);
+                set(VirtualRegister(dst), value);
                 break;
             }
             case LocalClosureVar:
@@ -4002,6 +4026,14 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     addToGraph(GetClosureVar, OpInfo(operand), OpInfo(prediction), scopeNode));
                 break;
             }
+            case UnresolvedProperty:
+            case UnresolvedPropertyWithVarInjectionChecks: {
+                addToGraph(ForceOSRExit);
+                Node* scopeNode = get(VirtualRegister(scope));
+                addToGraph(Phantom, scopeNode);
+                set(VirtualRegister(dst), addToGraph(JSConstant, OpInfo(m_constantUndefined)));
+                break;
+            }
             case Dynamic:
                 RELEASE_ASSERT_NOT_REACHED();
                 break;
@@ -4015,7 +4047,8 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             if (identifierNumber != UINT_MAX)
                 identifierNumber = m_inlineStackTop->m_identifierRemap[identifierNumber];
             unsigned value = currentInstruction[3].u.operand;
-            ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+            GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+            ResolveType resolveType = getPutInfo.resolveType();
             UniquedStringImpl* uid;
             if (identifierNumber != UINT_MAX)
                 uid = m_graph.identifiers()[identifierNumber];
@@ -4027,9 +4060,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             uintptr_t operand;
             {
                 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
-                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
+                if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
                     watchpoints = currentInstruction[5].u.watchpointSet;
-                else
+                else if (resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
                     structure = currentInstruction[5].u.structure.get();
                 operand = reinterpret_cast<uintptr_t>(currentInstruction[6].u.pointer);
             }
@@ -4056,14 +4089,23 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 addToGraph(Phantom, get(VirtualRegister(scope)));
                 break;
             }
+            case GlobalLexicalVar:
+            case GlobalLexicalVarWithVarInjectionChecks:
             case GlobalVar:
             case GlobalVarWithVarInjectionChecks: {
+                if (getPutInfo.initializationMode() != Initialization && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) {
+                    SpeculatedType prediction = SpecEmpty;
+                    Node* value = addToGraph(GetGlobalLexicalVariable, OpInfo(operand), OpInfo(prediction));
+                    addToGraph(CheckNotEmpty, value);
+                }
+
+                JSSegmentedVariableObject* scopeObject = jsCast<JSSegmentedVariableObject*>(JSScope::constantScopeForCodeBlock(resolveType, m_inlineStackTop->m_codeBlock));
                 if (watchpoints) {
-                    SymbolTableEntry entry = globalObject->symbolTable()->get(uid);
+                    SymbolTableEntry entry = scopeObject->symbolTable()->get(uid);
                     ASSERT_UNUSED(entry, watchpoints == entry.watchpointSet());
                 }
                 Node* valueNode = get(VirtualRegister(value));
-                addToGraph(PutGlobalVar, OpInfo(operand), weakJSConstant(globalObject), valueNode);
+                addToGraph(PutGlobalVariable, OpInfo(operand), weakJSConstant(scopeObject), valueNode);
                 if (watchpoints && watchpoints->state() != IsInvalidated) {
                     // Must happen after the store. See comment for GetGlobalVar.
                     addToGraph(NotifyWrite, OpInfo(watchpoints));
@@ -4086,6 +4128,13 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 }
                 break;
             }
+            case UnresolvedProperty:
+            case UnresolvedPropertyWithVarInjectionChecks: {
+                addToGraph(ForceOSRExit);
+                Node* scopeNode = get(VirtualRegister(scope));
+                addToGraph(Phantom, scopeNode);
+                break;
+            }
             case Dynamic:
                 RELEASE_ASSERT_NOT_REACHED();
                 break;
index be62b9f..eca20da 100644 (file)
@@ -220,7 +220,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
         return CanCompileAndInline;
 
     case op_put_to_scope: {
-        ResolveType resolveType = ResolveModeAndType(pc[4].u.operand).type();
+        ResolveType resolveType = GetPutInfo(pc[4].u.operand).resolveType();
         // If we're writing to a readonly property we emit a Dynamic put that
         // the DFG can't currently handle.
         if (resolveType == Dynamic)
@@ -230,7 +230,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
 
     case op_resolve_scope: {
         // We don't compile 'catch' or 'with', so there's no point in compiling variable resolution within them.
-        ResolveType resolveType = ResolveModeAndType(pc[4].u.operand).type();
+        ResolveType resolveType = static_cast<ResolveType>(pc[4].u.operand);
         if (resolveType == Dynamic)
             return CannotCompile;
         return CanCompileAndInline;
index 67891b8..d6127cf 100644 (file)
@@ -841,11 +841,12 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     }
         
     case GetGlobalVar:
+    case GetGlobalLexicalVariable:
         read(AbstractHeap(Absolute, node->variablePointer()));
         def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
         return;
         
-    case PutGlobalVar:
+    case PutGlobalVariable:
         write(AbstractHeap(Absolute, node->variablePointer()));
         def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
         return;
index e3daf25..bf8dfab 100644 (file)
@@ -105,7 +105,8 @@ bool doesGC(Graph& graph, Node* node)
     case GetClosureVar:
     case PutClosureVar:
     case GetGlobalVar:
-    case PutGlobalVar:
+    case GetGlobalLexicalVariable:
+    case PutGlobalVariable:
     case VarInjectionWatchpoint:
     case CheckCell:
     case CheckNotEmpty:
index bda4351..55c1b7a 100644 (file)
@@ -1191,7 +1191,7 @@ private:
             DFG_CRASH(m_graph, node, "Unexpected node during fixup");
             break;
         
-        case PutGlobalVar: {
+        case PutGlobalVariable: {
             fixEdge<CellUse>(node->child1());
             speculateForBarrier(node->child2());
             break;
@@ -1336,6 +1336,7 @@ private:
         case PhantomLocal:
         case GetLocalUnlinked:
         case GetGlobalVar:
+        case GetGlobalLexicalVariable:
         case NotifyWrite:
         case VarInjectionWatchpoint:
         case Call:
index e285533..d272d14 100644 (file)
@@ -186,7 +186,7 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
     //         @#   - a NodeIndex referencing a prior node in the graph.
     //         arg# - an argument number.
     //         id#  - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
-    //         var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
+    //         var# - the index of a var on the global object, used by GetGlobalVar/GetGlobalLexicalVariable/PutGlobalVariable operations.
     out.printf("% 4d:<%c%u:", (int)node->index(), mustGenerate ? '!' : ' ', refCount);
     if (node->hasResult() && node->hasVirtualRegister() && node->virtualRegister().isValid())
         out.print(node->virtualRegister());
@@ -222,7 +222,7 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext*
     if (node->hasDirectArgumentsOffset())
         out.print(comma, node->capturedArgumentsOffset());
     if (node->hasRegisterPointer())
-        out.print(comma, "global", globalObjectFor(node->origin.semantic)->findVariableIndex(node->variablePointer()), "(", RawPointer(node->variablePointer()), ")");
+        out.print(comma, "global", "(", RawPointer(node->variablePointer()), ")");
     if (node->hasIdentifier())
         out.print(comma, "id", node->identifierNumber(), "{", identifiers()[node->identifierNumber()], "}");
     if (node->hasPromotedLocationDescriptor())
index 80033b0..80ccaf5 100644 (file)
@@ -989,7 +989,7 @@ struct Node {
     
     bool hasRegisterPointer()
     {
-        return op() == GetGlobalVar || op() == PutGlobalVar;
+        return op() == GetGlobalVar || op() == GetGlobalLexicalVariable || op() == PutGlobalVariable;
     }
     
     WriteBarrier<Unknown>* variablePointer()
@@ -1262,6 +1262,7 @@ struct Node {
         case RegExpExec:
         case RegExpTest:
         case GetGlobalVar:
+        case GetGlobalLexicalVariable:
             return true;
         default:
             return false;
index 54ce748..a19b679 100644 (file)
@@ -207,7 +207,8 @@ namespace JSC { namespace DFG {
     macro(GetClosureVar, NodeResultJS) \
     macro(PutClosureVar, NodeMustGenerate) \
     macro(GetGlobalVar, NodeResultJS) \
-    macro(PutGlobalVar, NodeMustGenerate) \
+    macro(GetGlobalLexicalVariable, NodeResultJS) \
+    macro(PutGlobalVariable, NodeMustGenerate) \
     macro(NotifyWrite, NodeMustGenerate) \
     macro(VarInjectionWatchpoint, NodeMustGenerate) \
     macro(CheckCell, NodeMustGenerate) \
index 90e08a2..96f00e1 100644 (file)
@@ -200,6 +200,7 @@ private:
         case CallForwardVarargs:
         case ConstructForwardVarargs:
         case GetGlobalVar:
+        case GetGlobalLexicalVariable:
         case GetClosureVar:
         case GetFromArguments: {
             changed |= setPrediction(node->getHeapPrediction());
@@ -660,7 +661,7 @@ private:
         case VarInjectionWatchpoint:
         case Phantom:
         case Check:
-        case PutGlobalVar:
+        case PutGlobalVariable:
         case CheckWatchdogTimer:
         case Unreachable:
         case LoopHint:
index 7f36616..9e781f5 100644 (file)
@@ -196,7 +196,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case GetClosureVar:
     case PutClosureVar:
     case GetGlobalVar:
-    case PutGlobalVar:
+    case GetGlobalLexicalVariable:
+    case PutGlobalVariable:
     case VarInjectionWatchpoint:
     case CheckCell:
     case CheckBadCell:
index 515c063..a73315d 100644 (file)
@@ -4110,6 +4110,7 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case GetGlobalLexicalVariable:
     case GetGlobalVar: {
         GPRTemporary resultPayload(this);
         GPRTemporary resultTag(this);
@@ -4122,7 +4123,7 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
-    case PutGlobalVar: {
+    case PutGlobalVariable: {
         JSValueOperand value(this, node->child2());
 
         // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have
index 379d9c3..f76a0b1 100644 (file)
@@ -4105,6 +4105,7 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case GetGlobalLexicalVariable:
     case GetGlobalVar: {
         GPRTemporary result(this);
 
@@ -4114,7 +4115,7 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
-    case PutGlobalVar: {
+    case PutGlobalVariable: {
         JSValueOperand value(this, node->child2());
 
         m_jit.store64(value.gpr(), node->variablePointer());
index 0a8631d..a0d8dda 100644 (file)
@@ -273,7 +273,7 @@ private:
                 break;
             }
                 
-            case PutGlobalVar: {
+            case PutGlobalVariable: {
                 considerBarrier(m_node->child1(), m_node->child2());
                 break;
             }
index 80304a3..d35c51b 100644 (file)
@@ -77,7 +77,8 @@ inline CapabilityLevel canCompile(Node* node)
     case GetSetter:
     case PutByOffset:
     case GetGlobalVar:
-    case PutGlobalVar:
+    case GetGlobalLexicalVariable:
+    case PutGlobalVariable:
     case ValueAdd:
     case StrCat:
     case ArithAdd:
index 55a368d..2f67f83 100644 (file)
@@ -665,10 +665,11 @@ private:
             compileMultiPutByOffset();
             break;
         case GetGlobalVar:
-            compileGetGlobalVar();
+        case GetGlobalLexicalVariable:
+            compileGetGlobalVariable();
             break;
-        case PutGlobalVar:
-            compilePutGlobalVar();
+        case PutGlobalVariable:
+            compilePutGlobalVariable();
             break;
         case NotifyWrite:
             compileNotifyWrite();
@@ -4056,12 +4057,12 @@ private:
         m_out.appendTo(continuation, lastNext);
     }
     
-    void compileGetGlobalVar()
+    void compileGetGlobalVariable()
     {
         setJSValue(m_out.load64(m_out.absolute(m_node->variablePointer())));
     }
     
-    void compilePutGlobalVar()
+    void compilePutGlobalVariable()
     {
         m_out.store64(
             lowJSValue(m_node->child2()), m_out.absolute(m_node->variablePointer()));
index cb1f9d1..b69f4cf 100644 (file)
@@ -99,8 +99,8 @@ JSValue JSJavaScriptCallFrame::scopeType(ExecState* exec)
     for (DebuggerScope::iterator iter = scopeChain->begin(); iter != end; ++iter) {
         DebuggerScope* scope = iter.get();
 
-        if (!foundLocalScope && scope->isFunctionOrEvalScope()) {
-            // First function scope is the local scope, each successive one is a closure.
+        if (!foundLocalScope && scope->isClosureScope()) {
+            // First closure scope is the local scope, each successive one is a true closure.
             if (!index)
                 return jsNumber(JSJavaScriptCallFrame::LOCAL_SCOPE);
             foundLocalScope = true;
@@ -113,11 +113,16 @@ JSValue JSJavaScriptCallFrame::scopeType(ExecState* exec)
                 return jsNumber(JSJavaScriptCallFrame::FUNCTION_NAME_SCOPE);
             if (scope->isWithScope())
                 return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE);
+            if (scope->isGlobalLexicalEnvironment()) {
+                // FIXME: We need a way to better describe this scope.
+                // It's currently best described as a "closure" scope.
+                return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
+            }
             if (scope->isGlobalScope()) {
                 ASSERT(++iter == end);
                 return jsNumber(JSJavaScriptCallFrame::GLOBAL_SCOPE);
             }
-            ASSERT(scope->isFunctionOrEvalScope());
+            ASSERT(scope->isClosureScope());
             return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE);
         }
 
index fa62ea6..1f99e2c 100644 (file)
@@ -757,7 +757,7 @@ JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, J
 {
     SamplingScope samplingScope(this);
 
-    JSScope* scope = thisObj->globalObject();
+    JSScope* scope = thisObj->globalObject()->globalScope();
     VM& vm = *scope->vm();
 
     ASSERT(!vm.exception());
@@ -1142,7 +1142,6 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
                 }
             }
         }
-        ASSERT(!variableObject->isNameScopeObject());
     }
 
     JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall);
@@ -1150,6 +1149,28 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
         return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
     EvalCodeBlock* codeBlock = eval->codeBlock();
 
+    // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval.
+    if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numFunctions)) {
+        JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment();
+        for (unsigned i = 0; i < numVariables; ++i) {
+            const Identifier& ident = codeBlock->variable(i);
+            PropertySlot slot(globalLexicalEnvironment);
+            if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, ident, slot)) {
+                return checkedReturn(callFrame->vm().throwException(callFrame,
+                    createTypeError(callFrame, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'"))));
+            }
+        }
+
+        for (int i = 0; i < numFunctions; ++i) {
+            FunctionExecutable* function = codeBlock->functionDecl(i);
+            PropertySlot slot(globalLexicalEnvironment);
+            if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, function->name(), slot)) {
+                return checkedReturn(callFrame->vm().throwException(callFrame,
+                    createTypeError(callFrame, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'"))));
+            }
+        }
+    }
+
     if (numVariables || numFunctions) {
         BatchedTransitionOptimizer optimizer(vm, variableObject);
         if (variableObject->next())
index 59e7538..24c1240 100644 (file)
@@ -670,11 +670,15 @@ namespace JSC {
         void emitResolveClosure(int dst, int scope, bool needsVarInjectionChecks, unsigned depth);
         void emitLoadWithStructureCheck(int scope, Structure** structureSlot);
         void emitGetGlobalProperty(uintptr_t* operandSlot);
-        void emitGetGlobalVar(uintptr_t operand);
+#if USE(JSVALUE64)
+        void emitGetVarFromPointer(uintptr_t operand, GPRReg);
+#else
+        void emitGetVarFromPointer(uintptr_t operand, GPRReg tag, GPRReg payload);
+#endif
         void emitGetClosureVar(int scope, uintptr_t operand);
         void emitPutGlobalProperty(uintptr_t* operandSlot, int value);
         void emitNotifyWrite(WatchpointSet*);
-        void emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet*);
+        void emitPutGlobalVariable(uintptr_t operand, int value, WatchpointSet*);
         void emitPutClosureVar(int scope, uintptr_t operand, int value, WatchpointSet*);
 
         void emitInitRegister(int dst);
index cb7bbf6..6d501e6 100644 (file)
@@ -1928,15 +1928,6 @@ char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(ExecState* exec, Enc
     return reinterpret_cast<char*>(result);
 }
 
-EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t scopeReg, int32_t identifierIndex)
-{
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-    const Identifier& ident = exec->codeBlock()->identifier(identifierIndex);
-    JSScope* scope = exec->uncheckedR(scopeReg).Register::scope();
-    return JSValue::encode(JSScope::resolve(exec, scope, ident));
-}
-
 EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction* bytecodePC)
 {
     VM& vm = exec->vm();
@@ -1946,29 +1937,30 @@ EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction*
 
     const Identifier& ident = codeBlock->identifier(pc[3].u.operand);
     JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[2].u.operand).jsValue());
-    ResolveModeAndType modeAndType(pc[4].u.operand);
+    GetPutInfo getPutInfo(pc[4].u.operand);
 
     PropertySlot slot(scope);
     if (!scope->getPropertySlot(exec, ident, slot)) {
-        if (modeAndType.mode() == ThrowIfNotFound)
+        if (getPutInfo.resolveMode() == ThrowIfNotFound)
             vm.throwException(exec, createUndefinedVariableError(exec, ident));
         return JSValue::encode(jsUndefined());
     }
 
-    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
-    if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure(vm)->propertyAccessesAreCacheable()) {
-        if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
-            Structure* structure = scope->structure(vm);
-            {
-                ConcurrentJITLocker locker(codeBlock->m_lock);
-                pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), structure);
-                pc[6].u.operand = slot.cachedOffset();
-            }
-            structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
+    JSValue result = JSValue();
+    if (jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+        // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
+        result = slot.getValue(exec, ident);
+        if (result == jsTDZValue()) {
+            exec->vm().throwException(exec, createTDZError(exec));
+            return JSValue::encode(jsUndefined());
         }
     }
 
-    return JSValue::encode(slot.getValue(exec, ident));
+    CommonSlowPaths::tryCacheGetFromScopeGlobal(exec, vm, pc, scope, slot, ident);
+
+    if (!result)
+        result = slot.getValue(exec, ident);
+    return JSValue::encode(result);
 }
 
 void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC)
@@ -1981,26 +1973,40 @@ void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC)
     const Identifier& ident = codeBlock->identifier(pc[2].u.operand);
     JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[1].u.operand).jsValue());
     JSValue value = exec->r(pc[3].u.operand).jsValue();
-    ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
-    if (modeAndType.type() == LocalClosureVar) {
+    GetPutInfo getPutInfo = GetPutInfo(pc[4].u.operand);
+    if (getPutInfo.resolveType() == LocalClosureVar) {
         JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope);
         environment->variableAt(ScopeOffset(pc[6].u.operand)).set(vm, environment, value);
         if (WatchpointSet* set = pc[5].u.watchpointSet)
             set->touch("Executed op_put_scope<LocalClosureVar>");
         return;
     }
-    if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) {
+
+    bool hasProperty = scope->hasProperty(exec, ident);
+    if (hasProperty
+        && jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)
+        && getPutInfo.initializationMode() != Initialization) {
+        // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
+        PropertySlot slot(scope);
+        JSGlobalLexicalEnvironment::getOwnPropertySlot(scope, exec, ident, slot);
+        if (slot.getValue(exec, ident) == jsTDZValue()) {
+            exec->vm().throwException(exec, createTDZError(exec));
+            return;
+        }
+    }
+
+    if (getPutInfo.resolveMode() == ThrowIfNotFound && !hasProperty) {
         exec->vm().throwException(exec, createUndefinedVariableError(exec, ident));
         return;
     }
 
-    PutPropertySlot slot(scope, codeBlock->isStrictMode());
+    PutPropertySlot slot(scope, codeBlock->isStrictMode(), PutPropertySlot::UnknownContext, getPutInfo.initializationMode() == Initialization);
     scope->methodTable()->put(scope, exec, ident, value, slot);
     
     if (exec->vm().exception())
         return;
 
-    CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot);
+    CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, getPutInfo, slot, ident);
 }
 
 void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExceptionValue)
index 0320592..ccc5126 100644 (file)
@@ -334,7 +334,6 @@ EncodedJSValue JIT_OPERATION operationToObject(ExecState*, EncodedJSValue) WTF_I
 char* JIT_OPERATION operationSwitchCharWithUnknownKeyType(ExecState*, EncodedJSValue key, size_t tableIndex) WTF_INTERNAL;
 char* JIT_OPERATION operationSwitchImmWithUnknownKeyType(ExecState*, EncodedJSValue key, size_t tableIndex) WTF_INTERNAL;
 char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(ExecState*, EncodedJSValue key, size_t tableIndex) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationResolveScope(ExecState*, int32_t scope, int32_t identifierIndex) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState*, Instruction* bytecodePC) WTF_INTERNAL;
 void JIT_OPERATION operationPutToScope(ExecState*, Instruction* bytecodePC) WTF_INTERNAL;
 
index c8cf06d..429a0aa 100644 (file)
@@ -43,6 +43,7 @@
 #include "SamplingTool.h"
 #include "ScopedArguments.h"
 #include "ScopedArgumentsTable.h"
+#include "SlowPathCall.h"
 #include <wtf/StringPrintStream.h>
 
 
@@ -695,14 +696,22 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
     case GlobalVar:
     case GlobalPropertyWithVarInjectionChecks:
     case GlobalVarWithVarInjectionChecks:
+    case GlobalLexicalVar:
+    case GlobalLexicalVarWithVarInjectionChecks: {
+        JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_codeBlock);
+        RELEASE_ASSERT(constantScope);
+        RELEASE_ASSERT(static_cast<JSScope*>(currentInstruction[6].u.pointer) == constantScope);
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
+        move(TrustedImmPtr(constantScope), regT0);
         emitPutVirtualRegister(dst);
         break;
+    }
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
         emitResolveClosure(dst, scope, needsVarInjectionChecks(resolveType), depth);
         break;
+    case UnresolvedProperty:
+    case UnresolvedPropertyWithVarInjectionChecks:
     case Dynamic:
         addSlowCase(jump());
         break;
@@ -713,16 +722,13 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_resolve_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    int dst = currentInstruction[1].u.operand;
     ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
-
-    if (resolveType == GlobalProperty || resolveType == GlobalVar || resolveType == ClosureVar)
+    if (resolveType == GlobalProperty || resolveType == GlobalVar || resolveType == ClosureVar || resolveType == GlobalLexicalVar)
         return;
 
     linkSlowCase(iter);
-    int32_t scope = currentInstruction[2].u.operand;
-    int32_t identifierIndex = currentInstruction[3].u.operand;
-    callOperation(operationResolveScope, dst, scope, identifierIndex);
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_resolve_scope);
+    slowPathCall.call();
 }
 
 void JIT::emitLoadWithStructureCheck(int scope, Structure** structureSlot)
@@ -740,9 +746,9 @@ void JIT::emitGetGlobalProperty(uintptr_t* operandSlot)
     compileGetDirectOffset(regT0, regT0, regT1, regT2, KnownNotFinal);
 }
 
-void JIT::emitGetGlobalVar(uintptr_t operand)
+void JIT::emitGetVarFromPointer(uintptr_t operand, GPRReg reg)
 {
-    loadPtr(reinterpret_cast<void*>(operand), regT0);
+    loadPtr(reinterpret_cast<void*>(operand), reg);
 }
 
 void JIT::emitGetClosureVar(int scope, uintptr_t operand)
@@ -755,7 +761,7 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
     int scope = currentInstruction[2].u.operand;
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
     Structure** structureSlot = currentInstruction[5].u.structure.slot();
     uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
 
@@ -767,14 +773,20 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
         break;
     case GlobalVar:
     case GlobalVarWithVarInjectionChecks:
+    case GlobalLexicalVar:
+    case GlobalLexicalVarWithVarInjectionChecks:
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        emitGetGlobalVar(*operandSlot);
+        emitGetVarFromPointer(*operandSlot, regT0);
+        if (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks) // TDZ check.
+            addSlowCase(branchTest64(Zero, regT0));
         break;
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         emitGetClosureVar(scope, *operandSlot);
         break;
+    case UnresolvedProperty:
+    case UnresolvedPropertyWithVarInjectionChecks:
     case Dynamic:
         addSlowCase(jump());
         break;
@@ -788,14 +800,19 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
 void JIT::emitSlow_op_get_from_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int dst = currentInstruction[1].u.operand;
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
 
     if (resolveType == GlobalVar || resolveType == ClosureVar)
         return;
 
     if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks)
         linkSlowCase(iter);
+
+    if (resolveType == GlobalLexicalVarWithVarInjectionChecks) // Var injections check.
+        linkSlowCase(iter);
+
     linkSlowCase(iter);
+
     callOperation(WithProfile, operationGetFromScope, dst, currentInstruction);
 }
 
@@ -809,7 +826,7 @@ void JIT::emitPutGlobalProperty(uintptr_t* operandSlot, int value)
     storePtr(regT2, BaseIndex(regT0, regT1, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)));
 }
 
-void JIT::emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet* set)
+void JIT::emitPutGlobalVariable(uintptr_t operand, int value, WatchpointSet* set)
 {
     emitGetVirtualRegister(value, regT0);
     emitNotifyWrite(set);
@@ -828,7 +845,8 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
 {
     int scope = currentInstruction[1].u.operand;
     int value = currentInstruction[3].u.operand;
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+    ResolveType resolveType = getPutInfo.resolveType();
     Structure** structureSlot = currentInstruction[5].u.structure.slot();
     uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
 
@@ -841,10 +859,21 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
         break;
     case GlobalVar:
     case GlobalVarWithVarInjectionChecks:
-        emitWriteBarrier(m_codeBlock->globalObject(), value, ShouldFilterValue);
+    case GlobalLexicalVar:
+    case GlobalLexicalVarWithVarInjectionChecks: {
+        JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_codeBlock);
+        RELEASE_ASSERT(constantScope);
+        emitWriteBarrier(constantScope, value, ShouldFilterValue);
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        emitPutGlobalVar(*operandSlot, value, currentInstruction[5].u.watchpointSet);
+        if (getPutInfo.initializationMode() != Initialization && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) {
+            // We need to do a TDZ check here because we can't always prove we need to emit TDZ checks statically.
+            emitGetVarFromPointer(*operandSlot, regT0);
+            addSlowCase(branchTest64(Zero, regT0));
+        }
+
+        emitPutGlobalVariable(*operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
+    }
     case LocalClosureVar:
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
@@ -852,6 +881,8 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         emitPutClosureVar(scope, *operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
+    case UnresolvedProperty:
+    case UnresolvedPropertyWithVarInjectionChecks:
     case Dynamic:
         addSlowCase(jump());
         break;
@@ -860,15 +891,20 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+    ResolveType resolveType = getPutInfo.resolveType();
     unsigned linkCount = 0;
-    if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar)
+    if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar && resolveType != GlobalLexicalVar)
         linkCount++;
-    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
+    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks 
+         || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks 
+         || resolveType == LocalClosureVar)
         && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
         linkCount++;
     if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks)
         linkCount++;
+    if (getPutInfo.initializationMode() != Initialization && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) // TDZ check.
+        linkCount++;
     if (!linkCount)
         return;
     while (linkCount--)
index 7bfd75f..0dd0853 100644 (file)
@@ -41,6 +41,7 @@
 #include "RepatchBuffer.h"
 #include "ResultType.h"
 #include "SamplingTool.h"
+#include "SlowPathCall.h"
 #include <wtf/StringPrintStream.h>
 
 
@@ -724,17 +725,25 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
     switch (resolveType) {
     case GlobalProperty:
     case GlobalVar:
+    case GlobalLexicalVar:
     case GlobalPropertyWithVarInjectionChecks:
-    case GlobalVarWithVarInjectionChecks:
+    case GlobalVarWithVarInjectionChecks: 
+    case GlobalLexicalVarWithVarInjectionChecks: {
+        JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_codeBlock);
+        RELEASE_ASSERT(constantScope);
+        RELEASE_ASSERT(static_cast<JSScope*>(currentInstruction[6].u.pointer) == constantScope);
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         move(TrustedImm32(JSValue::CellTag), regT1);
-        move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
+        move(TrustedImmPtr(constantScope), regT0);
         emitStore(dst, regT1, regT0);
         break;
+    }
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
         emitResolveClosure(dst, scope, needsVarInjectionChecks(resolveType), depth);
         break;
+    case UnresolvedProperty:
+    case UnresolvedPropertyWithVarInjectionChecks:
     case Dynamic:
         addSlowCase(jump());
         break;
@@ -745,16 +754,14 @@ void JIT::emit_op_resolve_scope(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_resolve_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    int dst = currentInstruction[1].u.operand;
     ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand);
 
-    if (resolveType == GlobalProperty || resolveType == GlobalVar || resolveType == ClosureVar)
+    if (resolveType == GlobalProperty || resolveType == GlobalVar || resolveType == ClosureVar || resolveType == GlobalLexicalVar)
         return;
 
     linkSlowCase(iter);
-    int32_t scope = currentInstruction[2].u.operand;
-    int32_t identifierIndex = currentInstruction[3].u.operand;
-    callOperation(operationResolveScope, dst, scope, identifierIndex);
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_resolve_scope);
+    slowPathCall.call();
 }
 
 void JIT::emitLoadWithStructureCheck(int scope, Structure** structureSlot)
@@ -771,10 +778,10 @@ void JIT::emitGetGlobalProperty(uintptr_t* operandSlot)
     compileGetDirectOffset(regT2, regT1, regT0, regT3, KnownNotFinal);
 }
 
-void JIT::emitGetGlobalVar(uintptr_t operand)
+void JIT::emitGetVarFromPointer(uintptr_t operand, GPRReg tag, GPRReg payload)
 {
-    load32(reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag), regT1);
-    load32(reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), regT0);
+    load32(reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag), tag);
+    load32(reinterpret_cast<char*>(operand) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload), payload);
 }
 
 void JIT::emitGetClosureVar(int scope, uintptr_t operand)
@@ -788,7 +795,7 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
     int scope = currentInstruction[2].u.operand;
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
     Structure** structureSlot = currentInstruction[5].u.structure.slot();
     uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
 
@@ -800,14 +807,20 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
         break;
     case GlobalVar:
     case GlobalVarWithVarInjectionChecks:
+    case GlobalLexicalVar:
+    case GlobalLexicalVarWithVarInjectionChecks:
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        emitGetGlobalVar(*operandSlot);
+        emitGetVarFromPointer(*operandSlot, regT1, regT0);
+        if (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks) // TDZ check.
+            addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
         break;
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         emitGetClosureVar(scope, *operandSlot);
         break;
+    case UnresolvedProperty:
+    case UnresolvedPropertyWithVarInjectionChecks:
     case Dynamic:
         addSlowCase(jump());
         break;
@@ -821,11 +834,14 @@ void JIT::emit_op_get_from_scope(Instruction* currentInstruction)
 void JIT::emitSlow_op_get_from_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int dst = currentInstruction[1].u.operand;
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    ResolveType resolveType = GetPutInfo(currentInstruction[4].u.operand).resolveType();
 
     if (resolveType == GlobalVar || resolveType == ClosureVar)
         return;
 
+    if (resolveType == GlobalLexicalVarWithVarInjectionChecks) // Var Injections check.
+        linkSlowCase(iter);
+
     linkSlowCase(iter);
     callOperation(WithProfile, operationGetFromScope, dst, currentInstruction);
 }
@@ -841,7 +857,7 @@ void JIT::emitPutGlobalProperty(uintptr_t* operandSlot, int value)
     store32(regT2, BaseIndex(regT0, regT1, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
 }
 
-void JIT::emitPutGlobalVar(uintptr_t operand, int value, WatchpointSet* set)
+void JIT::emitPutGlobalVariable(uintptr_t operand, int value, WatchpointSet* set)
 {
     emitLoad(value, regT1, regT0);
     emitNotifyWrite(set);
@@ -862,7 +878,8 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
 {
     int scope = currentInstruction[1].u.operand;
     int value = currentInstruction[3].u.operand;
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+    ResolveType resolveType = getPutInfo.resolveType();
     Structure** structureSlot = currentInstruction[5].u.structure.slot();
     uintptr_t* operandSlot = reinterpret_cast<uintptr_t*>(&currentInstruction[6].u.pointer);
 
@@ -875,10 +892,20 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
         break;
     case GlobalVar:
     case GlobalVarWithVarInjectionChecks:
-        emitWriteBarrier(m_codeBlock->globalObject(), value, ShouldFilterValue);
+    case GlobalLexicalVar:
+    case GlobalLexicalVarWithVarInjectionChecks: {
+        JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_codeBlock);
+        RELEASE_ASSERT(constantScope);
+        emitWriteBarrier(constantScope, value, ShouldFilterValue);
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
-        emitPutGlobalVar(*operandSlot, value, currentInstruction[5].u.watchpointSet);
+        if (getPutInfo.initializationMode() != Initialization && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) {
+            // We need to do a TDZ check here because we can't always prove we need to emit TDZ checks statically.
+            emitGetVarFromPointer(*operandSlot, regT1, regT0);
+            addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
+        }
+        emitPutGlobalVariable(*operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
+    }
     case LocalClosureVar:
     case ClosureVar:
     case ClosureVarWithVarInjectionChecks:
@@ -886,6 +913,8 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
         emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
         emitPutClosureVar(scope, *operandSlot, value, currentInstruction[5].u.watchpointSet);
         break;
+    case UnresolvedProperty:
+    case UnresolvedPropertyWithVarInjectionChecks:
     case Dynamic:
         addSlowCase(jump());
         break;
@@ -894,13 +923,17 @@ void JIT::emit_op_put_to_scope(Instruction* currentInstruction)
 
 void JIT::emitSlow_op_put_to_scope(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type();
+    GetPutInfo getPutInfo = GetPutInfo(currentInstruction[4].u.operand);
+    ResolveType resolveType = getPutInfo.resolveType();
     unsigned linkCount = 0;
-    if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar)
+    if (resolveType != GlobalVar && resolveType != ClosureVar && resolveType != LocalClosureVar && resolveType != GlobalLexicalVar)
         linkCount++;
-    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar)
+    if ((resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar
+        || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
         && currentInstruction[5].u.watchpointSet->state() != IsInvalidated)
         linkCount++;
+    if (getPutInfo.initializationMode() != Initialization && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) // TDZ check.
+        linkCount++;
     if (!linkCount)
         return;
     while (linkCount--)
index 777cfde..f1f3ea2 100644 (file)
@@ -145,14 +145,19 @@ void Data::performAssertions(VM& vm)
 
     static_assert(GlobalProperty == 0, "LLInt assumes GlobalProperty ResultType is == 0");
     static_assert(GlobalVar == 1, "LLInt assumes GlobalVar ResultType is == 1");
-    static_assert(ClosureVar == 2, "LLInt assumes ClosureVar ResultType is == 2");
-    static_assert(LocalClosureVar == 3, "LLInt assumes LocalClosureVar ResultType is == 3");
-    static_assert(GlobalPropertyWithVarInjectionChecks == 4, "LLInt assumes GlobalPropertyWithVarInjectionChecks ResultType is == 4");
-    static_assert(GlobalVarWithVarInjectionChecks == 5, "LLInt assumes GlobalVarWithVarInjectionChecks ResultType is == 5");
-    static_assert(ClosureVarWithVarInjectionChecks == 6, "LLInt assumes ClosureVarWithVarInjectionChecks ResultType is == 6");
-    static_assert(Dynamic == 7, "LLInt assumes Dynamic ResultType is == 7");
+    static_assert(GlobalLexicalVar == 2, "LLInt assumes GlobalLexicalVar ResultType is == 2");
+    static_assert(ClosureVar == 3, "LLInt assumes ClosureVar ResultType is == 3");
+    static_assert(LocalClosureVar == 4, "LLInt assumes LocalClosureVar ResultType is == 4");
+    static_assert(GlobalPropertyWithVarInjectionChecks == 5, "LLInt assumes GlobalPropertyWithVarInjectionChecks ResultType is == 5");
+    static_assert(GlobalVarWithVarInjectionChecks == 6, "LLInt assumes GlobalVarWithVarInjectionChecks ResultType is == 6");
+    static_assert(GlobalLexicalVarWithVarInjectionChecks == 7, "LLInt assumes GlobalLexicalVarWithVarInjectionChecks ResultType is == 7");
+    static_assert(ClosureVarWithVarInjectionChecks == 8, "LLInt assumes ClosureVarWithVarInjectionChecks ResultType is == 8");
+
+    static_assert(InitializationMode::Initialization == 0, "LLInt assumes that InitializationMode::Initialization is 0");
     
-    ASSERT(ResolveModeAndType::mask == 0xffff);
+    ASSERT(GetPutInfo::typeBits == 0x3ff);
+    ASSERT(GetPutInfo::initializationShift == 10);
+    ASSERT(GetPutInfo::initializationBits == 0xffc00);
 
     ASSERT(MarkedBlock::blockMask == ~static_cast<decltype(MarkedBlock::blockMask)>(0x3fff));
 
index 27cbcc5..7eda2ba 100644 (file)
@@ -1358,44 +1358,34 @@ LLINT_SLOW_PATH_DECL(slow_path_handle_exception)
     LLINT_END_IMPL();
 }
 
-LLINT_SLOW_PATH_DECL(slow_path_resolve_scope)
-{
-    LLINT_BEGIN();
-    const Identifier& ident = exec->codeBlock()->identifier(pc[3].u.operand);
-    JSScope* scope = LLINT_OP(2).Register::scope();
-    LLINT_RETURN(JSScope::resolve(exec, scope, ident));
-}
-
 LLINT_SLOW_PATH_DECL(slow_path_get_from_scope)
 {
     LLINT_BEGIN();
 
     const Identifier& ident = exec->codeBlock()->identifier(pc[3].u.operand);
     JSObject* scope = jsCast<JSObject*>(LLINT_OP(2).jsValue());
-    ResolveModeAndType modeAndType(pc[4].u.operand);
+    GetPutInfo getPutInfo(pc[4].u.operand);
 
     PropertySlot slot(scope);
     if (!scope->getPropertySlot(exec, ident, slot)) {
-        if (modeAndType.mode() == ThrowIfNotFound)
+        if (getPutInfo.resolveMode() == ThrowIfNotFound)
             LLINT_RETURN(exec->vm().throwException(exec, createUndefinedVariableError(exec, ident)));
         LLINT_RETURN(jsUndefined());
     }
 
-    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
-    if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure()->propertyAccessesAreCacheable()) {
-        if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
-            CodeBlock* codeBlock = exec->codeBlock();
-            Structure* structure = scope->structure(vm);
-            {
-                ConcurrentJITLocker locker(codeBlock->m_lock);
-                pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), structure);
-                pc[6].u.operand = slot.cachedOffset();
-            }
-            structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
-        }
+    JSValue result = JSValue();
+    if (jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+        // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
+        result = slot.getValue(exec, ident);
+        if (result == jsTDZValue())
+            LLINT_THROW(createTDZError(exec));
     }
 
-    LLINT_RETURN(slot.getValue(exec, ident));
+    CommonSlowPaths::tryCacheGetFromScopeGlobal(exec, vm, pc, scope, slot, ident);
+
+    if (!result)
+        result = slot.getValue(exec, ident);
+    LLINT_RETURN(result);
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_put_to_scope)
@@ -1406,8 +1396,8 @@ LLINT_SLOW_PATH_DECL(slow_path_put_to_scope)
     const Identifier& ident = codeBlock->identifier(pc[2].u.operand);
     JSObject* scope = jsCast<JSObject*>(LLINT_OP(1).jsValue());
     JSValue value = LLINT_OP_C(3).jsValue();
-    ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
-    if (modeAndType.type() == LocalClosureVar) {
+    GetPutInfo getPutInfo = GetPutInfo(pc[4].u.operand);
+    if (getPutInfo.resolveType() == LocalClosureVar) {
         JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope);
         environment->variableAt(ScopeOffset(pc[6].u.operand)).set(vm, environment, value);
         
@@ -1419,13 +1409,24 @@ LLINT_SLOW_PATH_DECL(slow_path_put_to_scope)
         LLINT_END();
     }
 
-    if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident))
+    bool hasProperty = scope->hasProperty(exec, ident);
+    if (hasProperty
+        && jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)
+        && getPutInfo.initializationMode() != Initialization) {
+        // When we can't statically prove we need a TDZ check, we must perform the check on the slow path.
+        PropertySlot slot(scope);
+        JSGlobalLexicalEnvironment::getOwnPropertySlot(scope, exec, ident, slot);
+        if (slot.getValue(exec, ident) == jsTDZValue())
+            LLINT_THROW(createTDZError(exec));
+    }
+
+    if (getPutInfo.resolveMode() == ThrowIfNotFound && !hasProperty)
         LLINT_THROW(createUndefinedVariableError(exec, ident));
 
-    PutPropertySlot slot(scope, codeBlock->isStrictMode());
+    PutPropertySlot slot(scope, codeBlock->isStrictMode(), PutPropertySlot::UnknownContext, getPutInfo.initializationMode() == Initialization);
     scope->methodTable()->put(scope, exec, ident, value, slot);
     
-    CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot);
+    CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, getPutInfo, slot, ident);
 
     LLINT_END();
 }
index 3f1daa8..eae042c 100644 (file)
@@ -114,7 +114,6 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_debug);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_will_call);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_did_call);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_handle_exception);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_from_scope);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_to_scope);
 extern "C" SlowPathReturnType llint_throw_stack_overflow_error(VM*, ProtoCallFrame*) WTF_INTERNAL;
index 75c91f8..455b607 100644 (file)
@@ -190,14 +190,18 @@ const firstOutOfLineOffset = 100
 # ResolveType
 const GlobalProperty = 0
 const GlobalVar = 1
-const ClosureVar = 2
-const LocalClosureVar = 3
-const GlobalPropertyWithVarInjectionChecks = 4
-const GlobalVarWithVarInjectionChecks = 5
-const ClosureVarWithVarInjectionChecks = 6
-const Dynamic = 7
-
-const ResolveModeMask = 0xffff
+const GlobalLexicalVar = 2
+const ClosureVar = 3
+const LocalClosureVar = 4
+const GlobalPropertyWithVarInjectionChecks = 5
+const GlobalVarWithVarInjectionChecks = 6
+const GlobalLexicalVarWithVarInjectionChecks = 7
+const ClosureVarWithVarInjectionChecks = 8
+
+const ResolveTypeMask = 0x3ff
+const InitializationModeMask = 0xffc00
+const InitializationModeShift = 10
+const Initialization = 0
 
 const MarkedBlockSize = 16 * 1024
 const MarkedBlockMask = ~(MarkedBlockSize - 1)
index 7ef6b87..92e3ec8 100644 (file)
@@ -596,14 +596,14 @@ macro writeBarrierOnOperands(cellOperand, valueOperand)
     end
 end
 
-macro writeBarrierOnGlobalObject(valueOperand)
+macro writeBarrierOnGlobal(valueOperand, loadHelper)
     if GGC
         loadisFromInstruction(valueOperand, t1)
         loadConstantOrVariableTag(t1, t0)
         bineq t0, CellTag, .writeBarrierDone
+
+        loadHelper(t3)
     
-        loadp CodeBlock[cfr], t3
-        loadp CodeBlock::m_globalObject[t3], t3
         skipIfIsRememberedOrInEden(t3, t1, t2,
             macro(gcData)
                 btbnz gcData, .writeBarrierDone
@@ -619,6 +619,23 @@ macro writeBarrierOnGlobalObject(valueOperand)
     end
 end
 
+macro writeBarrierOnGlobalObject(valueOperand)
+    writeBarrierOnGlobal(valueOperand,
+        macro(registerToStoreGlobal)
+            loadp CodeBlock[cfr], registerToStoreGlobal
+            loadp CodeBlock::m_globalObject[registerToStoreGlobal], registerToStoreGlobal
+        end)
+end
+
+macro writeBarrierOnGlobalLexicalEnvironment(valueOperand)
+    writeBarrierOnGlobal(valueOperand,
+        macro(registerToStoreGlobal)
+            loadp CodeBlock[cfr], registerToStoreGlobal
+            loadp CodeBlock::m_globalObject[registerToStoreGlobal], registerToStoreGlobal
+            loadp JSGlobalObject::m_globalLexicalEnvironment[registerToStoreGlobal], registerToStoreGlobal
+        end)
+end
+
 macro valueProfile(tag, payload, operand, scratch)
     loadp operand[PC], scratch
     storei tag, ValueProfile::m_buckets + TagOffset[scratch]
@@ -2037,9 +2054,8 @@ macro nativeCallTrampoline(executableOffsetToFunction)
 end
 
 
-macro getGlobalObject(dst)
-    loadp CodeBlock[cfr], t0
-    loadp CodeBlock::m_globalObject[t0], t0
+macro getConstantScope(dst)
+    loadpFromInstruction(6, t0)
     loadisFromInstruction(dst, t1)
     storei CellTag, TagOffset[cfr, t1, 8]
     storei t0, PayloadOffset[cfr, t1, 8]
@@ -2078,12 +2094,17 @@ _llint_op_resolve_scope:
 
 #rGlobalProperty:
     bineq t0, GlobalProperty, .rGlobalVar
-    getGlobalObject(1)
+    getConstantScope(1)
     dispatch(7)
 
 .rGlobalVar:
-    bineq t0, GlobalVar, .rClosureVar
-    getGlobalObject(1)
+    bineq t0, GlobalVar, .rGlobalLexicalVar
+    getConstantScope(1)
+    dispatch(7)
+
+.rGlobalLexicalVar:
+    bineq t0, GlobalLexicalVar, .rClosureVar
+    getConstantScope(1)
     dispatch(7)
 
 .rClosureVar:
@@ -2094,13 +2115,19 @@ _llint_op_resolve_scope:
 .rGlobalPropertyWithVarInjectionChecks:
     bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks
     varInjectionCheck(.rDynamic)
-    getGlobalObject(1)
+    getConstantScope(1)
     dispatch(7)
 
 .rGlobalVarWithVarInjectionChecks:
-    bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
+    bineq t0, GlobalVarWithVarInjectionChecks, .rGlobalLexicalVarWithVarInjectionChecks
+    varInjectionCheck(.rDynamic)
+    getConstantScope(1)
+    dispatch(7)
+
+.rGlobalLexicalVarWithVarInjectionChecks:
+    bineq t0, GlobalLexicalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
     varInjectionCheck(.rDynamic)
-    getGlobalObject(1)
+    getConstantScope(1)
     dispatch(7)
 
 .rClosureVarWithVarInjectionChecks:
@@ -2110,7 +2137,7 @@ _llint_op_resolve_scope:
     dispatch(7)
 
 .rDynamic:
-    callSlowPath(_llint_slow_path_resolve_scope)
+    callSlowPath(_slow_path_resolve_scope)
     dispatch(7)
 
 
@@ -2130,10 +2157,11 @@ macro getProperty()
     storei t2, PayloadOffset[cfr, t0, 8]
 end
 
-macro getGlobalVar()
+macro getGlobalVar(tdzCheckIfNecessary)
     loadpFromInstruction(6, t0)
     loadp TagOffset[t0], t1
     loadp PayloadOffset[t0], t2
+    tdzCheckIfNecessary(t1)
     valueProfile(t1, t2, 28, t0)
     loadisFromInstruction(1, t0)
     storei t1, TagOffset[cfr, t0, 8]
@@ -2153,7 +2181,7 @@ end
 _llint_op_get_from_scope:
     traceExecution()
     loadisFromInstruction(4, t0)
-    andi ResolveModeMask, t0
+    andi ResolveTypeMask, t0
 
 #gGlobalProperty:
     bineq t0, GlobalProperty, .gGlobalVar
@@ -2162,8 +2190,16 @@ _llint_op_get_from_scope:
     dispatch(8)
 
 .gGlobalVar:
-    bineq t0, GlobalVar, .gClosureVar
-    getGlobalVar()
+    bineq t0, GlobalVar, .gGlobalLexicalVar
+    getGlobalVar(macro(t) end)
+    dispatch(8)
+
+.gGlobalLexicalVar:
+    bineq t0, GlobalLexicalVar, .gClosureVar
+    getGlobalVar(
+        macro(tag)
+            bieq tag, EmptyValueTag, .gDynamic
+        end)
     dispatch(8)
 
 .gClosureVar:
@@ -2179,9 +2215,18 @@ _llint_op_get_from_scope:
     dispatch(8)
 
 .gGlobalVarWithVarInjectionChecks:
-    bineq t0, GlobalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
+    bineq t0, GlobalVarWithVarInjectionChecks, .gGlobalLexicalVarWithVarInjectionChecks
     varInjectionCheck(.gDynamic)
-    getGlobalVar()
+    getGlobalVar(macro(t) end)
+    dispatch(8)
+
+.gGlobalLexicalVarWithVarInjectionChecks:
+    bineq t0, GlobalLexicalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
+    varInjectionCheck(.gDynamic)
+    getGlobalVar(
+        macro(tag)
+            bieq tag, EmptyValueTag, .gDynamic
+        end)
     dispatch(8)
 
 .gClosureVarWithVarInjectionChecks:
@@ -2203,7 +2248,7 @@ macro putProperty()
     storePropertyAtVariableOffset(t1, t0, t2, t3)
 end
 
-macro putGlobalVar()
+macro putGlobalVariable()
     loadisFromInstruction(3, t0)
     loadConstantOrVariable(t0, t1, t2)
     loadpFromInstruction(5, t3)
@@ -2237,7 +2282,7 @@ end
 _llint_op_put_to_scope:
     traceExecution()
     loadisFromInstruction(4, t0)
-    andi ResolveModeMask, t0
+    andi ResolveTypeMask, t0
 
 #pLocalClosureVar:
     bineq t0, LocalClosureVar, .pGlobalProperty
@@ -2254,9 +2299,15 @@ _llint_op_put_to_scope:
     dispatch(7)
 
 .pGlobalVar:
-    bineq t0, GlobalVar, .pClosureVar
+    bineq t0, GlobalVar, .pGlobalLexicalVar
     writeBarrierOnGlobalObject(3)
-    putGlobalVar()
+    putGlobalVariable()
+    dispatch(7)
+
+.pGlobalLexicalVar:
+    bineq t0, GlobalLexicalVar, .pClosureVar
+    writeBarrierOnGlobalLexicalEnvironment(3)
+    putGlobalVariable()
     dispatch(7)
 
 .pClosureVar:
@@ -2274,10 +2325,17 @@ _llint_op_put_to_scope:
     dispatch(7)
 
 .pGlobalVarWithVarInjectionChecks:
-    bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
+    bineq t0, GlobalVarWithVarInjectionChecks, .pGlobalLexicalVarWithVarInjectionChecks
     writeBarrierOnGlobalObject(3)
     varInjectionCheck(.pDynamic)
-    putGlobalVar()
+    putGlobalVariable()
+    dispatch(7)
+
+.pGlobalLexicalVarWithVarInjectionChecks:
+    bineq t0, GlobalLexicalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
+    writeBarrierOnGlobalLexicalEnvironment(3)
+    varInjectionCheck(.pDynamic)
+    putGlobalVariable()
     dispatch(7)
 
 .pClosureVarWithVarInjectionChecks:
@@ -2381,4 +2439,4 @@ _llint_op_load_arrowfunction_this:
     loadisFromInstruction(1, t1)
     storei CellTag, TagOffset[cfr, t1, 8]
     storei t0, PayloadOffset[cfr, t1, 8]
-    dispatch(2)
\ No newline at end of file
+    dispatch(2)
index d2152a2..7f338da 100644 (file)
@@ -466,14 +466,13 @@ macro writeBarrierOnOperands(cellOperand, valueOperand)
     end
 end
 
-macro writeBarrierOnGlobalObject(valueOperand)
+macro writeBarrierOnGlobal(valueOperand, loadHelper)
     if GGC
         loadisFromInstruction(valueOperand, t1)
         loadConstantOrVariableCell(t1, t0, .writeBarrierDone)
         btpz t0, .writeBarrierDone
     
-        loadp CodeBlock[cfr], t3
-        loadp CodeBlock::m_globalObject[t3], t3
+        loadHelper(t3)
         skipIfIsRememberedOrInEden(t3, t1, t2,
             macro(gcData)
                 btbnz gcData, .writeBarrierDone
@@ -486,6 +485,23 @@ macro writeBarrierOnGlobalObject(valueOperand)
     end
 end
 
+macro writeBarrierOnGlobalObject(valueOperand)
+    writeBarrierOnGlobal(valueOperand,
+        macro(registerToStoreGlobal)
+            loadp CodeBlock[cfr], registerToStoreGlobal
+            loadp CodeBlock::m_globalObject[registerToStoreGlobal], registerToStoreGlobal
+        end)
+end
+
+macro writeBarrierOnGlobalLexicalEnvironment(valueOperand)
+    writeBarrierOnGlobal(valueOperand,
+        macro(registerToStoreGlobal)
+            loadp CodeBlock[cfr], registerToStoreGlobal
+            loadp CodeBlock::m_globalObject[registerToStoreGlobal], registerToStoreGlobal
+            loadp JSGlobalObject::m_globalLexicalEnvironment[registerToStoreGlobal], registerToStoreGlobal
+        end)
+end
+
 macro valueProfile(value, operand, scratch)
     loadpFromInstruction(operand, scratch)
     storeq value, ValueProfile::m_buckets[scratch]
@@ -1910,10 +1926,8 @@ macro nativeCallTrampoline(executableOffsetToFunction)
     jmp _llint_throw_from_slow_path_trampoline
 end
 
-
-macro getGlobalObject(dst)
-    loadp CodeBlock[cfr], t0
-    loadp CodeBlock::m_globalObject[t0], t0
+macro getConstantScope(dst)
+    loadpFromInstruction(6, t0)
     loadisFromInstruction(dst, t1)
     storeq t0, [cfr, t1, 8]
 end
@@ -1948,12 +1962,17 @@ _llint_op_resolve_scope:
 
 #rGlobalProperty:
     bineq t0, GlobalProperty, .rGlobalVar
-    getGlobalObject(1)
+    getConstantScope(1)
     dispatch(7)
 
 .rGlobalVar:
-    bineq t0, GlobalVar, .rClosureVar
-    getGlobalObject(1)
+    bineq t0, GlobalVar, .rGlobalLexicalVar
+    getConstantScope(1)
+    dispatch(7)
+
+.rGlobalLexicalVar:
+    bineq t0, GlobalLexicalVar, .rClosureVar
+    getConstantScope(1)
     dispatch(7)
 
 .rClosureVar:
@@ -1964,13 +1983,19 @@ _llint_op_resolve_scope:
 .rGlobalPropertyWithVarInjectionChecks:
     bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks
     varInjectionCheck(.rDynamic)
-    getGlobalObject(1)
+    getConstantScope(1)
     dispatch(7)
 
 .rGlobalVarWithVarInjectionChecks:
-    bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
+    bineq t0, GlobalVarWithVarInjectionChecks, .rGlobalLexicalVarWithVarInjectionChecks
     varInjectionCheck(.rDynamic)
-    getGlobalObject(1)
+    getConstantScope(1)
+    dispatch(7)
+
+.rGlobalLexicalVarWithVarInjectionChecks:
+    bineq t0, GlobalLexicalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
+    varInjectionCheck(.rDynamic)
+    getConstantScope(1)
     dispatch(7)
 
 .rClosureVarWithVarInjectionChecks:
@@ -1980,7 +2005,7 @@ _llint_op_resolve_scope:
     dispatch(7)
 
 .rDynamic:
-    callSlowPath(_llint_slow_path_resolve_scope)
+    callSlowPath(_slow_path_resolve_scope)
     dispatch(7)
 
 
@@ -2000,9 +2025,10 @@ macro getProperty()
     storeq t2, [cfr, t0, 8]
 end
 
-macro getGlobalVar()
+macro getGlobalVar(tdzCheckIfNecessary)
     loadpFromInstruction(6, t0)
     loadq [t0], t0
+    tdzCheckIfNecessary(t0)
     valueProfile(t0, 7, t1)
     loadisFromInstruction(1, t1)
     storeq t0, [cfr, t1, 8]
@@ -2019,7 +2045,7 @@ end
 _llint_op_get_from_scope:
     traceExecution()
     loadisFromInstruction(4, t0)
-    andi ResolveModeMask, t0
+    andi ResolveTypeMask, t0
 
 #gGlobalProperty:
     bineq t0, GlobalProperty, .gGlobalVar
@@ -2028,8 +2054,16 @@ _llint_op_get_from_scope:
     dispatch(8)
 
 .gGlobalVar:
-    bineq t0, GlobalVar, .gClosureVar
-    getGlobalVar()
+    bineq t0, GlobalVar, .gGlobalLexicalVar
+    getGlobalVar(macro(v) end)
+    dispatch(8)
+
+.gGlobalLexicalVar:
+    bineq t0, GlobalLexicalVar, .gClosureVar
+    getGlobalVar(
+        macro (value)
+            bqeq value, ValueEmpty, .gDynamic
+        end)
     dispatch(8)
 
 .gClosureVar:
@@ -2045,9 +2079,18 @@ _llint_op_get_from_scope:
     dispatch(8)
 
 .gGlobalVarWithVarInjectionChecks:
-    bineq t0, GlobalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
+    bineq t0, GlobalVarWithVarInjectionChecks, .gGlobalLexicalVarWithVarInjectionChecks
     varInjectionCheck(.gDynamic)
-    getGlobalVar()
+    getGlobalVar(macro(v) end)
+    dispatch(8)
+
+.gGlobalLexicalVarWithVarInjectionChecks:
+    bineq t0, GlobalLexicalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
+    varInjectionCheck(.gDynamic)
+    getGlobalVar(
+        macro (value)
+            bqeq value, ValueEmpty, .gDynamic
+        end)
     dispatch(8)
 
 .gClosureVarWithVarInjectionChecks:
@@ -2069,7 +2112,7 @@ macro putProperty()
     storePropertyAtVariableOffset(t1, t0, t2)
 end
 
-macro putGlobalVar()
+macro putGlobalVariable()
     loadisFromInstruction(3, t0)
     loadConstantOrVariable(t0, t1)
     loadpFromInstruction(5, t2)
@@ -2096,11 +2139,22 @@ macro putLocalClosureVar()
     storeq t2, JSEnvironmentRecord_variables[t0, t1, 8]
 end
 
+macro checkTDZInGlobalPutToScopeIfNecessary()
+    loadisFromInstruction(4, t0)
+    andi InitializationModeMask, t0
+    rshifti InitializationModeShift, t0
+    bieq t0, Initialization, .noNeedForTDZCheck
+    loadpFromInstruction(6, t0)
+    loadq [t0], t0
+    bqeq t0, ValueEmpty, .pDynamic
+.noNeedForTDZCheck:
+end
+
 
 _llint_op_put_to_scope:
     traceExecution()
     loadisFromInstruction(4, t0)
-    andi ResolveModeMask, t0
+    andi ResolveTypeMask, t0
 
 #pLocalClosureVar:
     bineq t0, LocalClosureVar, .pGlobalProperty
@@ -2117,9 +2171,16 @@ _llint_op_put_to_scope:
     dispatch(7)
 
 .pGlobalVar:
-    bineq t0, GlobalVar, .pClosureVar
+    bineq t0, GlobalVar, .pGlobalLexicalVar
     writeBarrierOnGlobalObject(3)
-    putGlobalVar()
+    putGlobalVariable()
+    dispatch(7)
+
+.pGlobalLexicalVar:
+    bineq t0, GlobalLexicalVar, .pClosureVar
+    writeBarrierOnGlobalLexicalEnvironment(3)
+    checkTDZInGlobalPutToScopeIfNecessary()
+    putGlobalVariable()
     dispatch(7)
 
 .pClosureVar:
@@ -2137,10 +2198,18 @@ _llint_op_put_to_scope:
     dispatch(7)
 
 .pGlobalVarWithVarInjectionChecks:
-    bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
+    bineq t0, GlobalVarWithVarInjectionChecks, .pGlobalLexicalVarWithVarInjectionChecks
     writeBarrierOnGlobalObject(3)
     varInjectionCheck(.pDynamic)
-    putGlobalVar()
+    putGlobalVariable()
+    dispatch(7)
+
+.pGlobalLexicalVarWithVarInjectionChecks:
+    bineq t0, GlobalLexicalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
+    writeBarrierOnGlobalLexicalEnvironment(3)
+    varInjectionCheck(.pDynamic)
+    checkTDZInGlobalPutToScopeIfNecessary()
+    putGlobalVariable()
     dispatch(7)
 
 .pClosureVarWithVarInjectionChecks:
@@ -2233,4 +2302,4 @@ _llint_op_load_arrowfunction_this:
     loadp JSArrowFunction::m_boundThis[t0], t0
     loadisFromInstruction(1, t1)
     storeq t0, [cfr, t1, 8]
-    dispatch(2)
\ No newline at end of file
+    dispatch(2)
index 7580833..e829f85 100644 (file)
@@ -660,4 +660,34 @@ SLOW_PATH_DECL(slow_path_push_with_scope)
     RETURN(JSWithScope::create(exec, newScope, currentScope));
 }
 
+SLOW_PATH_DECL(slow_path_resolve_scope)
+{
+    BEGIN();
+    const Identifier& ident = exec->codeBlock()->identifier(pc[3].u.operand);
+    JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+    JSValue resolvedScope = JSScope::resolve(exec, scope, ident);
+
+    ResolveType resolveType = static_cast<ResolveType>(pc[4].u.operand);
+    if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
+        if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(resolvedScope)) {
+            if (resolveType == UnresolvedProperty)
+                pc[4].u.operand = GlobalLexicalVar;
+            else
+                pc[4].u.operand = GlobalLexicalVarWithVarInjectionChecks;
+            pc[6].u.pointer = globalLexicalEnvironment;
+        } else if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(resolvedScope)) {
+            if (globalObject->hasProperty(exec, ident)) {
+                if (resolveType == UnresolvedProperty)
+                    pc[4].u.operand = GlobalProperty;
+                else
+                    pc[4].u.operand = GlobalPropertyWithVarInjectionChecks;
+
+                pc[6].u.pointer = globalObject;
+            }
+        }
+    }
+
+    RETURN(resolvedScope);
+}
+
 } // namespace JSC
index 067df0c..8c9867f 100644 (file)
@@ -90,29 +90,81 @@ inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal)
 
 inline void tryCachePutToScopeGlobal(
     ExecState* exec, CodeBlock* codeBlock, Instruction* pc, JSObject* scope,
-    ResolveModeAndType modeAndType, PutPropertySlot& slot)
+    GetPutInfo getPutInfo, PutPropertySlot& slot, const Identifier& ident)
 {
     // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
     
-    if (modeAndType.type() != GlobalProperty && modeAndType.type() != GlobalPropertyWithVarInjectionChecks)
-        return;
-    
-    if (!slot.isCacheablePut()
-        || slot.base() != scope
-        || !scope->structure()->propertyAccessesAreCacheable())
-        return;
-    
-    if (slot.type() == PutPropertySlot::NewProperty) {
-        // Don't cache if we've done a transition. We want to detect the first replace so that we
-        // can invalidate the watchpoint.
+    ResolveType resolveType = getPutInfo.resolveType();
+    if (resolveType != GlobalProperty && resolveType != GlobalPropertyWithVarInjectionChecks 
+        && resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
         return;
+
+    if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
+        if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+            ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
+            pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+            SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
+            ASSERT(!entry.isNull());
+            pc[5].u.watchpointSet = entry.watchpointSet();
+            pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
+        } else if (jsDynamicCast<JSGlobalObject*>(scope)) {
+            ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
+            pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+
+            if (!slot.isCacheablePut()
+                || slot.base() != scope
+                || !scope->structure()->propertyAccessesAreCacheable())
+                return;
+            
+            if (slot.type() == PutPropertySlot::NewProperty) {
+                // Don't cache if we've done a transition. We want to detect the first replace so that we
+                // can invalidate the watchpoint.
+                return;
+            }
+            
+            scope->structure()->didCachePropertyReplacement(exec->vm(), slot.cachedOffset());
+
+            ConcurrentJITLocker locker(codeBlock->m_lock);
+            pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure());
+            pc[6].u.operand = slot.cachedOffset();
+        }
     }
-    
-    scope->structure()->didCachePropertyReplacement(exec->vm(), slot.cachedOffset());
+}
+
+inline void tryCacheGetFromScopeGlobal(
+    ExecState* exec, VM& vm, Instruction* pc, JSObject* scope, PropertySlot& slot, const Identifier& ident)
+{
+    GetPutInfo getPutInfo(pc[4].u.operand);
+    ResolveType resolveType = getPutInfo.resolveType();
 
-    ConcurrentJITLocker locker(codeBlock->m_lock);
-    pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure());
-    pc[6].u.operand = slot.cachedOffset();
+    if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
+        if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+            ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
+            pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+            SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
+            ASSERT(!entry.isNull());
+            pc[5].u.watchpointSet = entry.watchpointSet();
+            pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
+        } else if (jsDynamicCast<JSGlobalObject*>(scope)) {
+            ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
+            resolveType = newResolveType; // Allow bottom caching mechanism to kick in.
+            pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+        }
+    }
+
+    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
+    if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure()->propertyAccessesAreCacheable()) {
+        if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) {
+            CodeBlock* codeBlock = exec->codeBlock();
+            Structure* structure = scope->structure(vm);
+            {
+                ConcurrentJITLocker locker(codeBlock->m_lock);
+                pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), structure);
+                pc[6].u.operand = slot.cachedOffset();
+            }
+            structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
+        }
+    }
 }
 
 } // namespace CommonSlowPaths
@@ -235,6 +287,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
 SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log);
 SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment);
 SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
+SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
 
 } // namespace JSC
 
index b1d0055..b3172e6 100644 (file)
@@ -539,6 +539,40 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF
     if (exception)
         return exception;
 
+    JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment();
+    const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
+    const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations();
+    // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope.
+    // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation
+    {
+        ExecState* exec = globalObject->globalExec();
+        // Check for intersection of "var" and "let"/"const"/"class"
+        for (auto& entry : lexicalDeclarations) {
+            if (variableDeclarations.contains(entry.key))
+                return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
+        }
+
+        // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables.
+        // It's an error to introduce a shadow.
+        for (auto& entry : lexicalDeclarations) {
+            if (globalObject->hasProperty(exec, entry.key.get()))
+                return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'"));
+
+            if (globalLexicalEnvironment->hasProperty(exec, entry.key.get()))
+                return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
+        }
+
+        // Check if any new "var"s will shadow any previous "let"/"const"/"class" names.
+        // It's an error to introduce a shadow.
+        if (!globalLexicalEnvironment->isEmpty()) {
+            for (auto& entry : variableDeclarations) {
+                if (globalLexicalEnvironment->hasProperty(exec, entry.key.get()))
+                    return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
+            }
+        }
+    }
+
+
     m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock);
 
     BatchedTransitionOptimizer optimizer(vm, globalObject);
@@ -554,11 +588,25 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF
         }
     }
 
-    const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
     for (auto& entry : variableDeclarations) {
         ASSERT(entry.value.isVar());
         globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get()));
     }
+
+    {
+        JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope());
+        SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable();
+        ConcurrentJITLocker locker(symbolTable->m_lock);
+        for (auto& entry : lexicalDeclarations) {
+            ScopeOffset offset = symbolTable->takeNextScopeOffset(locker);
+            SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0);
+            newEntry.prepareToWatch();
+            symbolTable->add(locker, entry.key.get(), newEntry);
+            
+            ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue());
+            RELEASE_ASSERT(offsetForAssert == offset);
+        }
+    }
     return 0;
 }
 
diff --git a/Source/JavaScriptCore/runtime/GetPutInfo.h b/Source/JavaScriptCore/runtime/GetPutInfo.h
new file mode 100644 (file)
index 0000000..2e7a2ef
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef GetPutInfo_h
+#define GetPutInfo_h
+
+namespace JSC {
+
+class Structure;
+class WatchpointSet;
+class JSLexicalEnvironment;
+
+enum ResolveMode {
+    ThrowIfNotFound,
+    DoNotThrowIfNotFound
+};
+
+enum ResolveType {
+    // Lexical scope guaranteed a certain type of variable access.
+    GlobalProperty,
+    GlobalVar,
+    GlobalLexicalVar,
+    ClosureVar,
+    LocalClosureVar,
+
+    // Ditto, but at least one intervening scope used non-strict eval, which
+    // can inject an intercepting var delcaration at runtime.
+    GlobalPropertyWithVarInjectionChecks,
+    GlobalVarWithVarInjectionChecks,
+    GlobalLexicalVarWithVarInjectionChecks,
+    ClosureVarWithVarInjectionChecks,
+
+    // We haven't found which scope this belongs to, and we also
+    // haven't ruled out the possibility of it being cached. Ideally,
+    // we want to transition this to GlobalVar/GlobalLexicalVar/GlobalProperty <with/without injection>
+    UnresolvedProperty,
+    UnresolvedPropertyWithVarInjectionChecks,
+
+    // Lexical scope didn't prove anything -- probably because of a 'with' scope.
+    Dynamic
+};
+
+enum InitializationMode {
+    Initialization,   // "let x = 20;"
+    NotInitialization // "x = 20;"
+}; 
+
+ALWAYS_INLINE const char* resolveModeName(ResolveMode resolveMode)
+{
+    static const char* const names[] = {
+        "ThrowIfNotFound",
+        "DoNotThrowIfNotFound"
+    };
+    return names[resolveMode];
+}
+
+ALWAYS_INLINE const char* resolveTypeName(ResolveType type)
+{
+    static const char* const names[] = {
+        "GlobalProperty",
+        "GlobalVar",
+        "GlobalLexicalVar",
+        "ClosureVar",
+        "LocalClosureVar",
+        "GlobalPropertyWithVarInjectionChecks",
+        "GlobalVarWithVarInjectionChecks",
+        "GlobalLexicalVarWithVarInjectionChecks",
+        "ClosureVarWithVarInjectionChecks",
+        "UnresolvedProperty",
+        "UnresolvedPropertyWithVarInjectionChecks",
+        "Dynamic"
+    };
+    return names[type];
+}
+
+ALWAYS_INLINE const char* initializationModeName(InitializationMode initializationMode)
+{
+    static const char* const names[] = {
+        "Initialization",
+        "NotInitialization"
+    };
+    return names[initializationMode];
+}
+
+
+ALWAYS_INLINE ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
+{
+    if (!needsVarInjectionChecks)
+        return type;
+
+    switch (type) {
+    case GlobalProperty:
+        return GlobalPropertyWithVarInjectionChecks;
+    case GlobalVar:
+        return GlobalVarWithVarInjectionChecks;
+    case GlobalLexicalVar:
+        return GlobalLexicalVarWithVarInjectionChecks;
+    case ClosureVar:
+    case LocalClosureVar:
+        return ClosureVarWithVarInjectionChecks;
+    case UnresolvedProperty:
+        return UnresolvedPropertyWithVarInjectionChecks;
+    case GlobalPropertyWithVarInjectionChecks:
+    case GlobalVarWithVarInjectionChecks:
+    case GlobalLexicalVarWithVarInjectionChecks:
+    case ClosureVarWithVarInjectionChecks:
+    case UnresolvedPropertyWithVarInjectionChecks:
+    case Dynamic:
+        return type;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+    return type;
+}
+
+ALWAYS_INLINE bool needsVarInjectionChecks(ResolveType type)
+{
+    switch (type) {
+    case GlobalProperty:
+    case GlobalVar:
+    case GlobalLexicalVar:
+    case ClosureVar:
+    case LocalClosureVar:
+    case UnresolvedProperty:
+        return false;
+    case GlobalPropertyWithVarInjectionChecks:
+    case GlobalVarWithVarInjectionChecks:
+    case GlobalLexicalVarWithVarInjectionChecks:
+    case ClosureVarWithVarInjectionChecks:
+    case UnresolvedPropertyWithVarInjectionChecks:
+    case Dynamic:
+        return true;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return true;
+    }
+}
+
+struct ResolveOp {
+    ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, WatchpointSet* watchpointSet, uintptr_t operand)
+        : type(type)
+        , depth(depth)
+        , structure(structure)
+        , lexicalEnvironment(lexicalEnvironment)
+        , watchpointSet(watchpointSet)
+        , operand(operand)
+    {
+    }
+
+    ResolveType type;
+    size_t depth;
+    Structure* structure;
+    JSLexicalEnvironment* lexicalEnvironment;
+    WatchpointSet* watchpointSet;
+    uintptr_t operand;
+};
+
+class GetPutInfo {
+    typedef unsigned Operand;
+public:
+    // Give each field 10 bits for simplicity.
+    static_assert(sizeof(Operand) * 8 > 30, "Not enough bits for GetPutInfo");
+    static const unsigned modeShift = 20;
+    static const unsigned initializationShift = 10;
+    static const unsigned typeBits = (1 << initializationShift) - 1;
+    static const unsigned initializationBits = ((1 << modeShift) - 1) & ~typeBits;
+    static const unsigned modeBits = ((1 << 30) - 1) & ~initializationBits & ~typeBits;
+    static_assert((modeBits & initializationBits & typeBits) == 0x0, "There should be no intersection between ResolveMode ResolveType and InitializationMode");
+
+    GetPutInfo(ResolveMode resolveMode, ResolveType resolveType, InitializationMode initializationMode)
+        : m_operand((resolveMode << modeShift) | (initializationMode << initializationShift) | resolveType)
+    {
+    }
+
+    explicit GetPutInfo(unsigned operand)
+        : m_operand(operand)
+    {
+    }
+
+    ResolveType resolveType() const { return static_cast<ResolveType>(m_operand & typeBits); }
+    InitializationMode initializationMode() const { return static_cast<InitializationMode>((m_operand & initializationBits) >> initializationShift); }
+    ResolveMode resolveMode() const { return static_cast<ResolveMode>((m_operand & modeBits) >> modeShift); }
+    unsigned operand() { return m_operand; }
+
+private:
+    Operand m_operand;
+};
+
+enum GetOrPut { Get, Put };
+
+} // namespace JSC
+
+#endif // GetPutInfo_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp b/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp
new file mode 100644 (file)
index 0000000..f5ff0cf
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "JSGlobalLexicalEnvironment.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSGlobalLexicalEnvironment::s_info = { "JSGlobalLexicalEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSGlobalLexicalEnvironment) };
+
+bool JSGlobalLexicalEnvironment::getOwnPropertySlot(JSObject* object, ExecState*, PropertyName propertyName, PropertySlot& slot)
+{
+    JSGlobalLexicalEnvironment* thisObject = jsCast<JSGlobalLexicalEnvironment*>(object);
+    return symbolTableGet(thisObject, propertyName, slot);
+}
+
+void JSGlobalLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+    JSGlobalLexicalEnvironment* thisObject = jsCast<JSGlobalLexicalEnvironment*>(cell);
+    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+    bool alwaysThrowWhenAssigningToConstProperty = true;
+    bool ignoreConstAssignmentError = slot.isInitialization();
+    symbolTablePut(thisObject, exec, propertyName, value, alwaysThrowWhenAssigningToConstProperty, ignoreConstAssignmentError);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h b/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h
new file mode 100644 (file)
index 0000000..643f095
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef JSGlobalLexicalEnvironment_h
+#define JSGlobalLexicalEnvironment_h
+
+#include "JSSegmentedVariableObject.h"
+
+namespace JSC {
+
+class JSGlobalLexicalEnvironment : public JSSegmentedVariableObject {
+
+public:
+    typedef JSSegmentedVariableObject Base;
+
+    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+    static JSGlobalLexicalEnvironment* create(VM& vm, Structure* structure, JSScope* parentScope)
+    {
+        JSGlobalLexicalEnvironment* result =
+            new (NotNull, allocateCell<JSGlobalLexicalEnvironment>(vm.heap)) JSGlobalLexicalEnvironment(vm, structure, parentScope);
+        result->finishCreation(vm);
+        result->symbolTable()->setScopeType(SymbolTable::ScopeType::GlobalLexicalScope);
+        return result;
+    }
+
+    static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+    static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
+    bool isEmpty() const { return !symbolTable()->size(); }
+    
+    DECLARE_INFO;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
+    {
+        return Structure::create(vm, globalObject, jsNull(), TypeInfo(ClosureObjectType, StructureFlags), info());
+    }
+
+protected:
+    JSGlobalLexicalEnvironment(VM& vm, Structure* structure, JSScope* scope)
+        : Base(vm, structure, scope)
+    {
+    }
+};
+
+} // namespace JSC
+
+#endif // JSGlobalLexicalEnvironment_h
+
index 4e094fd..ad37bae 100644 (file)
@@ -262,8 +262,9 @@ void JSGlobalObject::init(VM& vm)
     m_functionPrototype.set(vm, this, FunctionPrototype::create(vm, FunctionPrototype::createStructure(vm, this, jsNull()))); // The real prototype will be set once ObjectPrototype is created.
     m_calleeStructure.set(vm, this, JSCallee::createStructure(vm, this, jsNull()));
 
+    m_globalLexicalEnvironment.set(vm, this, JSGlobalLexicalEnvironment::create(vm, JSGlobalLexicalEnvironment::createStructure(vm, this), this));
     // Need to create the callee structure (above) before creating the callee.
-    m_globalCallee.set(vm, this, JSCallee::create(vm, this, this));
+    m_globalCallee.set(vm, this, JSCallee::create(vm, this, globalScope()));
     exec->setCallee(m_globalCallee.get());
 
     m_functionStructure.set(vm, this, JSFunction::createStructure(vm, this, m_functionPrototype.get()));
@@ -552,7 +553,7 @@ void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyNam
     JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
 
-    if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode()))
+    if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode(), false))
         return;
     Base::put(thisObject, exec, propertyName, value, slot);
 }
@@ -579,7 +580,7 @@ void JSGlobalObject::addGlobalVar(const Identifier& ident)
     newEntry.prepareToWatch();
     symbolTable()->add(locker, ident.impl(), newEntry);
     
-    ScopeOffset offsetForAssert = addVariables(1);
+    ScopeOffset offsetForAssert = addVariables(1, jsUndefined());
     RELEASE_ASSERT(offsetForAssert == offset);
 }
 
@@ -754,6 +755,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
     visitor.append(&thisObject->m_globalThis);
 
+    visitor.append(&thisObject->m_globalLexicalEnvironment);
     visitor.append(&thisObject->m_globalCallee);
     visitor.append(&thisObject->m_regExpConstructor);
     visitor.append(&thisObject->m_errorConstructor);
@@ -855,7 +857,7 @@ ExecState* JSGlobalObject::globalExec()
 
 void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
 {
-    ScopeOffset startOffset = addVariables(count);
+    ScopeOffset startOffset = addVariables(count, jsUndefined());
 
     for (int i = 0; i < count; ++i) {
         GlobalPropertyInfo& global = globals[i];
index 1ca31b7..461959d 100644 (file)
@@ -26,6 +26,7 @@
 #include "JSArray.h"
 #include "JSArrayBufferPrototype.h"
 #include "JSClassRef.h"
+#include "JSGlobalLexicalEnvironment.h"
 #include "JSProxy.h"
 #include "JSSegmentedVariableObject.h"
 #include "JSWeakObjectMapRefInternal.h"
@@ -193,6 +194,7 @@ protected:
 
     WriteBarrier<JSObject> m_globalThis;
 
+    WriteBarrier<JSGlobalLexicalEnvironment> m_globalLexicalEnvironment;
     WriteBarrier<JSObject> m_globalCallee;
     WriteBarrier<RegExpConstructor> m_regExpConstructor;
     WriteBarrier<ErrorConstructor> m_errorConstructor;
@@ -385,10 +387,6 @@ public:
     JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes);
     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
 
-    // We use this in the code generator as we perform symbol table
-    // lookups prior to initializing the properties
-    bool symbolTableHasProperty(PropertyName);
-
     void addVar(ExecState* exec, const Identifier& propertyName)
     {
         if (!hasProperty(exec, propertyName))
@@ -396,6 +394,9 @@ public:
     }
     void addFunction(ExecState*, const Identifier&);
 
+    JSScope* globalScope() { return m_globalLexicalEnvironment.get(); }
+    JSGlobalLexicalEnvironment* globalLexicalEnvironment() { return m_globalLexicalEnvironment.get(); }
+
     // The following accessors return pristine values, even if a script 
     // replaces the global object's associated property.
 
@@ -693,12 +694,6 @@ inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName
     return symbolTableGet(this, propertyName, slot, slotIsWriteable);
 }
 
-inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName)
-{
-    SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid());
-    return !entry.isNull();
-}
-
 inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
 {
     return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->vm(), initialLength >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength));
index b7ee125..2bf13bb 100644 (file)
@@ -585,7 +585,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
     if (!eval)
         return JSValue::encode(jsUndefined());
 
-    return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject));
+    return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject->globalScope()));
 }
 
 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
index 9516318..507312e 100644 (file)
@@ -75,7 +75,7 @@ public:
 
     DECLARE_INFO;
 
-    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(ActivationObjectType, StructureFlags), info()); }
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(ClosureObjectType, StructureFlags), info()); }
 
 private:
     bool symbolTableGet(PropertyName, PropertySlot&);
index 9ded8ee..95d4efa 100644 (file)
@@ -597,10 +597,6 @@ public:
     JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
 
     bool isGlobalObject() const;
-    bool isVariableObject() const;
-    bool isStaticScopeObject() const;
-    bool isNameScopeObject() const;
-    bool isActivationObject() const;
     bool isErrorInstance() const;
     bool isWithScope() const;
 
@@ -1012,27 +1008,6 @@ inline bool JSObject::isGlobalObject() const
     return type() == GlobalObjectType;
 }
 
-inline bool JSObject::isVariableObject() const
-{
-    return type() == GlobalObjectType || type() == ActivationObjectType;
-}
-
-inline bool JSObject::isStaticScopeObject() const
-{
-    JSType type = this->type();
-    return type == NameScopeObjectType || type == ActivationObjectType;
-}
-
-inline bool JSObject::isNameScopeObject() const
-{
-    return type() == NameScopeObjectType;
-}
-
-inline bool JSObject::isActivationObject() const
-{
-    return type() == ActivationObjectType;
-}
-
 inline bool JSObject::isErrorInstance() const
 {
     return type() == ErrorInstanceType;
index bb2efdd..128a602 100644 (file)
@@ -44,7 +44,7 @@ void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
 }
 
 // Returns true if we found enough information to terminate optimization.
-static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op)
+static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op, InitializationMode initializationMode)
 {
     if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(scope)) {
         if (ident == exec->propertyNames().arguments) {
@@ -70,6 +70,33 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif
         return false;
     }
 
+    if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+        SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
+        if (!entry.isNull()) {
+            if (getOrPut == Put && entry.isReadOnly() && initializationMode != Initialization) {
+                // We know the property will be at global lexical environment, but we don't know how to cache it.
+                op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
+                return true;
+            }
+
+            // We can try to force const Initialization to always go down the fast path. It is provably impossible to construct
+            // a program that needs a var injection check here. You can convince yourself of this as follows:
+            // Any other let/const/class would be a duplicate of this in the global scope, so we would never get here in that situation.
+            // Also, if we had an eval in the global scope that defined a const, it would also be a duplicate of this const, and so it would
+            // also throw an error. Therefore, we're *the only* thing that can assign to this "const" slot for the first (and only) time. Also, 
+            // we will never have a Dynamic ResolveType here because if we were inside a "with" statement, that would mean the "const" definition 
+            // isn't a global, it would be a local to the "with" block. 
+            // We still need to make the slow path correct for when we need to fire a watchpoint.
+            ResolveType resolveType = initializationMode == Initialization ? GlobalLexicalVar : makeType(GlobalLexicalVar, needsVarInjectionChecks);
+            op = ResolveOp(
+                resolveType, depth, 0, 0, entry.watchpointSet(),
+                reinterpret_cast<uintptr_t>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()));
+            return true;
+        }
+
+        return false;
+    }
+
     if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(scope)) {
         SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl());
         if (!entry.isNull()) {
@@ -92,7 +119,7 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif
             || (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) {
             // We know the property will be at global scope, but we don't know how to cache it.
             ASSERT(!scope->next());
-            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0);
+            op = ResolveOp(makeType(UnresolvedProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0);
             return true;
         }
         
@@ -161,7 +188,7 @@ JSValue JSScope::resolve(ExecState* exec, JSScope* scope, const Identifier& iden
     }
 }
 
-ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType)
+ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType, InitializationMode initializationMode)
 {
     ResolveOp op(Dynamic, 0, 0, 0, 0, 0);
     if (unlinkedType == Dynamic)
@@ -170,7 +197,7 @@ ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope*
     bool needsVarInjectionChecks = JSC::needsVarInjectionChecks(unlinkedType);
     size_t depth = depthOffset;
     for (; scope; scope = scope->next()) {
-        if (abstractAccess(exec, scope, ident, getOrPut, depth, needsVarInjectionChecks, op))
+        if (abstractAccess(exec, scope, ident, getOrPut, depth, needsVarInjectionChecks, op, initializationMode))
             break;
         ++depth;
     }
@@ -181,63 +208,68 @@ ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope*
 void JSScope::collectVariablesUnderTDZ(JSScope* scope, VariableEnvironment& result)
 {
     for (; scope; scope = scope->next()) {
-        if (!scope->isLexicalScope())
+        if (!scope->isLexicalScope() && !scope->isGlobalLexicalEnvironment())
             continue;
-        SymbolTable* symbolTable = jsCast<JSLexicalEnvironment*>(scope)->symbolTable();
-        ASSERT(symbolTable->scopeType() == SymbolTable::ScopeType::LexicalScope);
+        SymbolTable* symbolTable = jsCast<JSSymbolTableObject*>(scope)->symbolTable();
+        ASSERT(symbolTable->scopeType() == SymbolTable::ScopeType::LexicalScope || symbolTable->scopeType() == SymbolTable::ScopeType::GlobalLexicalScope);
         ConcurrentJITLocker locker(symbolTable->m_lock);
         for (auto end = symbolTable->end(locker), iter = symbolTable->begin(locker); iter != end; ++iter)
             result.add(iter->key);
     }
 }
 
-bool JSScope::isLexicalScope()
+template <typename EnvironmentType, SymbolTable::ScopeType scopeType>
+inline static bool isScopeType(JSScope* scope)
 {
-    JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(this);
-    if (!lexicalEnvironment) // Global object does not hold any lexical variables so we can ignore it.
+    EnvironmentType* environment = jsDynamicCast<EnvironmentType*>(scope);
+    if (!environment)
         return false;
 
-    return lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::LexicalScope;
+    return environment->symbolTable()->scopeType() == scopeType;
+}
+
+bool JSScope::isVarScope()
+{
+    return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::VarScope>(this);
+}
+
+bool JSScope::isLexicalScope()
+{
+    return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::LexicalScope>(this);
 }
 
 bool JSScope::isCatchScope()
 {
-    JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(this);
-    if (!lexicalEnvironment)
-        return false;
-    return lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::CatchScope;
+    return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::CatchScope>(this);
 }
 
 bool JSScope::isFunctionNameScopeObject()
 {
-    JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(this);
-    if (!lexicalEnvironment)
-        return false;
-    return lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::FunctionNameScope;
+    return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::FunctionNameScope>(this);
 }
 
-const char* resolveModeName(ResolveMode mode)
+bool JSScope::isGlobalLexicalEnvironment()
 {
-    static const char* const names[] = {
-        "ThrowIfNotFound",
-        "DoNotThrowIfNotFound"
-    };
-    return names[mode];
+    return isScopeType<JSGlobalLexicalEnvironment, SymbolTable::ScopeType::GlobalLexicalScope>(this);
 }
 
-const char* resolveTypeName(ResolveType type)
+JSScope* JSScope::constantScopeForCodeBlock(ResolveType type, CodeBlock* codeBlock)
 {
-    static const char* const names[] = {
-        "GlobalProperty",
-        "GlobalVar",
-        "ClosureVar",
-        "LocalClosureVar",
-        "GlobalPropertyWithVarInjectionChecks",
-        "GlobalVarWithVarInjectionChecks",
-        "ClosureVarWithVarInjectionChecks",
-        "Dynamic"
-    };
-    return names[type];
+    switch (type) {
+    case GlobalProperty:
+    case GlobalVar:
+    case GlobalPropertyWithVarInjectionChecks:
+    case GlobalVarWithVarInjectionChecks:
+        return codeBlock->globalObject();
+    case GlobalLexicalVarWithVarInjectionChecks:
+    case GlobalLexicalVar:
+        return codeBlock->globalObject()->globalLexicalEnvironment();
+    default:
+        return nullptr;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+    return nullptr;
 }
 
 } // namespace JSC
index a653167..06d9ef1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012-2015  Apple Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
 #ifndef JSScope_h
 #define JSScope_h
 
+#include "GetPutInfo.h"
 #include "JSObject.h"
 #include "VariableEnvironment.h"
 
@@ -34,119 +35,6 @@ namespace JSC {
 class ScopeChainIterator;
 class WatchpointSet;
 
-enum ResolveMode {
-    ThrowIfNotFound,
-    DoNotThrowIfNotFound
-};
-
-enum ResolveType {
-    // Lexical scope guaranteed a certain type of variable access.
-    GlobalProperty,
-    GlobalVar,
-    ClosureVar,
-    LocalClosureVar,
-
-    // Ditto, but at least one intervening scope used non-strict eval, which
-    // can inject an intercepting var delcaration at runtime.
-    GlobalPropertyWithVarInjectionChecks,
-    GlobalVarWithVarInjectionChecks,
-    ClosureVarWithVarInjectionChecks,
-
-    // Lexical scope didn't prove anything -- probably because of a 'with' scope.
-    Dynamic
-};
-
-const char* resolveModeName(ResolveMode mode);
-const char* resolveTypeName(ResolveType type);
-
-inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
-{
-    if (!needsVarInjectionChecks)
-        return type;
-
-    switch (type) {
-    case GlobalProperty:
-        return GlobalPropertyWithVarInjectionChecks;
-    case GlobalVar:
-        return GlobalVarWithVarInjectionChecks;
-    case ClosureVar:
-    case LocalClosureVar:
-        return ClosureVarWithVarInjectionChecks;
-    case GlobalPropertyWithVarInjectionChecks:
-    case GlobalVarWithVarInjectionChecks:
-    case ClosureVarWithVarInjectionChecks:
-    case Dynamic:
-        return type;
-    }
-
-    RELEASE_ASSERT_NOT_REACHED();
-    return type;
-}
-
-inline bool needsVarInjectionChecks(ResolveType type)
-{
-    switch (type) {
-    case GlobalProperty:
-    case GlobalVar:
-    case ClosureVar:
-    case LocalClosureVar:
-        return false;
-    case GlobalPropertyWithVarInjectionChecks:
-    case GlobalVarWithVarInjectionChecks:
-    case ClosureVarWithVarInjectionChecks:
-    case Dynamic:
-        return true;
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        return true;
-    }
-}
-
-struct ResolveOp {
-    ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, WatchpointSet* watchpointSet, uintptr_t operand)
-        : type(type)
-        , depth(depth)
-        , structure(structure)
-        , lexicalEnvironment(lexicalEnvironment)
-        , watchpointSet(watchpointSet)
-        , operand(operand)
-    {
-    }
-
-    ResolveType type;
-    size_t depth;
-    Structure* structure;
-    JSLexicalEnvironment* lexicalEnvironment;
-    WatchpointSet* watchpointSet;
-    uintptr_t operand;
-};
-
-class ResolveModeAndType {
-    typedef unsigned Operand;
-public:
-    static const size_t shift = sizeof(Operand) * 8 / 2;
-    static const unsigned mask = (1 << shift) - 1;
-
-    ResolveModeAndType(ResolveMode resolveMode, ResolveType resolveType)
-        : m_operand((resolveMode << shift) | resolveType)
-    {
-    }
-
-    explicit ResolveModeAndType(unsigned operand)
-        : m_operand(operand)
-    {
-    }
-
-    ResolveMode mode() { return static_cast<ResolveMode>(m_operand >> shift); }
-    ResolveType type() { return static_cast<ResolveType>(m_operand & mask); }
-    unsigned operand() { return m_operand; }
-
-private:
-    Operand m_operand;
-};
-
-enum GetOrPut { Get, Put };
-
 class JSScope : public JSNonFinalObject {
 public:
     typedef JSNonFinalObject Base;
@@ -158,13 +46,18 @@ public:
     static JSObject* objectAtScope(JSScope*);
 
     static JSValue resolve(ExecState*, JSScope*, const Identifier&);
-    static ResolveOp abstractResolve(ExecState*, size_t depthOffset, JSScope*, const Identifier&, GetOrPut, ResolveType);
+    static ResolveOp abstractResolve(ExecState*, size_t depthOffset, JSScope*, const Identifier&, GetOrPut, ResolveType, InitializationMode);
+
+    static bool hasConstantScope(ResolveType);
+    static JSScope* constantScopeForCodeBlock(ResolveType, CodeBlock*);
 
     static void collectVariablesUnderTDZ(JSScope*, VariableEnvironment& result);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
+    bool isVarScope();
     bool isLexicalScope();
+    bool isGlobalLexicalEnvironment();
     bool isCatchScope();
     bool isFunctionNameScopeObject();
 
index 2502fa8..15f19f5 100644 (file)
@@ -46,7 +46,7 @@ ScopeOffset JSSegmentedVariableObject::findVariableIndex(void* variableAddress)
     return ScopeOffset();
 }
 
-ScopeOffset JSSegmentedVariableObject::addVariables(unsigned numberOfVariablesToAdd)
+ScopeOffset JSSegmentedVariableObject::addVariables(unsigned numberOfVariablesToAdd, JSValue initialValue)
 {
     ConcurrentJITLocker locker(m_lock);
     
@@ -54,7 +54,7 @@ ScopeOffset JSSegmentedVariableObject::addVariables(unsigned numberOfVariablesTo
     m_variables.grow(oldSize + numberOfVariablesToAdd);
     
     for (size_t i = numberOfVariablesToAdd; i--;)
-        m_variables[oldSize + i].setWithoutWriteBarrier(jsUndefined());
+        m_variables[oldSize + i].setWithoutWriteBarrier(initialValue);
     
     return ScopeOffset(oldSize);
 }
index feaf0bb..d8f614a 100644 (file)
@@ -77,7 +77,7 @@ public:
     
     // Adds numberOfRegistersToAdd registers, initializes them to Undefined, and returns
     // the index of the first one added.
-    JS_EXPORT_PRIVATE ScopeOffset addVariables(unsigned numberOfVariablesToAdd);
+    JS_EXPORT_PRIVATE ScopeOffset addVariables(unsigned numberOfVariablesToAdd, JSValue);
     
     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
 
index 9fe8384..77bd8f0 100644 (file)
@@ -127,7 +127,7 @@ inline bool symbolTableGet(
 template<typename SymbolTableObjectType>
 inline bool symbolTablePut(
     SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value,
-    bool shouldThrow)
+    bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors)
 {
     VM& vm = exec->vm();
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
@@ -145,8 +145,8 @@ inline bool symbolTablePut(
         bool wasFat;
         SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat);
         ASSERT(!fastEntry.isNull());
-        if (fastEntry.isReadOnly()) {
-            if (shouldThrow)
+        if (fastEntry.isReadOnly() && !ignoreReadOnlyErrors) {
+            if (shouldThrowReadOnlyError)
                 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
             return true;
         }
index 110f8b5..60d5826 100644 (file)
@@ -75,12 +75,10 @@ enum JSType : uint8_t {
     Float64ArrayType,
     DataViewType,
 
-    NameScopeObjectType,
-
     GlobalObjectType,
-    ActivationObjectType,
+    ClosureObjectType,
 
-    LastJSCObjectType = ActivationObjectType,
+    LastJSCObjectType = ClosureObjectType,
 };
 
 COMPILE_ASSERT(sizeof(JSType) == sizeof(uint8_t), sizeof_jstype_is_one_byte);
index d105ac6..a79745c 100644 (file)
@@ -1,6 +1,5 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,12 +42,13 @@ public:
     enum Context { UnknownContext, PutById, PutByIdEval };
     typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
 
-    PutPropertySlot(JSValue thisValue, bool isStrictMode = false, Context context = UnknownContext)
+    PutPropertySlot(JSValue thisValue, bool isStrictMode = false, Context context = UnknownContext, bool isInitialization = false)
         : m_type(Uncachable)
         , m_base(0)
         , m_thisValue(thisValue)
         , m_offset(invalidOffset)
         , m_isStrictMode(isStrictMode)
+        , m_isInitialization(isInitialization)
         , m_context(context)
         , m_putFunction(nullptr)
     {
@@ -99,6 +99,7 @@ public:
     bool isCacheablePut() const { return m_type == NewProperty || m_type == ExistingProperty; }
     bool isCacheableSetter() const { return m_type == SetterProperty; }
     bool isCacheableCustom() const { return m_type == CustomProperty; }
+    bool isInitialization() const { return m_isInitialization; }
 
     PropertyOffset cachedOffset() const
     {
@@ -111,6 +112,7 @@ private:
     JSValue m_thisValue;
     PropertyOffset m_offset;
     bool m_isStrictMode;
+    bool m_isInitialization;
     uint8_t m_context;
     PutValueFunc m_putFunction;
 };
index 990039c..0996058 100644 (file)
@@ -651,6 +651,7 @@ public:
 
     enum ScopeType {
         VarScope,
+        GlobalLexicalScope,
         LexicalScope,
         CatchScope,
         FunctionNameScope
@@ -685,7 +686,7 @@ private:
     std::unique_ptr<TypeProfilingRareData> m_typeProfilingRareData;
 
     bool m_usesNonStrictEval : 1;
-    unsigned m_scopeType : 2; // ScopeType
+    unsigned m_scopeType : 3; // ScopeType
     
     WriteBarrier<ScopedArgumentsTable> m_arguments;
     WriteBarrier<InferredValue> m_singletonScope;
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-let-no-rhs.js b/Source/JavaScriptCore/tests/stress/global-lexical-let-no-rhs.js
new file mode 100644 (file)
index 0000000..cd77889
--- /dev/null
@@ -0,0 +1,14 @@
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+
+let x;
+function foo() {
+    return x;
+}
+for (var i = 0; i < 1000; i++) {
+    assert(x === undefined);
+    assert(foo() === undefined);
+}
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-redeclare-variable.js b/Source/JavaScriptCore/tests/stress/global-lexical-redeclare-variable.js
new file mode 100644 (file)
index 0000000..4689a8f
--- /dev/null
@@ -0,0 +1,74 @@
+let globalLet = "let";
+function globalFunction() { }
+class globalClass { }
+const globalConst = 20;
+var globalVar = 21;
+this.globalProperty = 22;
+
+let sentinel = "__s__";
+
+function assert(b) {
+    if (!b)
+        throw new Error("bad assertion");
+}
+
+function assertExpectations() {
+    assert(sentinel === "__s__");
+}
+
+
+let errorCount = 0;
+function assertProperError(e) {
+    if (e instanceof SyntaxError && e.message.indexOf("Can't create duplicate variable") !== -1) {
+        errorCount++;
+    } else {
+        assert(false);
+    }
+
+}
+
+assertExpectations();
+
+try {
+    load("./multiple-files-tests/global-lexical-redeclare-variable/first.js");
+} catch(e) {
+    assertProperError(e);
+}
+assertExpectations();
+
+try {
+    load("./multiple-files-tests/global-lexical-redeclare-variable/second.js");
+} catch(e) {
+    assertProperError(e);
+}
+assertExpectations();
+
+try {
+    load("./multiple-files-tests/global-lexical-redeclare-variable/third.js");
+} catch(e) {
+    assertProperError(e);
+}
+assertExpectations();
+
+try {
+    load("./multiple-files-tests/global-lexical-redeclare-variable/fourth.js");
+} catch(e) {
+    assertProperError(e);
+}
+assertExpectations();
+
+try {
+    load("./multiple-files-tests/global-lexical-redeclare-variable/fifth.js");
+} catch(e) {
+    assertProperError(e);
+}
+assertExpectations();
+
+try {
+    load("./multiple-files-tests/global-lexical-redeclare-variable/sixth.js");
+} catch(e) {
+    assertProperError(e);
+}
+assertExpectations();
+
+assert(errorCount === 6);
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-redefine-const.js b/Source/JavaScriptCore/tests/stress/global-lexical-redefine-const.js
new file mode 100644 (file)
index 0000000..1c6baf7
--- /dev/null
@@ -0,0 +1,2 @@
+load("./multiple-files-tests/global-lexical-redefine-const/first.js");
+load("./multiple-files-tests/global-lexical-redefine-const/second.js");
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-var-injection.js b/Source/JavaScriptCore/tests/stress/global-lexical-var-injection.js
new file mode 100644 (file)
index 0000000..662eb46
--- /dev/null
@@ -0,0 +1,57 @@
+function assert(cond) {
+    if (!cond)
+        throw new Error("broke assertion");
+}
+noInline(assert);
+
+let foo = "foo";
+const bar = "bar";
+
+for (let i = 0; i < 1000; i++) {
+    assert(foo === "foo");
+    assert(bar === "bar");
+}
+
+eval("var INJECTION = 20");
+
+for (let i = 0; i < 100; i++) {
+    assert(foo === "foo");
+    assert(bar === "bar");
+    assert(INJECTION === 20);
+    let threw = false;
+    try {
+        eval("var foo;");
+    } catch(e) {
+        threw = true;
+        assert(e.message.indexOf("Can't create duplicate global variable in eval") !== -1);
+    }
+    assert(threw);
+    threw = false;
+    try {
+        eval("var bar;");
+    } catch(e) {
+        threw = true;
+        assert(e.message.indexOf("Can't create duplicate global variable in eval") !== -1);
+    }
+    assert(threw);
+
+    assert(foo === "foo");
+    assert(bar === "bar");
+    assert(INJECTION === 20);
+}
+
+
+var flag = false;
+function baz() {
+    if (flag) eval("var foo = 20;");
+    return foo;
+}
+
+for (var i = 0; i < 1000; i++) {
+    assert(baz() === "foo");
+    assert(baz() === foo);
+}
+flag = true;
+for (var i = 0; i < 1000; i++) {
+    assert(baz() === 20);
+}
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-variable-tdz.js b/Source/JavaScriptCore/tests/stress/global-lexical-variable-tdz.js
new file mode 100644 (file)
index 0000000..e88cfd6
--- /dev/null
@@ -0,0 +1,2 @@
+load("./multiple-files-tests/global-lexical-variable-tdz/first.js");
+load("./multiple-files-tests/global-lexical-variable-tdz/second.js");
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-variable-unresolved-property.js b/Source/JavaScriptCore/tests/stress/global-lexical-variable-unresolved-property.js
new file mode 100644 (file)
index 0000000..d622145
--- /dev/null
@@ -0,0 +1,2 @@
+load("./multiple-files-tests/global-lexical-variable-unresolved-property/first.js");
+load("./multiple-files-tests/global-lexical-variable-unresolved-property/second.js");
diff --git a/Source/JavaScriptCore/tests/stress/global-lexical-variable-with-statement.js b/Source/JavaScriptCore/tests/stress/global-lexical-variable-with-statement.js
new file mode 100644 (file)
index 0000000..aab0b65
--- /dev/null
@@ -0,0 +1,33 @@
+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);
+
+
+function makeObj() {
+    return {foo: 20};
+}
+noInline(makeObj);
+
+let foo = "foo";
+const bar = "bar"; 
+
+for (var i = 0; i < 100; i++) {
+    with (makeObj()) {
+        assert(foo === 20);
+        assert(bar === "bar");
+        shouldThrowInvalidConstAssignment(function() { bar = 20; });
+    }
+}
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fifth.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fifth.js
new file mode 100644 (file)
index 0000000..dfa947d
--- /dev/null
@@ -0,0 +1,2 @@
+let globalVar = "bad";
+sentinel = "bad";
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/first.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/first.js
new file mode 100644 (file)
index 0000000..511fdc5
--- /dev/null
@@ -0,0 +1,2 @@
+let globalLet = "bad";
+sentinel = "bad";
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fourth.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/fourth.js
new file mode 100644 (file)
index 0000000..2b0d3ac
--- /dev/null
@@ -0,0 +1,2 @@
+let globalConst = "bad";
+sentinel = "bad";
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/second.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/second.js
new file mode 100644 (file)
index 0000000..6eb8092
--- /dev/null
@@ -0,0 +1,2 @@
+let globalFunction = "bad";
+sentinel = "bad";
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/sixth.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/sixth.js
new file mode 100644 (file)
index 0000000..f8ae3ca
--- /dev/null
@@ -0,0 +1,2 @@
+let globalProperty = "bad";
+sentinel = "bad";
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/third.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redeclare-variable/third.js
new file mode 100644 (file)
index 0000000..3292e52
--- /dev/null
@@ -0,0 +1,2 @@
+let globalClass = "bad";
+sentinel = "bad";
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redefine-const/first.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redefine-const/first.js
new file mode 100644 (file)
index 0000000..55e076a
--- /dev/null
@@ -0,0 +1,21 @@
+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);
+
+
+const constValue = "const";
+const {a: destructureObj} = {a: 20};
+const [destructureArr] = [40];
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redefine-const/second.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-redefine-const/second.js
new file mode 100644 (file)
index 0000000..12337fe
--- /dev/null
@@ -0,0 +1,22 @@
+function foo() {
+    constValue = 20;
+}
+
+function bar() {
+    destructureObj = 100;
+}
+
+function baz() {
+    destructureArr = 100;
+}
+
+for (var i = 0; i < 1000; i++) {
+    shouldThrowInvalidConstAssignment(foo);
+    assert(constValue === "const");
+
+    shouldThrowInvalidConstAssignment(bar);
+    assert(destructureObj === 20);
+
+    shouldThrowInvalidConstAssignment(baz);
+    assert(destructureArr === 40);
+}
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-tdz/first.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-tdz/first.js
new file mode 100644 (file)
index 0000000..2e1c3d2
--- /dev/null
@@ -0,0 +1,29 @@
+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);
+
+
+
+
+function foo() {
+    return lexicalVariableNotYetDefined;
+}
+
+function bar() {
+    lexicalVariableNotYetDefinedSecond = 300;
+    return lexicalVariableNotYetDefinedSecond;
+}
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-tdz/second.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-tdz/second.js
new file mode 100644 (file)
index 0000000..81dcedc
--- /dev/null
@@ -0,0 +1,12 @@
+
+for (var i = 0; i < 1000; i++)
+    shouldThrowTDZ(foo);
+
+let lexicalVariableNotYetDefined = 100;
+assert(foo() === lexicalVariableNotYetDefined);
+
+
+for (var i = 0; i < 1000; i++)
+    shouldThrowTDZ(bar);
+let lexicalVariableNotYetDefinedSecond = 200;
+assert(bar() === 300);
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/first.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/first.js
new file mode 100644 (file)
index 0000000..2a73148
--- /dev/null
@@ -0,0 +1,25 @@
+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);
+
+
+let b = false;
+function foo() {
+    if (b)
+        return x;
+}
+foo(); // Link as UnresolvedProperty.
diff --git a/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/second.js b/Source/JavaScriptCore/tests/stress/multiple-files-tests/global-lexical-variable-unresolved-property/second.js
new file mode 100644 (file)
index 0000000..f234b85
--- /dev/null
@@ -0,0 +1,14 @@
+b = true;
+let x = "x";
+for (var i = 0; i < 1000; i++) {
+    assert(foo() === "x");
+    assert(x === "x");
+}
+
+x = 20;
+x = 40;
+for (var i = 0; i < 1000; i++) {
+    assert(foo() === 40);
+    assert(x === 40);
+}
+