Title: [240072] branches/safari-607-branch
Revision
240072
Author
alanc...@apple.com
Date
2019-01-16 15:27:52 -0800 (Wed, 16 Jan 2019)

Log Message

Cherry-pick r239879. rdar://problem/47260206

    [JSC] Global lexical bindings can shadow global variables if it is `configurable = true`
    https://bugs.webkit.org/show_bug.cgi?id=193308
    <rdar://problem/45546542>

    Reviewed by Saam Barati.

    JSTests:

    * stress/const-lexical-binding-shadow-existing-global-property-ftl.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    (get shouldThrow):
    * stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    (get shouldBe):
    (get shouldThrow):
    (get return):
    * stress/const-lexical-binding-shadow-existing-global-property-tdz.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    (get shouldBe):
    (get shouldThrow):
    * stress/const-lexical-binding-shadow-existing-global-property.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    * stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    * stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js: Added.
    (shouldThrow):
    * stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js: Added.
    (shouldThrow):
    * stress/let-lexical-binding-shadow-existing-global-property-ftl.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    * stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    (get shouldBe):
    (get shouldThrow):
    (get return):
    * stress/let-lexical-binding-shadow-existing-global-property-tdz.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    (get shouldBe):
    (get shouldThrow):
    * stress/let-lexical-binding-shadow-existing-global-property.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):
    * stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
    (shouldThrow):
    (shouldBe):
    (foo):

    Source/_javascript_Core:

    Previously, we assumed that lexical bindings in JSGlobalLexicalEnvironment cannot shadow existing global properties.
    However, it is wrong. According to the spec, we can shadow global properties if a property's attribute is configurable = true.
    For example, we execute two scripts.

    script1.js

        bar = 42;
        function load() { return bar; }
        print(bar); // 42
        print(load()); // 42

    script2.js

        let bar = 0; // This lexical binding can shadow the global.bar defined in script1.js
        print(bar); // 0
        print(load()); // 0

    In JSC, we cache GlobalProperty resolve type and its associated information in op_resolve_type, op_get_from_scope, and op_put_to_scope.
    They attempt to load a property from JSGlobalObject directly. However, once the newly added lexical binding starts shadowing this, our existing instructions
    become invalid since they do not respect JSGlobalLexicalEnvironment.

    In this patch, we fix this issue by introducing the following mechanisms.

    1. We have a HashMap<property name, watchpoint set> in JSGlobalObject. DFG and FTL create a watchpoint set with the property name if the generated code
    depends on GlobalProperty condition of op_resolve_scope etc. These watchpoint will be fired when the shadowing happens, so that our generated DFG and FTL
    code will be invalidated if it depends on the condition which is no longer valid.

    2. When we detect shadowing, we iterate all the live CodeBlocks which globalObject is the target one. And we rewrite instructions in them from GlobalProperty
    to GlobalLexicalVar (or Dynamic precisely). So, the subsequent LLInt code just works well. "Dynamic" conversion happens when your op_put_to_scope attempts to
    put a value onto a const lexical binding. This fails and it should throw a type error.

    3. GlobalProperty scope operations in Baseline JIT start checking ResolveType in metadata, and emit code for GlobalProperty and GlobalLexicalVar. Once the rewrite
    happens, baseline JIT continues working because it checks the rewritten metadata's ResolveType.

    We use this mechanism (which is similar to haveABadTime() thing) because,

    1. Shadowing should be super rare. Before r214145, we made these cases as SytaxError. Thus, before r214145, this type of code cannot be executed in WebKit.
    And the number of the live CodeBlocks for the given JSGlobalObject should be small. This supports introducing rather simple (but not so efficient) mechanism
    instead of the complicated one.

    2. Rewriting instructions immediately forces GlobalProperty => GlobalLexicalVar / Dynamic conversion in all the possible CodeBlock. This allows us to avoid
    compilation failure loop in DFG and FTL: DFG and FTL codes are invalidated by the watchpoint, but we may attempt to compile the code with the invalidated watchpoint
    and GlobalProperty status if we do not rewrite it. One possible other implementation is having and checking a counter in instruction, and every time we introduce
    a new shadow binding, bump the counter. And eventually executed instruction will go to the slow path and rewrite itself. However, this way leaves the not-executed-again-yet
    instructions as is, and DFG and FTL repeatedly fail to compile if we just watch the invalidated watchpoint for that. Rewriting all the existing GlobalProperty immediately
    avoids this situation easily.

    * _javascript_Core.xcodeproj/project.pbxproj:
    * Sources.txt:
    * bytecode/CodeBlock.cpp:
    (JSC::CodeBlock::notifyLexicalBindingShadowing):
    * bytecode/CodeBlock.h:
    (JSC::CodeBlock::scriptMode const):
    * bytecode/Watchpoint.h:
    (JSC::WatchpointSet::create):
    * dfg/DFGByteCodeParser.cpp:
    (JSC::DFG::ByteCodeParser::parseBlock):
    * dfg/DFGDesiredGlobalProperties.cpp: Added.
    (JSC::DFG::DesiredGlobalProperties::isStillValidOnMainThread):
    (JSC::DFG::DesiredGlobalProperties::reallyAdd):
    * dfg/DFGDesiredGlobalProperties.h: Added.
    (JSC::DFG::DesiredGlobalProperties::addLazily):
    We need this DesiredGlobalProperties mechanism since we do not want to ref() the UniquedStringImpl in DFG and FTL thread.
    We keep JSGlobalObject* and identifierNumber, and materialize WatchpointSets for each JSGlobalObject's property referenced
    from DFG and FTL and inject CodeBlock jettison watchpoints in the main thread.
    * dfg/DFGDesiredGlobalProperty.h: Added.
    (JSC::DFG::DesiredGlobalProperty::DesiredGlobalProperty):
    (JSC::DFG::DesiredGlobalProperty::globalObject const):
    (JSC::DFG::DesiredGlobalProperty::identifierNumber const):
    (JSC::DFG::DesiredGlobalProperty::operator== const):
    (JSC::DFG::DesiredGlobalProperty::operator!= const):
    (JSC::DFG::DesiredGlobalProperty::isHashTableDeletedValue const):
    (JSC::DFG::DesiredGlobalProperty::hash const):
    (JSC::DFG::DesiredGlobalProperty::dumpInContext const):
    (JSC::DFG::DesiredGlobalProperty::dump const):
    (JSC::DFG::DesiredGlobalPropertyHash::hash):
    (JSC::DFG::DesiredGlobalPropertyHash::equal):
    * dfg/DFGGraph.h:
    (JSC::DFG::Graph::globalProperties):
    * dfg/DFGPlan.cpp:
    (JSC::DFG::Plan::reallyAdd):
    (JSC::DFG::Plan::isStillValidOnMainThread):
    (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
    (JSC::DFG::Plan::cancel):
    * dfg/DFGPlan.h:
    (JSC::DFG::Plan::globalProperties):
    * jit/JITPropertyAccess.cpp:
    (JSC::JIT::emit_op_resolve_scope):
    (JSC::JIT::emit_op_get_from_scope):
    (JSC::JIT::emit_op_put_to_scope):
    * jit/JITPropertyAccess32_64.cpp:
    (JSC::JIT::emit_op_resolve_scope):
    (JSC::JIT::emit_op_get_from_scope):
    (JSC::JIT::emit_op_put_to_scope):
    * runtime/JSGlobalObject.cpp:
    (JSC::JSGlobalObject::addStaticGlobals):
    (JSC::JSGlobalObject::notifyLexicalBindingShadowing):
    (JSC::JSGlobalObject::getReferencedPropertyWatchpointSet):
    (JSC::JSGlobalObject::ensureReferencedPropertyWatchpointSet):
    * runtime/JSGlobalObject.h:
    * runtime/ProgramExecutable.cpp:
    (JSC::hasRestrictedGlobalProperty):
    (JSC::ProgramExecutable::initializeGlobalProperties):

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

Modified Paths

Added Paths

Diff

Modified: branches/safari-607-branch/JSTests/ChangeLog (240071 => 240072)


--- branches/safari-607-branch/JSTests/ChangeLog	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/JSTests/ChangeLog	2019-01-16 23:27:52 UTC (rev 240072)
@@ -1,3 +1,243 @@
+2019-01-15  Alan Coon  <alanc...@apple.com>
+
+        Cherry-pick r239879. rdar://problem/47260206
+
+    [JSC] Global lexical bindings can shadow global variables if it is `configurable = true`
+    https://bugs.webkit.org/show_bug.cgi?id=193308
+    <rdar://problem/45546542>
+    
+    Reviewed by Saam Barati.
+    
+    JSTests:
+    
+    * stress/const-lexical-binding-shadow-existing-global-property-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldThrow):
+    * stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    (get return):
+    * stress/const-lexical-binding-shadow-existing-global-property-tdz.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    * stress/const-lexical-binding-shadow-existing-global-property.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js: Added.
+    (shouldThrow):
+    * stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js: Added.
+    (shouldThrow):
+    * stress/let-lexical-binding-shadow-existing-global-property-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    (get return):
+    * stress/let-lexical-binding-shadow-existing-global-property-tdz.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    * stress/let-lexical-binding-shadow-existing-global-property.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    
+    Source/_javascript_Core:
+    
+    Previously, we assumed that lexical bindings in JSGlobalLexicalEnvironment cannot shadow existing global properties.
+    However, it is wrong. According to the spec, we can shadow global properties if a property's attribute is configurable = true.
+    For example, we execute two scripts.
+    
+    script1.js
+    
+        bar = 42;
+        function load() { return bar; }
+        print(bar); // 42
+        print(load()); // 42
+    
+    script2.js
+    
+        let bar = 0; // This lexical binding can shadow the global.bar defined in script1.js
+        print(bar); // 0
+        print(load()); // 0
+    
+    In JSC, we cache GlobalProperty resolve type and its associated information in op_resolve_type, op_get_from_scope, and op_put_to_scope.
+    They attempt to load a property from JSGlobalObject directly. However, once the newly added lexical binding starts shadowing this, our existing instructions
+    become invalid since they do not respect JSGlobalLexicalEnvironment.
+    
+    In this patch, we fix this issue by introducing the following mechanisms.
+    
+    1. We have a HashMap<property name, watchpoint set> in JSGlobalObject. DFG and FTL create a watchpoint set with the property name if the generated code
+    depends on GlobalProperty condition of op_resolve_scope etc. These watchpoint will be fired when the shadowing happens, so that our generated DFG and FTL
+    code will be invalidated if it depends on the condition which is no longer valid.
+    
+    2. When we detect shadowing, we iterate all the live CodeBlocks which globalObject is the target one. And we rewrite instructions in them from GlobalProperty
+    to GlobalLexicalVar (or Dynamic precisely). So, the subsequent LLInt code just works well. "Dynamic" conversion happens when your op_put_to_scope attempts to
+    put a value onto a const lexical binding. This fails and it should throw a type error.
+    
+    3. GlobalProperty scope operations in Baseline JIT start checking ResolveType in metadata, and emit code for GlobalProperty and GlobalLexicalVar. Once the rewrite
+    happens, baseline JIT continues working because it checks the rewritten metadata's ResolveType.
+    
+    We use this mechanism (which is similar to haveABadTime() thing) because,
+    
+    1. Shadowing should be super rare. Before r214145, we made these cases as SytaxError. Thus, before r214145, this type of code cannot be executed in WebKit.
+    And the number of the live CodeBlocks for the given JSGlobalObject should be small. This supports introducing rather simple (but not so efficient) mechanism
+    instead of the complicated one.
+    
+    2. Rewriting instructions immediately forces GlobalProperty => GlobalLexicalVar / Dynamic conversion in all the possible CodeBlock. This allows us to avoid
+    compilation failure loop in DFG and FTL: DFG and FTL codes are invalidated by the watchpoint, but we may attempt to compile the code with the invalidated watchpoint
+    and GlobalProperty status if we do not rewrite it. One possible other implementation is having and checking a counter in instruction, and every time we introduce
+    a new shadow binding, bump the counter. And eventually executed instruction will go to the slow path and rewrite itself. However, this way leaves the not-executed-again-yet
+    instructions as is, and DFG and FTL repeatedly fail to compile if we just watch the invalidated watchpoint for that. Rewriting all the existing GlobalProperty immediately
+    avoids this situation easily.
+    
+    * _javascript_Core.xcodeproj/project.pbxproj:
+    * Sources.txt:
+    * bytecode/CodeBlock.cpp:
+    (JSC::CodeBlock::notifyLexicalBindingShadowing):
+    * bytecode/CodeBlock.h:
+    (JSC::CodeBlock::scriptMode const):
+    * bytecode/Watchpoint.h:
+    (JSC::WatchpointSet::create):
+    * dfg/DFGByteCodeParser.cpp:
+    (JSC::DFG::ByteCodeParser::parseBlock):
+    * dfg/DFGDesiredGlobalProperties.cpp: Added.
+    (JSC::DFG::DesiredGlobalProperties::isStillValidOnMainThread):
+    (JSC::DFG::DesiredGlobalProperties::reallyAdd):
+    * dfg/DFGDesiredGlobalProperties.h: Added.
+    (JSC::DFG::DesiredGlobalProperties::addLazily):
+    We need this DesiredGlobalProperties mechanism since we do not want to ref() the UniquedStringImpl in DFG and FTL thread.
+    We keep JSGlobalObject* and identifierNumber, and materialize WatchpointSets for each JSGlobalObject's property referenced
+    from DFG and FTL and inject CodeBlock jettison watchpoints in the main thread.
+    * dfg/DFGDesiredGlobalProperty.h: Added.
+    (JSC::DFG::DesiredGlobalProperty::DesiredGlobalProperty):
+    (JSC::DFG::DesiredGlobalProperty::globalObject const):
+    (JSC::DFG::DesiredGlobalProperty::identifierNumber const):
+    (JSC::DFG::DesiredGlobalProperty::operator== const):
+    (JSC::DFG::DesiredGlobalProperty::operator!= const):
+    (JSC::DFG::DesiredGlobalProperty::isHashTableDeletedValue const):
+    (JSC::DFG::DesiredGlobalProperty::hash const):
+    (JSC::DFG::DesiredGlobalProperty::dumpInContext const):
+    (JSC::DFG::DesiredGlobalProperty::dump const):
+    (JSC::DFG::DesiredGlobalPropertyHash::hash):
+    (JSC::DFG::DesiredGlobalPropertyHash::equal):
+    * dfg/DFGGraph.h:
+    (JSC::DFG::Graph::globalProperties):
+    * dfg/DFGPlan.cpp:
+    (JSC::DFG::Plan::reallyAdd):
+    (JSC::DFG::Plan::isStillValidOnMainThread):
+    (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
+    (JSC::DFG::Plan::cancel):
+    * dfg/DFGPlan.h:
+    (JSC::DFG::Plan::globalProperties):
+    * jit/JITPropertyAccess.cpp:
+    (JSC::JIT::emit_op_resolve_scope):
+    (JSC::JIT::emit_op_get_from_scope):
+    (JSC::JIT::emit_op_put_to_scope):
+    * jit/JITPropertyAccess32_64.cpp:
+    (JSC::JIT::emit_op_resolve_scope):
+    (JSC::JIT::emit_op_get_from_scope):
+    (JSC::JIT::emit_op_put_to_scope):
+    * runtime/JSGlobalObject.cpp:
+    (JSC::JSGlobalObject::addStaticGlobals):
+    (JSC::JSGlobalObject::notifyLexicalBindingShadowing):
+    (JSC::JSGlobalObject::getReferencedPropertyWatchpointSet):
+    (JSC::JSGlobalObject::ensureReferencedPropertyWatchpointSet):
+    * runtime/JSGlobalObject.h:
+    * runtime/ProgramExecutable.cpp:
+    (JSC::hasRestrictedGlobalProperty):
+    (JSC::ProgramExecutable::initializeGlobalProperties):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@239879 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-01-11  Yusuke Suzuki  <yusukesuz...@slowstart.org>
+
+            [JSC] Global lexical bindings can shadow global variables if it is `configurable = true`
+            https://bugs.webkit.org/show_bug.cgi?id=193308
+            <rdar://problem/45546542>
+
+            Reviewed by Saam Barati.
+
+            * stress/const-lexical-binding-shadow-existing-global-property-ftl.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            (get shouldThrow):
+            * stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            (get shouldBe):
+            (get shouldThrow):
+            (get return):
+            * stress/const-lexical-binding-shadow-existing-global-property-tdz.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            (get shouldBe):
+            (get shouldThrow):
+            * stress/const-lexical-binding-shadow-existing-global-property.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            * stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            * stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js: Added.
+            (shouldThrow):
+            * stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js: Added.
+            (shouldThrow):
+            * stress/let-lexical-binding-shadow-existing-global-property-ftl.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            * stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            (get shouldBe):
+            (get shouldThrow):
+            (get return):
+            * stress/let-lexical-binding-shadow-existing-global-property-tdz.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            (get shouldBe):
+            (get shouldThrow):
+            * stress/let-lexical-binding-shadow-existing-global-property.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+            * stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
+            (shouldThrow):
+            (shouldBe):
+            (foo):
+
 2019-01-09  Kocsen Chung  <kocsen_ch...@apple.com>
 
         Cherry-pick r239731. rdar://problem/47158715

Added: branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-ftl.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-ftl.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-ftl.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,49 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+function get() {
+    return bar;
+}
+for (var i = 0; i < 1e6; ++i)
+    foo();
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 4);
+
+shouldBe(bar, 4);
+$.evalScript('const bar = 3;');
+shouldBe(bar, 3);
+shouldBe(get(), 3);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 3);
+
+shouldThrow(() => {
+    foo();
+}, `TypeError: Attempted to assign to readonly property.`);
+shouldBe(bar, 3);
+shouldBe(get(), 3);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 3);

