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(¤tInstruction[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(¤tInstruction[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;
}