Added: branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,53 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+function get() {
+    return bar;
+}
+for (var i = 0; i < 1e6; ++i)
+    foo();
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 4);
+
+shouldBe(bar, 4);
+shouldThrow(() => {
+    $.evalScript('get(); const bar = 3;');
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(bar, 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(get(), 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    $.evalScript('bar;');
+}, `ReferenceError: Cannot access uninitialized variable.`);
+
+for (var i = 0; i < 1e3; ++i) {
+    shouldThrow(() => {
+        shouldBe(get(), 3);
+    }, `ReferenceError: Cannot access uninitialized variable.`);
+}
+

Added: branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-tdz.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-tdz.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property-tdz.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,44 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+function get() {
+    return bar;
+}
+foo();
+shouldBe(get(), 4);
+
+shouldBe(bar, 4);
+shouldThrow(() => {
+    $.evalScript('get(); const bar = 3;');
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(bar, 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(get(), 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    $.evalScript('bar;');
+}, `ReferenceError: Cannot access uninitialized variable.`);

Added: branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadow-existing-global-property.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,33 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+foo();
+shouldBe(bar, 4);
+$.evalScript('const bar = 3;');
+shouldBe(bar, 3);
+shouldThrow(() => {
+    foo();
+}, `TypeError: Attempted to assign to readonly property.`);
+shouldBe(bar, 3);

Added: branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,36 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+bar = 0;
+function foo(code) {
+    eval(code);
+    return (function () {
+        return bar;
+    }());
+}
+shouldBe(foo(`42`), 0);
+
+$.evalScript(`const bar = 42`);
+shouldBe(foo(`42`), 42);
+
+shouldBe(foo(`var bar = 1`), 1);
+shouldBe(foo(`42`), 42);

Added: branches/safari-607-branch/JSTests/stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,18 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+shouldThrow(() => {
+    $.evalScript(`const shouldThrow = 42`);
+}, `SyntaxError: Can't create duplicate variable that shadows a global property: 'shouldThrow'`);

Added: branches/safari-607-branch/JSTests/stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,18 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+shouldThrow(() => {
+    $.evalScript(`const NaN = 42`);
+}, `SyntaxError: Can't create duplicate variable that shadows a global property: 'NaN'`);

Added: branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-ftl.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-ftl.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-ftl.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,47 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+function get() {
+    return bar;
+}
+for (var i = 0; i < 1e6; ++i)
+    foo();
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 4);
+
+shouldBe(bar, 4);
+$.evalScript('let bar = 3;');
+shouldBe(bar, 3);
+shouldBe(get(), 3);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 3);
+
+foo();
+shouldBe(bar, 4);
+shouldBe(get(), 4);
+
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 4);

Added: branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,53 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+function get() {
+    return bar;
+}
+for (var i = 0; i < 1e6; ++i)
+    foo();
+for (var i = 0; i < 1e6; ++i)
+    shouldBe(get(), 4);
+
+shouldBe(bar, 4);
+shouldThrow(() => {
+    $.evalScript('get(); let bar = 3;');
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(bar, 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(get(), 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    $.evalScript('bar;');
+}, `ReferenceError: Cannot access uninitialized variable.`);
+
+for (var i = 0; i < 1e3; ++i) {
+    shouldThrow(() => {
+        shouldBe(get(), 3);
+    }, `ReferenceError: Cannot access uninitialized variable.`);
+}
+

Added: branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-tdz.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-tdz.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property-tdz.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,44 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+function get() {
+    return bar;
+}
+foo();
+shouldBe(get(), 4);
+
+shouldBe(bar, 4);
+shouldThrow(() => {
+    $.evalScript('get(); let bar = 3;');
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(bar, 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    shouldBe(get(), 3);
+}, `ReferenceError: Cannot access uninitialized variable.`);
+shouldThrow(() => {
+    $.evalScript('bar;');
+}, `ReferenceError: Cannot access uninitialized variable.`);

Added: branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadow-existing-global-property.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,31 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+function foo() {
+    bar = 4;
+}
+foo();
+shouldBe(bar, 4);
+$.evalScript('let bar = 3;');
+shouldBe(bar, 3);
+foo();
+shouldBe(bar, 4);

Added: branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js (0 => 240072)


--- branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js	                        (rev 0)
+++ branches/safari-607-branch/JSTests/stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,36 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+noInline(shouldThrow);
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+noInline(shouldBe);
+
+bar = 0;
+function foo(code) {
+    eval(code);
+    return (function () {
+        return bar;
+    }());
+}
+shouldBe(foo(`42`), 0);
+
+$.evalScript(`let bar = 42`);
+shouldBe(foo(`42`), 42);
+
+shouldBe(foo(`var bar = 1`), 1);
+shouldBe(foo(`42`), 42);

Modified: branches/safari-607-branch/Source/_javascript_Core/ChangeLog (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/ChangeLog	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/ChangeLog	2019-01-16 23:27:52 UTC (rev 240072)
@@ -1,5 +1,293 @@
 2019-01-15  Alan Coon  <alanc...@apple.com>
 
+        Cherry-pick r239879. rdar://problem/47260206
+
+    [JSC] Global lexical bindings can shadow global variables if it is `configurable = true`
+    https://bugs.webkit.org/show_bug.cgi?id=193308
+    <rdar://problem/45546542>
+    
+    Reviewed by Saam Barati.
+    
+    JSTests:
+    
+    * stress/const-lexical-binding-shadow-existing-global-property-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldThrow):
+    * stress/const-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    (get return):
+    * stress/const-lexical-binding-shadow-existing-global-property-tdz.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    * stress/const-lexical-binding-shadow-existing-global-property.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/const-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/global-add-function-should-not-be-shadowed-by-lexical-bindings.js: Added.
+    (shouldThrow):
+    * stress/global-static-variables-should-not-be-shadowed-by-lexical-bindings.js: Added.
+    (shouldThrow):
+    * stress/let-lexical-binding-shadow-existing-global-property-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/let-lexical-binding-shadow-existing-global-property-tdz-ftl.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    (get return):
+    * stress/let-lexical-binding-shadow-existing-global-property-tdz.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    (get shouldBe):
+    (get shouldThrow):
+    * stress/let-lexical-binding-shadow-existing-global-property.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    * stress/let-lexical-binding-shadowing-global-properties-and-eval-injection.js: Added.
+    (shouldThrow):
+    (shouldBe):
+    (foo):
+    
+    Source/_javascript_Core:
+    
+    Previously, we assumed that lexical bindings in JSGlobalLexicalEnvironment cannot shadow existing global properties.
+    However, it is wrong. According to the spec, we can shadow global properties if a property's attribute is configurable = true.
+    For example, we execute two scripts.
+    
+    script1.js
+    
+        bar = 42;
+        function load() { return bar; }
+        print(bar); // 42
+        print(load()); // 42
+    
+    script2.js
+    
+        let bar = 0; // This lexical binding can shadow the global.bar defined in script1.js
+        print(bar); // 0
+        print(load()); // 0
+    
+    In JSC, we cache GlobalProperty resolve type and its associated information in op_resolve_type, op_get_from_scope, and op_put_to_scope.
+    They attempt to load a property from JSGlobalObject directly. However, once the newly added lexical binding starts shadowing this, our existing instructions
+    become invalid since they do not respect JSGlobalLexicalEnvironment.
+    
+    In this patch, we fix this issue by introducing the following mechanisms.
+    
+    1. We have a HashMap<property name, watchpoint set> in JSGlobalObject. DFG and FTL create a watchpoint set with the property name if the generated code
+    depends on GlobalProperty condition of op_resolve_scope etc. These watchpoint will be fired when the shadowing happens, so that our generated DFG and FTL
+    code will be invalidated if it depends on the condition which is no longer valid.
+    
+    2. When we detect shadowing, we iterate all the live CodeBlocks which globalObject is the target one. And we rewrite instructions in them from GlobalProperty
+    to GlobalLexicalVar (or Dynamic precisely). So, the subsequent LLInt code just works well. "Dynamic" conversion happens when your op_put_to_scope attempts to
+    put a value onto a const lexical binding. This fails and it should throw a type error.
+    
+    3. GlobalProperty scope operations in Baseline JIT start checking ResolveType in metadata, and emit code for GlobalProperty and GlobalLexicalVar. Once the rewrite
+    happens, baseline JIT continues working because it checks the rewritten metadata's ResolveType.
+    
+    We use this mechanism (which is similar to haveABadTime() thing) because,
+    
+    1. Shadowing should be super rare. Before r214145, we made these cases as SytaxError. Thus, before r214145, this type of code cannot be executed in WebKit.
+    And the number of the live CodeBlocks for the given JSGlobalObject should be small. This supports introducing rather simple (but not so efficient) mechanism
+    instead of the complicated one.
+    
+    2. Rewriting instructions immediately forces GlobalProperty => GlobalLexicalVar / Dynamic conversion in all the possible CodeBlock. This allows us to avoid
+    compilation failure loop in DFG and FTL: DFG and FTL codes are invalidated by the watchpoint, but we may attempt to compile the code with the invalidated watchpoint
+    and GlobalProperty status if we do not rewrite it. One possible other implementation is having and checking a counter in instruction, and every time we introduce
+    a new shadow binding, bump the counter. And eventually executed instruction will go to the slow path and rewrite itself. However, this way leaves the not-executed-again-yet
+    instructions as is, and DFG and FTL repeatedly fail to compile if we just watch the invalidated watchpoint for that. Rewriting all the existing GlobalProperty immediately
+    avoids this situation easily.
+    
+    * _javascript_Core.xcodeproj/project.pbxproj:
+    * Sources.txt:
+    * bytecode/CodeBlock.cpp:
+    (JSC::CodeBlock::notifyLexicalBindingShadowing):
+    * bytecode/CodeBlock.h:
+    (JSC::CodeBlock::scriptMode const):
+    * bytecode/Watchpoint.h:
+    (JSC::WatchpointSet::create):
+    * dfg/DFGByteCodeParser.cpp:
+    (JSC::DFG::ByteCodeParser::parseBlock):
+    * dfg/DFGDesiredGlobalProperties.cpp: Added.
+    (JSC::DFG::DesiredGlobalProperties::isStillValidOnMainThread):
+    (JSC::DFG::DesiredGlobalProperties::reallyAdd):
+    * dfg/DFGDesiredGlobalProperties.h: Added.
+    (JSC::DFG::DesiredGlobalProperties::addLazily):
+    We need this DesiredGlobalProperties mechanism since we do not want to ref() the UniquedStringImpl in DFG and FTL thread.
+    We keep JSGlobalObject* and identifierNumber, and materialize WatchpointSets for each JSGlobalObject's property referenced
+    from DFG and FTL and inject CodeBlock jettison watchpoints in the main thread.
+    * dfg/DFGDesiredGlobalProperty.h: Added.
+    (JSC::DFG::DesiredGlobalProperty::DesiredGlobalProperty):
+    (JSC::DFG::DesiredGlobalProperty::globalObject const):
+    (JSC::DFG::DesiredGlobalProperty::identifierNumber const):
+    (JSC::DFG::DesiredGlobalProperty::operator== const):
+    (JSC::DFG::DesiredGlobalProperty::operator!= const):
+    (JSC::DFG::DesiredGlobalProperty::isHashTableDeletedValue const):
+    (JSC::DFG::DesiredGlobalProperty::hash const):
+    (JSC::DFG::DesiredGlobalProperty::dumpInContext const):
+    (JSC::DFG::DesiredGlobalProperty::dump const):
+    (JSC::DFG::DesiredGlobalPropertyHash::hash):
+    (JSC::DFG::DesiredGlobalPropertyHash::equal):
+    * dfg/DFGGraph.h:
+    (JSC::DFG::Graph::globalProperties):
+    * dfg/DFGPlan.cpp:
+    (JSC::DFG::Plan::reallyAdd):
+    (JSC::DFG::Plan::isStillValidOnMainThread):
+    (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
+    (JSC::DFG::Plan::cancel):
+    * dfg/DFGPlan.h:
+    (JSC::DFG::Plan::globalProperties):
+    * jit/JITPropertyAccess.cpp:
+    (JSC::JIT::emit_op_resolve_scope):
+    (JSC::JIT::emit_op_get_from_scope):
+    (JSC::JIT::emit_op_put_to_scope):
+    * jit/JITPropertyAccess32_64.cpp:
+    (JSC::JIT::emit_op_resolve_scope):
+    (JSC::JIT::emit_op_get_from_scope):
+    (JSC::JIT::emit_op_put_to_scope):
+    * runtime/JSGlobalObject.cpp:
+    (JSC::JSGlobalObject::addStaticGlobals):
+    (JSC::JSGlobalObject::notifyLexicalBindingShadowing):
+    (JSC::JSGlobalObject::getReferencedPropertyWatchpointSet):
+    (JSC::JSGlobalObject::ensureReferencedPropertyWatchpointSet):
+    * runtime/JSGlobalObject.h:
+    * runtime/ProgramExecutable.cpp:
+    (JSC::hasRestrictedGlobalProperty):
+    (JSC::ProgramExecutable::initializeGlobalProperties):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@239879 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-01-11  Yusuke Suzuki  <yusukesuz...@slowstart.org>
+
+            [JSC] Global lexical bindings can shadow global variables if it is `configurable = true`
+            https://bugs.webkit.org/show_bug.cgi?id=193308
+            <rdar://problem/45546542>
+
+            Reviewed by Saam Barati.
+
+            Previously, we assumed that lexical bindings in JSGlobalLexicalEnvironment cannot shadow existing global properties.
+            However, it is wrong. According to the spec, we can shadow global properties if a property's attribute is configurable = true.
+            For example, we execute two scripts.
+
+            script1.js
+
+                bar = 42;
+                function load() { return bar; }
+                print(bar); // 42
+                print(load()); // 42
+
+            script2.js
+
+                let bar = 0; // This lexical binding can shadow the global.bar defined in script1.js
+                print(bar); // 0
+                print(load()); // 0
+
+            In JSC, we cache GlobalProperty resolve type and its associated information in op_resolve_type, op_get_from_scope, and op_put_to_scope.
+            They attempt to load a property from JSGlobalObject directly. However, once the newly added lexical binding starts shadowing this, our existing instructions
+            become invalid since they do not respect JSGlobalLexicalEnvironment.
+
+            In this patch, we fix this issue by introducing the following mechanisms.
+
+            1. We have a HashMap<property name, watchpoint set> in JSGlobalObject. DFG and FTL create a watchpoint set with the property name if the generated code
+            depends on GlobalProperty condition of op_resolve_scope etc. These watchpoint will be fired when the shadowing happens, so that our generated DFG and FTL
+            code will be invalidated if it depends on the condition which is no longer valid.
+
+            2. When we detect shadowing, we iterate all the live CodeBlocks which globalObject is the target one. And we rewrite instructions in them from GlobalProperty
+            to GlobalLexicalVar (or Dynamic precisely). So, the subsequent LLInt code just works well. "Dynamic" conversion happens when your op_put_to_scope attempts to
+            put a value onto a const lexical binding. This fails and it should throw a type error.
+
+            3. GlobalProperty scope operations in Baseline JIT start checking ResolveType in metadata, and emit code for GlobalProperty and GlobalLexicalVar. Once the rewrite
+            happens, baseline JIT continues working because it checks the rewritten metadata's ResolveType.
+
+            We use this mechanism (which is similar to haveABadTime() thing) because,
+
+            1. Shadowing should be super rare. Before r214145, we made these cases as SytaxError. Thus, before r214145, this type of code cannot be executed in WebKit.
+            And the number of the live CodeBlocks for the given JSGlobalObject should be small. This supports introducing rather simple (but not so efficient) mechanism
+            instead of the complicated one.
+
+            2. Rewriting instructions immediately forces GlobalProperty => GlobalLexicalVar / Dynamic conversion in all the possible CodeBlock. This allows us to avoid
+            compilation failure loop in DFG and FTL: DFG and FTL codes are invalidated by the watchpoint, but we may attempt to compile the code with the invalidated watchpoint
+            and GlobalProperty status if we do not rewrite it. One possible other implementation is having and checking a counter in instruction, and every time we introduce
+            a new shadow binding, bump the counter. And eventually executed instruction will go to the slow path and rewrite itself. However, this way leaves the not-executed-again-yet
+            instructions as is, and DFG and FTL repeatedly fail to compile if we just watch the invalidated watchpoint for that. Rewriting all the existing GlobalProperty immediately
+            avoids this situation easily.
+
+            * _javascript_Core.xcodeproj/project.pbxproj:
+            * Sources.txt:
+            * bytecode/CodeBlock.cpp:
+            (JSC::CodeBlock::notifyLexicalBindingShadowing):
+            * bytecode/CodeBlock.h:
+            (JSC::CodeBlock::scriptMode const):
+            * bytecode/Watchpoint.h:
+            (JSC::WatchpointSet::create):
+            * dfg/DFGByteCodeParser.cpp:
+            (JSC::DFG::ByteCodeParser::parseBlock):
+            * dfg/DFGDesiredGlobalProperties.cpp: Added.
+            (JSC::DFG::DesiredGlobalProperties::isStillValidOnMainThread):
+            (JSC::DFG::DesiredGlobalProperties::reallyAdd):
+            * dfg/DFGDesiredGlobalProperties.h: Added.
+            (JSC::DFG::DesiredGlobalProperties::addLazily):
+            We need this DesiredGlobalProperties mechanism since we do not want to ref() the UniquedStringImpl in DFG and FTL thread.
+            We keep JSGlobalObject* and identifierNumber, and materialize WatchpointSets for each JSGlobalObject's property referenced
+            from DFG and FTL and inject CodeBlock jettison watchpoints in the main thread.
+            * dfg/DFGDesiredGlobalProperty.h: Added.
+            (JSC::DFG::DesiredGlobalProperty::DesiredGlobalProperty):
+            (JSC::DFG::DesiredGlobalProperty::globalObject const):
+            (JSC::DFG::DesiredGlobalProperty::identifierNumber const):
+            (JSC::DFG::DesiredGlobalProperty::operator== const):
+            (JSC::DFG::DesiredGlobalProperty::operator!= const):
+            (JSC::DFG::DesiredGlobalProperty::isHashTableDeletedValue const):
+            (JSC::DFG::DesiredGlobalProperty::hash const):
+            (JSC::DFG::DesiredGlobalProperty::dumpInContext const):
+            (JSC::DFG::DesiredGlobalProperty::dump const):
+            (JSC::DFG::DesiredGlobalPropertyHash::hash):
+            (JSC::DFG::DesiredGlobalPropertyHash::equal):
+            * dfg/DFGGraph.h:
+            (JSC::DFG::Graph::globalProperties):
+            * dfg/DFGPlan.cpp:
+            (JSC::DFG::Plan::reallyAdd):
+            (JSC::DFG::Plan::isStillValidOnMainThread):
+            (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
+            (JSC::DFG::Plan::cancel):
+            * dfg/DFGPlan.h:
+            (JSC::DFG::Plan::globalProperties):
+            * jit/JITPropertyAccess.cpp:
+            (JSC::JIT::emit_op_resolve_scope):
+            (JSC::JIT::emit_op_get_from_scope):
+            (JSC::JIT::emit_op_put_to_scope):
+            * jit/JITPropertyAccess32_64.cpp:
+            (JSC::JIT::emit_op_resolve_scope):
+            (JSC::JIT::emit_op_get_from_scope):
+            (JSC::JIT::emit_op_put_to_scope):
+            * runtime/JSGlobalObject.cpp:
+            (JSC::JSGlobalObject::addStaticGlobals):
+            (JSC::JSGlobalObject::notifyLexicalBindingShadowing):
+            (JSC::JSGlobalObject::getReferencedPropertyWatchpointSet):
+            (JSC::JSGlobalObject::ensureReferencedPropertyWatchpointSet):
+            * runtime/JSGlobalObject.h:
+            * runtime/ProgramExecutable.cpp:
+            (JSC::hasRestrictedGlobalProperty):
+            (JSC::ProgramExecutable::initializeGlobalProperties):
+
+2019-01-15  Alan Coon  <alanc...@apple.com>
+
         Cherry-pick r239787. rdar://problem/47260350
 
     Gigacage disabling checks should handle the GIGACAGE_ALLOCATION_CAN_FAIL case properly.

Modified: branches/safari-607-branch/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-01-16 23:27:52 UTC (rev 240072)
@@ -1084,6 +1084,7 @@
 		5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; };
 		5DBB1525131D0BD70056AD36 /* minidom.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 1412110D0A48788700480255 /* minidom.js */; };
 		5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */ = {isa = PBXBuildFile; fileRef = F692A8540255597D01FF60F7 /* create_hash_table */; settings = {ATTRIBUTES = (); }; };
+		5E158AC350BC4EC7877DC0F4 /* ObjectPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		623A37EC1B87A7C000754209 /* RegisterMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 623A37EB1B87A7BD00754209 /* RegisterMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		627673241B680C1E00FD9F2E /* CallMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 627673221B680C1E00FD9F2E /* CallMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1624,7 +1625,6 @@
 		BC18C4440E16F5CD00B34460 /* NumberPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C50E16D4E900A06E92 /* NumberPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		5E158AC350BC4EC7877DC0F4 /* ObjectPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4480E16F5CD00B34460 /* Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8780255597D01FF60F7 /* Operations.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4540E16F5CD00B34460 /* PropertyNameArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 65400C100A69BAF200509887 /* PropertyNameArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1757,6 +1757,7 @@
 		E3A0531C21342B680022EC14 /* WasmSectionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531821342B670022EC14 /* WasmSectionParser.h */; };
 		E3A32BC71FC83147007D7E76 /* WeakMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A32BC61FC8312E007D7E76 /* WeakMapImpl.h */; };
 		E3A421431D6F58930007C617 /* PreciseJumpTargetsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E3BFA5D021E853A1009C0EBA /* DFGDesiredGlobalProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFA5CD21E853A1009C0EBA /* DFGDesiredGlobalProperty.h */; };
 		E3BFD0BC1DAF808E0065DEA2 /* AccessCaseSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFD0BA1DAF807C0065DEA2 /* AccessCaseSnippetParams.h */; };
 		E3C295DD1ED2CBDA00D3016F /* ObjectPropertyChangeAdaptiveWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C295DC1ED2CBAA00D3016F /* ObjectPropertyChangeAdaptiveWatchpoint.h */; };
 		E3C79CAB1DB9A4DC00D1ECA4 /* DOMJITEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C79CAA1DB9A4D600D1ECA4 /* DOMJITEffect.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3669,6 +3670,7 @@
 		6A38CFA81E32B58B0060206F /* AsyncStackTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncStackTrace.h; sourceTree = "<group>"; };
 		6AD2CB4C19B9140100065719 /* DebuggerEvalEnabler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerEvalEnabler.h; sourceTree = "<group>"; };
 		6BA93C9590484C5BAD9316EA /* JSScriptFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSScriptFetcher.h; sourceTree = "<group>"; };
+		6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototypeInlines.h; sourceTree = "<group>"; };
 		70113D491A8DB093003848C4 /* IteratorOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IteratorOperations.cpp; sourceTree = "<group>"; };
 		70113D4A1A8DB093003848C4 /* IteratorOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IteratorOperations.h; sourceTree = "<group>"; };
 		7013CA891B491A9400CAE613 /* JSMicrotask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMicrotask.cpp; sourceTree = "<group>"; };
@@ -4487,7 +4489,6 @@
 		BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectConstructor.h; sourceTree = "<group>"; };
 		BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectPrototype.cpp; sourceTree = "<group>"; };
 		BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototype.h; sourceTree = "<group>"; };
-		6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototypeInlines.h; sourceTree = "<group>"; };
 		BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumberConstructor.lut.h; sourceTree = "<group>"; };
 		BC3046060E1F497F003232CF /* Error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Error.h; sourceTree = "<group>"; };
 		BC337BDE0E1AF0B80076918A /* GetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GetterSetter.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -4692,6 +4693,9 @@
 		E3A32BC51FC8312D007D7E76 /* WeakMapImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakMapImpl.cpp; sourceTree = "<group>"; };
 		E3A32BC61FC8312E007D7E76 /* WeakMapImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakMapImpl.h; sourceTree = "<group>"; };
 		E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreciseJumpTargetsInlines.h; sourceTree = "<group>"; };
+		E3BFA5CB21E853A0009C0EBA /* DFGDesiredGlobalProperties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredGlobalProperties.cpp; path = dfg/DFGDesiredGlobalProperties.cpp; sourceTree = "<group>"; };
+		E3BFA5CC21E853A0009C0EBA /* DFGDesiredGlobalProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredGlobalProperties.h; path = dfg/DFGDesiredGlobalProperties.h; sourceTree = "<group>"; };
+		E3BFA5CD21E853A1009C0EBA /* DFGDesiredGlobalProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredGlobalProperty.h; path = dfg/DFGDesiredGlobalProperty.h; sourceTree = "<group>"; };
 		E3BFD0B91DAF807C0065DEA2 /* AccessCaseSnippetParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessCaseSnippetParams.cpp; sourceTree = "<group>"; };
 		E3BFD0BA1DAF807C0065DEA2 /* AccessCaseSnippetParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessCaseSnippetParams.h; sourceTree = "<group>"; };
 		E3C295DC1ED2CBAA00D3016F /* ObjectPropertyChangeAdaptiveWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPropertyChangeAdaptiveWatchpoint.h; sourceTree = "<group>"; };
@@ -7337,6 +7341,9 @@
 				0FFFC94E14EF909500C72532 /* DFGCSEPhase.h */,
 				0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */,
 				0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */,
+				E3BFA5CB21E853A0009C0EBA /* DFGDesiredGlobalProperties.cpp */,
+				E3BFA5CC21E853A0009C0EBA /* DFGDesiredGlobalProperties.h */,
+				E3BFA5CD21E853A1009C0EBA /* DFGDesiredGlobalProperty.h */,
 				0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */,
 				0F8F2B98172F04FD007DBDA5 /* DFGDesiredIdentifiers.h */,
 				0FFC92131B94E83E0071DD66 /* DFGDesiredInferredType.h */,
@@ -8724,6 +8731,7 @@
 				A7D89CF617A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.h in Headers */,
 				0FFFC95A14EF90A900C72532 /* DFGCSEPhase.h in Headers */,
 				0F2FC77316E12F740038D976 /* DFGDCEPhase.h in Headers */,
+				E3BFA5D021E853A1009C0EBA /* DFGDesiredGlobalProperty.h in Headers */,
 				0F8F2B9A172F0501007DBDA5 /* DFGDesiredIdentifiers.h in Headers */,
 				0FFC92141B94E83E0071DD66 /* DFGDesiredInferredType.h in Headers */,
 				C2C0F7CE17BBFC5B00464FE4 /* DFGDesiredTransitions.h in Headers */,

Modified: branches/safari-607-branch/Source/_javascript_Core/Sources.txt (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/Sources.txt	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/Sources.txt	2019-01-16 23:27:52 UTC (rev 240072)
@@ -321,6 +321,7 @@
 dfg/DFGConstantHoistingPhase.cpp
 dfg/DFGCriticalEdgeBreakingPhase.cpp
 dfg/DFGDCEPhase.cpp
+dfg/DFGDesiredGlobalProperties.cpp
 dfg/DFGDesiredIdentifiers.cpp
 dfg/DFGDesiredTransitions.cpp
 dfg/DFGDesiredWatchpoints.cpp

Modified: branches/safari-607-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -107,6 +107,9 @@
 #endif
 
 namespace JSC {
+namespace CodeBlockInternal {
+static constexpr bool verbose = false;
+} // namespace CodeBlockInternal
 
 const ClassInfo CodeBlock::s_info = {
     "CodeBlock", nullptr, nullptr, nullptr,
@@ -620,9 +623,11 @@
                     metadata.lexicalEnvironment.set(vm, this, op.lexicalEnvironment);
                 } else
                     metadata.symbolTable.set(vm, this, op.lexicalEnvironment->symbolTable());
-            } else if (JSScope* constantScope = JSScope::constantScopeForCodeBlock(op.type, this))
+            } else if (JSScope* constantScope = JSScope::constantScopeForCodeBlock(op.type, this)) {
                 metadata.constantScope.set(vm, this, constantScope);
-            else
+                if (op.type == GlobalLexicalVar || op.type == GlobalLexicalVarWithVarInjectionChecks)
+                    metadata.localScopeDepth = 0;
+            } else
                 metadata.globalObject = nullptr;
             break;
         }
@@ -2663,6 +2668,99 @@
 }
 #endif // ENABLE(DFG_JIT)
 
+void CodeBlock::notifyLexicalBindingShadowing(VM& vm, const IdentifierSet& set)
+{
+    // FIXME: Currently, module code do not query to JSGlobalLexicalEnvironment. So this case should be removed once it is fixed.
+    // https://bugs.webkit.org/show_bug.cgi?id=193347
+    if (scriptMode() == JSParserScriptMode::Module)
+        return;
+    JSGlobalObject* globalObject = m_globalObject.get();
+
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    ConcurrentJSLocker locker(m_lock);
+
+    for (const auto& instruction : *m_instructions) {
+        OpcodeID opcodeID = instruction->opcodeID();
+        switch (opcodeID) {
+        case op_resolve_scope: {
+            auto bytecode = instruction->as<OpResolveScope>();
+            auto& metadata = bytecode.metadata(this);
+            ResolveType originalResolveType = metadata.resolveType;
+            if (originalResolveType == GlobalProperty || originalResolveType == GlobalPropertyWithVarInjectionChecks) {
+                const Identifier& ident = identifier(bytecode.var);
+                if (set.contains(ident.impl())) {
+                    // We pass JSGlobalLexicalScope as a start point of the scope chain.
+                    // It should immediately find the lexical binding because that's the reason why we perform this rewriting now.
+                    ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), bytecode.localScopeDepth, globalObject->globalScope(), ident, Get, bytecode.resolveType, InitializationMode::NotInitialization);
+                    EXCEPTION_ASSERT_UNUSED(throwScope, !throwScope.exception());
+                    ASSERT(op.type == GlobalLexicalVarWithVarInjectionChecks || op.type == GlobalLexicalVar);
+                    metadata.resolveType = needsVarInjectionChecks(originalResolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar;
+                    metadata.localScopeDepth = 0;
+                    ASSERT(!op.lexicalEnvironment);
+                    JSScope* constantScope = JSScope::constantScopeForCodeBlock(metadata.resolveType, this);
+                    ASSERT(constantScope == globalObject->globalScope());
+                    metadata.constantScope.set(vm, this, constantScope);
+                    dataLogLnIf(CodeBlockInternal::verbose, "Rewrite op_resolve_scope from ", originalResolveType, " to ", metadata.resolveType);
+                }
+            }
+            break;
+        }
+
+        case op_get_from_scope: {
+            auto bytecode = instruction->as<OpGetFromScope>();
+            auto& metadata = bytecode.metadata(this);
+            ResolveType originalResolveType = metadata.getPutInfo.resolveType();
+            if (originalResolveType == GlobalProperty || originalResolveType == GlobalPropertyWithVarInjectionChecks) {
+                const Identifier& ident = identifier(bytecode.var);
+                if (set.contains(ident.impl())) {
+                    // We pass JSGlobalLexicalScope as a start point of the scope chain.
+                    // It should immediately find the lexical binding because that's the reason why we perform this rewriting now.
+                    ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), bytecode.localScopeDepth, globalObject->globalScope(), ident, Get, bytecode.getPutInfo.resolveType(), InitializationMode::NotInitialization);
+                    EXCEPTION_ASSERT_UNUSED(throwScope, !throwScope.exception());
+                    ASSERT(op.type == GlobalLexicalVarWithVarInjectionChecks || op.type == GlobalLexicalVar);
+                    metadata.getPutInfo = GetPutInfo(bytecode.getPutInfo.resolveMode(), needsVarInjectionChecks(originalResolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar, bytecode.getPutInfo.initializationMode());
+                    metadata.watchpointSet = op.watchpointSet;
+                    metadata.operand = op.operand;
+                    dataLogLnIf(CodeBlockInternal::verbose, "Rewrite op_get_from_scope from ", originalResolveType, " to ", metadata.getPutInfo.resolveType());
+                }
+            }
+            break;
+        }
+
+        case op_put_to_scope: {
+            auto bytecode = instruction->as<OpPutToScope>();
+            auto& metadata = bytecode.metadata(this);
+            ResolveType originalResolveType = metadata.getPutInfo.resolveType();
+            if (originalResolveType == GlobalProperty || originalResolveType == GlobalPropertyWithVarInjectionChecks) {
+                const Identifier& ident = identifier(bytecode.var);
+                if (set.contains(ident.impl())) {
+                    // We pass JSGlobalLexicalScope as a start point of the scope chain.
+                    // It should immediately find the lexical binding because that's the reason why we perform this rewriting now.
+                    ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), bytecode.symbolTableOrScopeDepth, globalObject->globalScope(), ident, Put, bytecode.getPutInfo.resolveType(), bytecode.getPutInfo.initializationMode());
+                    EXCEPTION_ASSERT_UNUSED(throwScope, !throwScope.exception());
+                    ASSERT(op.type == GlobalLexicalVarWithVarInjectionChecks || op.type == GlobalLexicalVar || op.type == Dynamic);
+
+                    ResolveType resolveType = op.type;
+                    metadata.watchpointSet = nullptr;
+                    if (resolveType == GlobalLexicalVarWithVarInjectionChecks || resolveType == GlobalLexicalVar) {
+                        resolveType = needsVarInjectionChecks(originalResolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar;
+                        metadata.watchpointSet = op.watchpointSet;
+                    }
+                    metadata.getPutInfo = GetPutInfo(bytecode.getPutInfo.resolveMode(), resolveType, bytecode.getPutInfo.initializationMode());
+                    metadata.operand = op.operand;
+                    dataLogLnIf(CodeBlockInternal::verbose, "Rewrite op_put_to_scope from ", originalResolveType, " to ", metadata.getPutInfo.resolveType());
+                }
+            }
+            break;
+        }
+
+        default:
+            break;
+        }
+    }
+}
+
 #if ENABLE(VERBOSE_VALUE_PROFILE)
 void CodeBlock::dumpValueProfiles()
 {

Modified: branches/safari-607-branch/Source/_javascript_Core/bytecode/CodeBlock.h (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/bytecode/CodeBlock.h	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/bytecode/CodeBlock.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -195,6 +195,8 @@
     void visitChildren(SlotVisitor&);
     void finalizeUnconditionally(VM&);
 
+    void notifyLexicalBindingShadowing(VM&, const IdentifierSet&);
+
     void dumpSource();
     void dumpSource(PrintStream&);
 
@@ -212,6 +214,8 @@
     bool isStrictMode() const { return m_isStrictMode; }
     ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
 
+    JSParserScriptMode scriptMode() const { return m_unlinkedCode->scriptMode(); }
+
     bool hasInstalledVMTrapBreakpoints() const;
     bool installVMTrapBreakpoints();
 

Modified: branches/safari-607-branch/Source/_javascript_Core/bytecode/Watchpoint.h (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/bytecode/Watchpoint.h	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/bytecode/Watchpoint.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -124,6 +124,11 @@
     // FIXME: In many cases, it would be amazing if this *did* fire the watchpoints. I suspect that
     // this might be hard to get right, but still, it might be awesome.
     JS_EXPORT_PRIVATE ~WatchpointSet(); // Note that this will not fire any of the watchpoints; if you need to know when a WatchpointSet dies then you need a separate mechanism for this.
+
+    static Ref<WatchpointSet> create(WatchpointState state)
+    {
+        return adoptRef(*new WatchpointSet(state));
+    }
     
     // Fast way of getting the state, which only works from the main thread.
     WatchpointState stateOnJSThread() const

Modified: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -6134,9 +6134,39 @@
         case op_resolve_scope: {
             auto bytecode = currentInstruction->as<OpResolveScope>();
             auto& metadata = bytecode.metadata(codeBlock);
-            unsigned depth = metadata.localScopeDepth;
 
-            if (needsDynamicLookup(metadata.resolveType, op_resolve_scope)) {
+            ResolveType resolveType;
+            unsigned depth;
+            JSScope* constantScope = nullptr;
+            JSCell* lexicalEnvironment = nullptr;
+            SymbolTable* symbolTable = nullptr;
+            {
+                ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+                resolveType = metadata.resolveType;
+                depth = metadata.localScopeDepth;
+                switch (resolveType) {
+                case GlobalProperty:
+                case GlobalVar:
+                case GlobalPropertyWithVarInjectionChecks:
+                case GlobalVarWithVarInjectionChecks:
+                case GlobalLexicalVar:
+                case GlobalLexicalVarWithVarInjectionChecks:
+                    constantScope = metadata.constantScope.get();
+                    break;
+                case ModuleVar:
+                    lexicalEnvironment = metadata.lexicalEnvironment.get();
+                    break;
+                case LocalClosureVar:
+                case ClosureVar:
+                case ClosureVarWithVarInjectionChecks:
+                    symbolTable = metadata.symbolTable.get();
+                    break;
+                default:
+                    break;
+                }
+            }
+
+            if (needsDynamicLookup(resolveType, op_resolve_scope)) {
                 unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[bytecode.var];
                 set(bytecode.dst, addToGraph(ResolveScope, OpInfo(identifierNumber), get(bytecode.scope)));
                 NEXT_OPCODE(op_resolve_scope);
@@ -6143,10 +6173,20 @@
             }
 
             // get_from_scope and put_to_scope depend on this watchpoint forcing OSR exit, so they don't add their own watchpoints.
-            if (needsVarInjectionChecks(metadata.resolveType))
+            if (needsVarInjectionChecks(resolveType))
                 m_graph.watchpoints().addLazily(m_inlineStackTop->m_codeBlock->globalObject()->varInjectionWatchpoint());
 
-            switch (metadata.resolveType) {
+            // FIXME: Currently, module code do not query to JSGlobalLexicalEnvironment. So this case should be removed once it is fixed.
+            // https://bugs.webkit.org/show_bug.cgi?id=193347
+            if (m_inlineStackTop->m_codeBlock->scriptMode() != JSParserScriptMode::Module) {
+                if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) {
+                    unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[bytecode.var];
+                    JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject();
+                    m_graph.globalProperties().addLazily(DesiredGlobalProperty(globalObject, identifierNumber));
+                }
+            }
+
+            switch (resolveType) {
             case GlobalProperty:
             case GlobalVar:
             case GlobalPropertyWithVarInjectionChecks:
@@ -6153,9 +6193,8 @@
             case GlobalVarWithVarInjectionChecks:
             case GlobalLexicalVar:
             case GlobalLexicalVarWithVarInjectionChecks: {
-                JSScope* constantScope = JSScope::constantScopeForCodeBlock(metadata.resolveType, m_inlineStackTop->m_codeBlock);
                 RELEASE_ASSERT(constantScope);
-                RELEASE_ASSERT(metadata.constantScope.get() == constantScope);
+                RELEASE_ASSERT(constantScope == JSScope::constantScopeForCodeBlock(resolveType, m_inlineStackTop->m_codeBlock));
                 set(bytecode.dst, weakJSConstant(constantScope));
                 addToGraph(Phantom, get(bytecode.scope));
                 break;
@@ -6164,7 +6203,7 @@
                 // Since the value of the "scope" virtual register is not used in LLInt / baseline op_resolve_scope with ModuleVar,
                 // we need not to keep it alive by the Phantom node.
                 // Module environment is already strongly referenced by the CodeBlock.
-                set(bytecode.dst, weakJSConstant(metadata.lexicalEnvironment.get()));
+                set(bytecode.dst, weakJSConstant(lexicalEnvironment));
                 break;
             }
             case LocalClosureVar:
@@ -6175,7 +6214,7 @@
                 
                 // We have various forms of constant folding here. This is necessary to avoid
                 // spurious recompiles in dead-but-foldable code.
-                if (SymbolTable* symbolTable = metadata.symbolTable.get()) {
+                if (symbolTable) {
                     InferredValue* singleton = symbolTable->singletonScope();
                     if (JSValue value = singleton->inferredValue()) {
                         m_graph.watchpoints().addLazily(singleton);
@@ -6221,13 +6260,16 @@
             auto& metadata = bytecode.metadata(codeBlock);
             unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[bytecode.var];
             UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber];
-            ResolveType resolveType = metadata.getPutInfo.resolveType();
 
+            ResolveType resolveType;
+            GetPutInfo getPutInfo(0);
             Structure* structure = 0;
             WatchpointSet* watchpoints = 0;
             uintptr_t operand;
             {
                 ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+                getPutInfo = metadata.getPutInfo;
+                resolveType = getPutInfo.resolveType();
                 if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
                     watchpoints = metadata.watchpointSet;
                 else if (resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
@@ -6236,7 +6278,7 @@
             }
 
             if (needsDynamicLookup(resolveType, op_get_from_scope)) {
-                uint64_t opInfo1 = makeDynamicVarOpInfo(identifierNumber, metadata.getPutInfo.operand());
+                uint64_t opInfo1 = makeDynamicVarOpInfo(identifierNumber, getPutInfo.operand());
                 SpeculatedType prediction = getPrediction();
                 set(bytecode.dst,
                     addToGraph(GetDynamicVar, OpInfo(opInfo1), OpInfo(prediction), get(bytecode.scope)));
@@ -6250,6 +6292,11 @@
             switch (resolveType) {
             case GlobalProperty:
             case GlobalPropertyWithVarInjectionChecks: {
+                // FIXME: Currently, module code do not query to JSGlobalLexicalEnvironment. So this case should be removed once it is fixed.
+                // https://bugs.webkit.org/show_bug.cgi?id=193347
+                if (m_inlineStackTop->m_codeBlock->scriptMode() != JSParserScriptMode::Module)
+                    m_graph.globalProperties().addLazily(DesiredGlobalProperty(globalObject, identifierNumber));
+
                 SpeculatedType prediction = getPrediction();
 
                 GetByIdStatus status = GetByIdStatus::computeFor(structure, uid);
@@ -6386,7 +6433,6 @@
             unsigned identifierNumber = bytecode.var;
             if (identifierNumber != UINT_MAX)
                 identifierNumber = m_inlineStackTop->m_identifierRemap[identifierNumber];
-            ResolveType resolveType = metadata.getPutInfo.resolveType();
             UniquedStringImpl* uid;
             if (identifierNumber != UINT_MAX)
                 uid = m_graph.identifiers()[identifierNumber];
@@ -6393,11 +6439,15 @@
             else
                 uid = nullptr;
             
+            ResolveType resolveType;
+            GetPutInfo getPutInfo(0);
             Structure* structure = nullptr;
             WatchpointSet* watchpoints = nullptr;
             uintptr_t operand;
             {
                 ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+                getPutInfo = metadata.getPutInfo;
+                resolveType = getPutInfo.resolveType();
                 if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar || resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)
                     watchpoints = metadata.watchpointSet;
                 else if (resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
@@ -6409,7 +6459,7 @@
 
             if (needsDynamicLookup(resolveType, op_put_to_scope)) {
                 ASSERT(identifierNumber != UINT_MAX);
-                uint64_t opInfo1 = makeDynamicVarOpInfo(identifierNumber, metadata.getPutInfo.operand());
+                uint64_t opInfo1 = makeDynamicVarOpInfo(identifierNumber, getPutInfo.operand());
                 addToGraph(PutDynamicVar, OpInfo(opInfo1), OpInfo(), get(bytecode.scope), get(bytecode.value));
                 NEXT_OPCODE(op_put_to_scope);
             }
@@ -6417,6 +6467,11 @@
             switch (resolveType) {
             case GlobalProperty:
             case GlobalPropertyWithVarInjectionChecks: {
+                // FIXME: Currently, module code do not query to JSGlobalLexicalEnvironment. So this case should be removed once it is fixed.
+                // https://bugs.webkit.org/show_bug.cgi?id=193347
+                if (m_inlineStackTop->m_codeBlock->scriptMode() != JSParserScriptMode::Module)
+                    m_graph.globalProperties().addLazily(DesiredGlobalProperty(globalObject, identifierNumber));
+
                 PutByIdStatus status;
                 if (uid)
                     status = PutByIdStatus::computeFor(globalObject, structure, uid, false);
@@ -6438,7 +6493,7 @@
             case GlobalLexicalVarWithVarInjectionChecks:
             case GlobalVar:
             case GlobalVarWithVarInjectionChecks: {
-                if (!isInitialization(metadata.getPutInfo.initializationMode()) && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) {
+                if (!isInitialization(getPutInfo.initializationMode()) && (resolveType == GlobalLexicalVar || resolveType == GlobalLexicalVarWithVarInjectionChecks)) {
                     SpeculatedType prediction = SpecEmpty;
                     Node* value = addToGraph(GetGlobalLexicalVariable, OpInfo(operand), OpInfo(prediction));
                     addToGraph(CheckNotEmpty, value);

Added: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperties.cpp (0 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperties.cpp	                        (rev 0)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperties.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 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 "DFGDesiredGlobalProperties.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "CodeBlock.h"
+#include "DFGCommonData.h"
+#include "DFGDesiredIdentifiers.h"
+#include "JSCInlines.h"
+#include "JSGlobalObject.h"
+
+namespace JSC { namespace DFG {
+
+bool DesiredGlobalProperties::isStillValidOnMainThread(DesiredIdentifiers& identifiers)
+{
+    for (const auto& property : m_set) {
+        auto* uid = identifiers.at(property.identifierNumber());
+        if (auto* watchpointSet = property.globalObject()->getReferencedPropertyWatchpointSet(uid)) {
+            if (!watchpointSet->isStillValid())
+                return false;
+        }
+    }
+    return true;
+}
+
+void DesiredGlobalProperties::reallyAdd(CodeBlock* codeBlock, DesiredIdentifiers& identifiers, CommonData& common)
+{
+    for (const auto& property : m_set) {
+        auto* uid = identifiers.at(property.identifierNumber());
+        auto& watchpointSet = property.globalObject()->ensureReferencedPropertyWatchpointSet(uid);
+        ASSERT(watchpointSet.isStillValid());
+        watchpointSet.add(common.watchpoints.add(codeBlock));
+    }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+

Added: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperties.h (0 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperties.h	                        (rev 0)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperties.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGDesiredGlobalProperty.h"
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+class CodeBlock;
+class VM;
+
+namespace DFG {
+
+class CommonData;
+class DesiredIdentifiers;
+
+class DesiredGlobalProperties {
+public:
+    void addLazily(DesiredGlobalProperty&& property)
+    {
+        m_set.add(WTFMove(property));
+    }
+
+    bool isStillValidOnMainThread(DesiredIdentifiers&);
+
+    void reallyAdd(CodeBlock*, DesiredIdentifiers&, CommonData&);
+
+private:
+    HashSet<DesiredGlobalProperty> m_set;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)

Added: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperty.h (0 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperty.h	                        (rev 0)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGDesiredGlobalProperty.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#if ENABLE(DFG_JIT)
+
+#include "DumpContext.h"
+#include <wtf/HashMap.h>
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+class JSGlobalObject;
+
+namespace DFG {
+
+class DesiredGlobalProperty {
+public:
+    DesiredGlobalProperty() = default;
+
+    DesiredGlobalProperty(JSGlobalObject* globalObject, unsigned identifierNumber)
+        : m_globalObject(globalObject)
+        , m_identifierNumber(identifierNumber)
+    {
+    }
+
+    DesiredGlobalProperty(WTF::HashTableDeletedValueType)
+        : m_globalObject(nullptr)
+        , m_identifierNumber(UINT_MAX)
+    {
+    }
+
+    JSGlobalObject* globalObject() const { return m_globalObject; }
+    unsigned identifierNumber() const { return m_identifierNumber; }
+
+    bool operator==(const DesiredGlobalProperty& other) const
+    {
+        return m_globalObject == other.m_globalObject && m_identifierNumber == other.m_identifierNumber;
+    }
+
+    bool operator!=(const DesiredGlobalProperty& other) const
+    {
+        return !(*this == other);
+    }
+
+    bool isHashTableDeletedValue() const
+    {
+        return !m_globalObject && m_identifierNumber == UINT_MAX;
+    }
+
+    unsigned hash() const
+    {
+        return WTF::PtrHash<JSGlobalObject*>::hash(m_globalObject) + m_identifierNumber * 7;
+    }
+
+    void dumpInContext(PrintStream& out, DumpContext*) const
+    {
+        out.print(m_identifierNumber, " for ", RawPointer(m_globalObject));
+    }
+
+    void dump(PrintStream& out) const
+    {
+        dumpInContext(out, nullptr);
+    }
+
+private:
+    JSGlobalObject* m_globalObject { nullptr };
+    unsigned m_identifierNumber { 0 };
+};
+
+struct DesiredGlobalPropertyHash {
+    static unsigned hash(const DesiredGlobalProperty& key) { return key.hash(); }
+    static bool equal(const DesiredGlobalProperty& a, const DesiredGlobalProperty& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::DFG::DesiredGlobalProperty> {
+    typedef JSC::DFG::DesiredGlobalPropertyHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::DFG::DesiredGlobalProperty> : SimpleClassHashTraits<JSC::DFG::DesiredGlobalProperty> { };
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)

Modified: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGGraph.h (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGGraph.h	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGGraph.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -785,6 +785,7 @@
 
     DesiredIdentifiers& identifiers() { return m_plan.identifiers(); }
     DesiredWatchpoints& watchpoints() { return m_plan.watchpoints(); }
+    DesiredGlobalProperties& globalProperties() { return m_plan.globalProperties(); }
 
     // Returns false if the key is already invalid or unwatchable. If this is a Presence condition,
     // this also makes it cheap to query if the condition holds. Also makes sure that the GC knows

Modified: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGPlan.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGPlan.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGPlan.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -556,6 +556,7 @@
     m_identifiers.reallyAdd(*m_vm, commonData);
     m_weakReferences.reallyAdd(*m_vm, commonData);
     m_transitions.reallyAdd(*m_vm, commonData);
+    m_globalProperties.reallyAdd(m_codeBlock, m_identifiers, *commonData);
     commonData->recordedStatuses = WTFMove(m_recordedStatuses);
 }
 
@@ -570,12 +571,17 @@
     m_stage = Ready;
 }
 
+bool Plan::isStillValidOnMainThread()
+{
+    return m_globalProperties.isStillValidOnMainThread(m_identifiers);
+}
+
 CompilationResult Plan::finalizeWithoutNotifyingCallback()
 {
     // We will establish new references from the code block to things. So, we need a barrier.
     m_vm->heap.writeBarrier(m_codeBlock);
 
-    if (!isStillValid()) {
+    if (!isStillValidOnMainThread() || !isStillValid()) {
         CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("invalidated"));
         return CompilationInvalidated;
     }
@@ -682,6 +688,7 @@
     m_inlineCallFrames = nullptr;
     m_watchpoints = DesiredWatchpoints();
     m_identifiers = DesiredIdentifiers();
+    m_globalProperties = DesiredGlobalProperties();
     m_weakReferences = DesiredWeakReferences();
     m_transitions = DesiredTransitions();
     m_callback = nullptr;

Modified: branches/safari-607-branch/Source/_javascript_Core/dfg/DFGPlan.h (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/dfg/DFGPlan.h	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/dfg/DFGPlan.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -28,6 +28,7 @@
 #include "CompilationResult.h"
 #include "DFGCompilationKey.h"
 #include "DFGCompilationMode.h"
+#include "DFGDesiredGlobalProperties.h"
 #include "DFGDesiredIdentifiers.h"
 #include "DFGDesiredTransitions.h"
 #include "DFGDesiredWatchpoints.h"
@@ -101,6 +102,7 @@
     DesiredIdentifiers& identifiers() { return m_identifiers; }
     DesiredWeakReferences& weakReferences() { return m_weakReferences; }
     DesiredTransitions& transitions() { return m_transitions; }
+    DesiredGlobalProperties& globalProperties() { return m_globalProperties; }
     RecordedStatuses& recordedStatuses() { return m_recordedStatuses; }
 
     bool willTryToTierUp() const { return m_willTryToTierUp; }
@@ -122,6 +124,7 @@
     enum CompilationPath { FailPath, DFGPath, FTLPath, CancelPath };
     CompilationPath compileInThreadImpl();
     
+    bool isStillValidOnMainThread();
     bool isStillValid();
     void reallyAdd(CommonData*);
 
@@ -151,6 +154,7 @@
     DesiredIdentifiers m_identifiers;
     DesiredWeakReferences m_weakReferences;
     DesiredTransitions m_transitions;
+    DesiredGlobalProperties m_globalProperties;
     RecordedStatuses m_recordedStatuses;
 
     bool m_willTryToTierUp { false };

Modified: branches/safari-607-branch/Source/_javascript_Core/jit/JITPropertyAccess.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -767,8 +767,8 @@
     auto emitCode = [&] (ResolveType resolveType) {
         switch (resolveType) {
         case GlobalProperty:
+        case GlobalPropertyWithVarInjectionChecks:
         case GlobalVar:
-        case GlobalPropertyWithVarInjectionChecks:
         case GlobalVarWithVarInjectionChecks:
         case GlobalLexicalVar:
         case GlobalLexicalVarWithVarInjectionChecks: {
@@ -798,6 +798,15 @@
     };
 
     switch (resolveType) {
+    case GlobalProperty:
+    case GlobalPropertyWithVarInjectionChecks: {
+        // Since these GlobalProperty can be changed to GlobalLexicalVar, we should load the value from metadata.
+        JSScope** constantScopeSlot = metadata.constantScope.slot();
+        emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
+        loadPtr(constantScopeSlot, regT0);
+        emitPutVirtualRegister(dst);
+        break;
+    }
     case UnresolvedProperty:
     case UnresolvedPropertyWithVarInjectionChecks: {
         JumpList skipToEnd;
@@ -925,6 +934,22 @@
     };
 
     switch (resolveType) {
+    case GlobalProperty:
+    case GlobalPropertyWithVarInjectionChecks: {
+        JumpList skipToEnd;
+        load32(&metadata.getPutInfo, regT0);
+        and32(TrustedImm32(GetPutInfo::typeBits), regT0); // Load ResolveType into T0
+
+        Jump isNotGlobalProperty = branch32(NotEqual, regT0, TrustedImm32(resolveType));
+        emitCode(resolveType, false);
+        skipToEnd.append(jump());
+
+        isNotGlobalProperty.link(this);
+        emitCode(needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar, true);
+
+        skipToEnd.link(this);
+        break;
+    }
     case UnresolvedProperty:
     case UnresolvedPropertyWithVarInjectionChecks: {
         JumpList skipToEnd;
@@ -1064,6 +1089,25 @@
     };
 
     switch (resolveType) {
+    case GlobalProperty:
+    case GlobalPropertyWithVarInjectionChecks: {
+        JumpList skipToEnd;
+        load32(&metadata.getPutInfo, regT0);
+        and32(TrustedImm32(GetPutInfo::typeBits), regT0); // Load ResolveType into T0
+
+        Jump isGlobalProperty = branch32(Equal, regT0, TrustedImm32(resolveType));
+        Jump isGlobalLexicalVar = branch32(Equal, regT0, TrustedImm32(needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar));
+        addSlowCase(jump()); // Dynamic, it can happen if we attempt to put a value to already-initialized const binding.
+
+        isGlobalLexicalVar.link(this);
+        emitCode(needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar, true);
+        skipToEnd.append(jump());
+
+        isGlobalProperty.link(this);
+        emitCode(resolveType, false);
+        skipToEnd.link(this);
+        break;
+    }
     case UnresolvedProperty:
     case UnresolvedPropertyWithVarInjectionChecks: {
         JumpList skipToEnd;

Modified: branches/safari-607-branch/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -770,10 +770,10 @@
     auto emitCode = [&] (ResolveType resolveType) {
         switch (resolveType) {
         case GlobalProperty:
+        case GlobalPropertyWithVarInjectionChecks:
         case GlobalVar:
+        case GlobalVarWithVarInjectionChecks: 
         case GlobalLexicalVar:
-        case GlobalPropertyWithVarInjectionChecks:
-        case GlobalVarWithVarInjectionChecks: 
         case GlobalLexicalVarWithVarInjectionChecks: {
             JSScope* constantScope = JSScope::constantScopeForCodeBlock(resolveType, m_codeBlock);
             RELEASE_ASSERT(constantScope);
@@ -802,6 +802,16 @@
         }
     };
     switch (resolveType) {
+    case GlobalProperty:
+    case GlobalPropertyWithVarInjectionChecks: {
+        // Since these GlobalProperty can be changed to GlobalLexicalVar, we should load the value from metadata.
+        JSScope** constantScopeSlot = metadata.constantScope.slot();
+        emitVarInjectionCheck(needsVarInjectionChecks(resolveType));
+        move(TrustedImm32(JSValue::CellTag), regT1);
+        loadPtr(constantScopeSlot, regT0);
+        emitStore(dst, regT1, regT0);
+        break;
+    }
     case UnresolvedProperty:
     case UnresolvedPropertyWithVarInjectionChecks: {
         JumpList skipToEnd;
@@ -927,6 +937,21 @@
     };
 
     switch (resolveType) {
+    case GlobalProperty:
+    case GlobalPropertyWithVarInjectionChecks: {
+        JumpList skipToEnd;
+        load32(&currentInstruction[4], regT0);
+        and32(TrustedImm32(GetPutInfo::typeBits), regT0); // Load ResolveType into T0
+
+        Jump isNotGlobalProperty = branch32(NotEqual, regT0, TrustedImm32(resolveType));
+        emitCode(resolveType, false);
+        skipToEnd.append(jump());
+
+        isNotGlobalProperty.link(this);
+        emitCode(needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar, true);
+        skipToEnd.link(this);
+        break;
+    }
     case UnresolvedProperty:
     case UnresolvedPropertyWithVarInjectionChecks: {
         JumpList skipToEnd;
@@ -1067,6 +1092,25 @@
     };
 
     switch (resolveType) {
+    case GlobalProperty:
+    case GlobalPropertyWithVarInjectionChecks: {
+        JumpList skipToEnd;
+        load32(&currentInstruction[4], regT0);
+        and32(TrustedImm32(GetPutInfo::typeBits), regT0); // Load ResolveType into T0
+
+        Jump isGlobalProperty = branch32(Equal, regT0, TrustedImm32(resolveType));
+        Jump isGlobalLexicalVar = branch32(Equal, regT0, TrustedImm32(needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar));
+        addSlowCase(jump()); // Dynamic, it can happen if we attempt to put a value to already-initialized const binding.
+
+        isGlobalLexicalVar.link(this);
+        emitCode(needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar, true);
+        skipToEnd.append(jump());
+
+        isGlobalProperty.link(this);
+        emitCode(resolveType, false);
+        skipToEnd.link(this);
+        break;
+    }
     case UnresolvedProperty:
     case UnresolvedPropertyWithVarInjectionChecks: {
         JumpList skipToEnd;

Modified: branches/safari-607-branch/Source/_javascript_Core/runtime/JSGlobalObject.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -50,6 +50,7 @@
 #include "CatchScope.h"
 #include "ClonedArguments.h"
 #include "CodeBlock.h"
+#include "CodeBlockSetInlines.h"
 #include "CodeCache.h"
 #include "ConsoleObject.h"
 #include "DateConstructor.h"
@@ -1711,6 +1712,10 @@
 
     for (int i = 0; i < count; ++i) {
         GlobalPropertyInfo& global = globals[i];
+        // This `configurable = false` is necessary condition for static globals,
+        // otherwise lexical bindings can change the result of GlobalVar queries too.
+        // We won't be able to declare a global lexical variable with the sanem name to
+        // the static globals because configurable = false.
         ASSERT(global.attributes & PropertyAttribute::DontDelete);
         
         WatchpointSet* watchpointSet = nullptr;
@@ -1846,6 +1851,19 @@
 }
 #endif // ENABLE(INTL)
 
+void JSGlobalObject::notifyLexicalBindingShadowing(VM& vm, const IdentifierSet& set)
+{
+#if ENABLE(DFG_JIT)
+    for (const auto& key : set)
+        ensureReferencedPropertyWatchpointSet(key.get()).fireAll(vm, "Lexical binding shadows the existing global properties");
+#endif
+    vm.heap.codeBlockSet().iterate([&] (CodeBlock* codeBlock) {
+        if (codeBlock->globalObject() != this)
+            return;
+        codeBlock->notifyLexicalBindingShadowing(vm, set);
+    });
+}
+
 void JSGlobalObject::queueMicrotask(Ref<Microtask>&& task)
 {
     if (globalObjectMethodTable()->queueTaskToEventLoop) {
@@ -1866,6 +1884,20 @@
     return m_debugger && m_debugger->isInteractivelyDebugging();
 }
 
+#if ENABLE(DFG_JIT)
+WatchpointSet* JSGlobalObject::getReferencedPropertyWatchpointSet(UniquedStringImpl* uid)
+{
+    return m_referencedGlobalPropertyWatchpointSets.get(uid);
+}
+
+WatchpointSet& JSGlobalObject::ensureReferencedPropertyWatchpointSet(UniquedStringImpl* uid)
+{
+    return m_referencedGlobalPropertyWatchpointSets.ensure(uid, [] {
+        return WatchpointSet::create(IsWatched);
+    }).iterator->value.get();
+}
+#endif
+
 JSGlobalObject* JSGlobalObject::create(VM& vm, Structure* structure)
 {
     JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(vm.heap)) JSGlobalObject(vm, structure);

Modified: branches/safari-607-branch/Source/_javascript_Core/runtime/JSGlobalObject.h (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/runtime/JSGlobalObject.h	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/runtime/JSGlobalObject.h	2019-01-16 23:27:52 UTC (rev 240072)
@@ -483,6 +483,11 @@
     bool isMapPrototypeSetFastAndNonObservable();
     bool isSetPrototypeAddFastAndNonObservable();
 
+#if ENABLE(DFG_JIT)
+    using ReferencedGlobalPropertyWatchpointSets = HashMap<RefPtr<UniquedStringImpl>, Ref<WatchpointSet>, IdentifierRepHash>;
+    ReferencedGlobalPropertyWatchpointSets m_referencedGlobalPropertyWatchpointSets;
+#endif
+
     bool m_evalEnabled { true };
     bool m_webAssemblyEnabled { true };
     String m_evalDisabledErrorMessage;
@@ -512,6 +517,11 @@
     bool hasInteractiveDebugger() const;
     const RuntimeFlags& runtimeFlags() const { return m_runtimeFlags; }
 
+#if ENABLE(DFG_JIT)
+    WatchpointSet* getReferencedPropertyWatchpointSet(UniquedStringImpl*);
+    WatchpointSet& ensureReferencedPropertyWatchpointSet(UniquedStringImpl*);
+#endif
+
 protected:
     JS_EXPORT_PRIVATE explicit JSGlobalObject(VM&, Structure*, const GlobalObjectMethodTable* = nullptr);
 
@@ -737,6 +747,8 @@
     const HashSet<String>& intlPluralRulesAvailableLocales();
 #endif // ENABLE(INTL)
 
+    void notifyLexicalBindingShadowing(VM&, const IdentifierSet&);
+
     void setConsoleClient(ConsoleClient* consoleClient) { m_consoleClient = consoleClient; }
     ConsoleClient* consoleClient() const { return m_consoleClient; }
 

Modified: branches/safari-607-branch/Source/_javascript_Core/runtime/ProgramExecutable.cpp (240071 => 240072)


--- branches/safari-607-branch/Source/_javascript_Core/runtime/ProgramExecutable.cpp	2019-01-16 23:27:42 UTC (rev 240071)
+++ branches/safari-607-branch/Source/_javascript_Core/runtime/ProgramExecutable.cpp	2019-01-16 23:27:52 UTC (rev 240072)
@@ -59,14 +59,19 @@
 }
 
 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasrestrictedglobalproperty
-static bool hasRestrictedGlobalProperty(ExecState* exec, JSGlobalObject* globalObject, PropertyName propertyName)
+enum class GlobalPropertyLookUpStatus {
+    NotFound,
+    Configurable,
+    NonConfigurable,
+};
+static GlobalPropertyLookUpStatus hasRestrictedGlobalProperty(ExecState* exec, JSGlobalObject* globalObject, PropertyName propertyName)
 {
     PropertyDescriptor descriptor;
     if (!globalObject->getOwnPropertyDescriptor(exec, propertyName, descriptor))
-        return false;
+        return GlobalPropertyLookUpStatus::NotFound;
     if (descriptor.configurable())
-        return false;
-    return true;
+        return GlobalPropertyLookUpStatus::Configurable;
+    return GlobalPropertyLookUpStatus::NonConfigurable;
 }
 
 JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope)
@@ -102,6 +107,7 @@
     JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment();
     const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
     const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations();
+    IdentifierSet shadowedProperties;
     // 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
     {
@@ -112,16 +118,30 @@
                 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.
+        // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names (with configurable = false), or "var"/"let"/"const" variables.
         // It's an error to introduce a shadow.
         for (auto& entry : lexicalDeclarations) {
             // The ES6 spec says that RestrictedGlobalProperty can't be shadowed.
-            bool hasProperty = hasRestrictedGlobalProperty(exec, globalObject, entry.key.get());
+            GlobalPropertyLookUpStatus status = hasRestrictedGlobalProperty(exec, globalObject, entry.key.get());
             RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
-            if (hasProperty)
+            switch (status) {
+            case GlobalPropertyLookUpStatus::NonConfigurable:
                 return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'"));
+            case GlobalPropertyLookUpStatus::Configurable:
+                // Lexical bindings can shadow global properties if the given property's attribute is configurable.
+                // https://tc39.github.io/ecma262/#sec-globaldeclarationinstantiation step 5-c, `hasRestrictedGlobal` becomes false
+                // However we may emit GlobalProperty look up in bytecodes already and it may cache the value for the global scope.
+                // To make it invalid, we iterate all the CodeBlocks and rewrite the instruction to convert GlobalProperty to GlobalLexicalVar.
+                // 1. In LLInt, we always check metadata's resolveType. So rewritten instruction just works.
+                // 2. In Baseline JIT, we check metadata's resolveType in GlobalProperty case so that we can notice once it is changed.
+                // 3. In DFG and FTL, we watch the watchpoint and jettison once it is fired.
+                shadowedProperties.add(entry.key.get());
+                break;
+            case GlobalPropertyLookUpStatus::NotFound:
+                break;
+            }
 
-            hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get());
+            bool hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get());
             RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
             if (hasProperty) {
                 if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) {
@@ -186,6 +206,10 @@
             RELEASE_ASSERT(offsetForAssert == offset);
         }
     }
+
+    if (!shadowedProperties.isEmpty())
+        globalObject->notifyLexicalBindingShadowing(vm, WTFMove(shadowedProperties));
+
     return nullptr;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to