<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[212712] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/212712">212712</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2017-02-21 02:38:58 -0800 (Tue, 21 Feb 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>JSModuleNamespace object should have IC
https://bugs.webkit.org/show_bug.cgi?id=160590

Reviewed by Saam Barati.

JSTests:

* modules/module-assert-access-binding.js: Added.
* modules/module-assert-access-namespace.js: Added.
* modules/namespace-empty.js: Added.
(from.string_appeared_here.access):
(i.shouldThrow):
* stress/module-namespace-access-change.js: Added.
(shouldBe):
(access):
(import.string_appeared_here.then):
* stress/module-namespace-access-non-constant.js: Added.
(shouldBe):
(import.string_appeared_here.then):
* stress/module-namespace-access-poly.js: Added.
(shouldBe):
(access):
(import.string_appeared_here.then):
* stress/module-namespace-access-transitive-exports.js: Added.
(shouldBe):
(import.string_appeared_here.then):
* stress/module-namespace-access.js: Added.
(shouldBe):
(import.string_appeared_here.then):
* stress/resources/module-namespace-access-transitive-exports-2.js: Added.
(export.cocoa):
(export.change):
* stress/resources/module-namespace-access-transitive-exports.js: Added.
* stress/resources/module-namespace-access.js: Added.
(export.cocoa):
(export.change):

Source/JavaScriptCore:

This patch optimizes accesses to module namespace objects.

1. Cache the resolutions for module namespace objects.

    When constructing the module namespace object, we already resolves all the exports.
    The module namespace object caches this result and leverage it in the later access in
    getOwnPropertySlot. This avoids resolving bindings through resolveExport.

2. Introduce ModuleNamespaceLoad IC.

    This patch adds new IC for module namespace objects. The mechanism is simple, getOwnPropertySlot
    tells us about module namespace object resolution. The IC first checks whether the given object
    is an expected module namespace object. If this check succeeds, we load the value from the module
    environment.

3. Introduce DFG/FTL optimization.

    After exploiting module namespace object accesses in (2), DFG can recognize this in ByteCodeParser.
    DFG will convert it to CheckCell with the namespace object and GetClosureVar from the cached environment.
    At that time, we have a chance to fold it to the constant.

This optimization improves the performance of accessing to module namespace objects.

Before
    $ time ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m module-assert-access-namespace.js
    ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m   0.43s user 0.03s system 101% cpu 0.451 total
    $ time ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m module-assert-access-binding.js
    ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m   0.08s user 0.02s system 103% cpu 0.104 total

After
    $ time ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-namespace.js
    ../../WebKitBuild/module-ic/Release/bin/jsc -m   0.11s user 0.01s system 106% cpu 0.109 total
    $ time ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-binding.js
    ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-binding.j  0.08s user 0.02s system 102% cpu 0.105 total

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/AccessCase.cpp:
(JSC::AccessCase::create):
(JSC::AccessCase::guardedByStructureCheck):
(JSC::AccessCase::canReplace):
(JSC::AccessCase::visitWeak):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):
* bytecode/AccessCase.h:
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
(JSC::GetByIdStatus::makesCalls):
(JSC::GetByIdStatus::dump):
* bytecode/GetByIdStatus.h:
(JSC::GetByIdStatus::isModuleNamespace):
(JSC::GetByIdStatus::takesSlowPath):
(JSC::GetByIdStatus::moduleNamespaceObject):
(JSC::GetByIdStatus::moduleEnvironment):
(JSC::GetByIdStatus::scopeOffset):
* bytecode/ModuleNamespaceAccessCase.cpp: Added.
(JSC::ModuleNamespaceAccessCase::ModuleNamespaceAccessCase):
(JSC::ModuleNamespaceAccessCase::create):
(JSC::ModuleNamespaceAccessCase::~ModuleNamespaceAccessCase):
(JSC::ModuleNamespaceAccessCase::clone):
(JSC::ModuleNamespaceAccessCase::emit):
* bytecode/ModuleNamespaceAccessCase.h: Added.
(JSC::ModuleNamespaceAccessCase::moduleNamespaceObject):
(JSC::ModuleNamespaceAccessCase::moduleEnvironment):
(JSC::ModuleNamespaceAccessCase::scopeOffset):
* bytecode/PolymorphicAccess.cpp:
(WTF::printInternal):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleModuleNamespaceLoad):
(JSC::DFG::ByteCodeParser::handleGetById):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::loadValue):
* jit/Repatch.cpp:
(JSC::tryCacheGetByID):
* runtime/AbstractModuleRecord.cpp:
(JSC::AbstractModuleRecord::getModuleNamespace):
* runtime/JSModuleNamespaceObject.cpp:
(JSC::JSModuleNamespaceObject::finishCreation):
(JSC::JSModuleNamespaceObject::visitChildren):
(JSC::getValue):
(JSC::JSModuleNamespaceObject::getOwnPropertySlot):
(JSC::JSModuleNamespaceObject::getOwnPropertyNames):
* runtime/JSModuleNamespaceObject.h:
(JSC::isJSModuleNamespaceObject):
(JSC::JSModuleNamespaceObject::create): Deleted.
(JSC::JSModuleNamespaceObject::createStructure): Deleted.
(JSC::JSModuleNamespaceObject::moduleRecord): Deleted.
* runtime/JSModuleRecord.h:
(JSC::JSModuleRecord::moduleEnvironment): Deleted.
* runtime/PropertySlot.h:
(JSC::PropertySlot::PropertySlot):
(JSC::PropertySlot::domJIT):
(JSC::PropertySlot::moduleNamespaceSlot):
(JSC::PropertySlot::setValueModuleNamespace):
(JSC::PropertySlot::setCacheableCustom):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeAccessCasecpp">trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeAccessCaseh">trunk/Source/JavaScriptCore/bytecode/AccessCase.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeGetByIdStatuscpp">trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeGetByIdStatush">trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp">trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelpersh">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRepatchcpp">trunk/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeAbstractModuleRecordcpp">trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSModuleNamespaceObjectcpp">trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSModuleNamespaceObjecth">trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSModuleRecordh">trunk/Source/JavaScriptCore/runtime/JSModuleRecord.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimePropertySloth">trunk/Source/JavaScriptCore/runtime/PropertySlot.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsmodulesmoduleassertaccessbindingjs">trunk/JSTests/modules/module-assert-access-binding.js</a></li>
<li><a href="#trunkJSTestsmodulesmoduleassertaccessnamespacejs">trunk/JSTests/modules/module-assert-access-namespace.js</a></li>
<li><a href="#trunkJSTestsmodulesnamespaceemptyjs">trunk/JSTests/modules/namespace-empty.js</a></li>
<li><a href="#trunkJSTestsstressmodulenamespaceaccesschangejs">trunk/JSTests/stress/module-namespace-access-change.js</a></li>
<li><a href="#trunkJSTestsstressmodulenamespaceaccessnonconstantjs">trunk/JSTests/stress/module-namespace-access-non-constant.js</a></li>
<li><a href="#trunkJSTestsstressmodulenamespaceaccesspolyjs">trunk/JSTests/stress/module-namespace-access-poly.js</a></li>
<li><a href="#trunkJSTestsstressmodulenamespaceaccesstransitiveexportsjs">trunk/JSTests/stress/module-namespace-access-transitive-exports.js</a></li>
<li><a href="#trunkJSTestsstressmodulenamespaceaccessjs">trunk/JSTests/stress/module-namespace-access.js</a></li>
<li><a href="#trunkJSTestsstressresourcesmodulenamespaceaccesstransitiveexports2js">trunk/JSTests/stress/resources/module-namespace-access-transitive-exports-2.js</a></li>
<li><a href="#trunkJSTestsstressresourcesmodulenamespaceaccesstransitiveexportsjs">trunk/JSTests/stress/resources/module-namespace-access-transitive-exports.js</a></li>
<li><a href="#trunkJSTestsstressresourcesmodulenamespaceaccessjs">trunk/JSTests/stress/resources/module-namespace-access.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeModuleNamespaceAccessCasecpp">trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeModuleNamespaceAccessCaseh">trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/JSTests/ChangeLog        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -1,5 +1,42 @@
</span><span class="cx"> 2017-02-21  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><ins>+        JSModuleNamespace object should have IC
+        https://bugs.webkit.org/show_bug.cgi?id=160590
+
+        Reviewed by Saam Barati.
+
+        * modules/module-assert-access-binding.js: Added.
+        * modules/module-assert-access-namespace.js: Added.
+        * modules/namespace-empty.js: Added.
+        (from.string_appeared_here.access):
+        (i.shouldThrow):
+        * stress/module-namespace-access-change.js: Added.
+        (shouldBe):
+        (access):
+        (import.string_appeared_here.then):
+        * stress/module-namespace-access-non-constant.js: Added.
+        (shouldBe):
+        (import.string_appeared_here.then):
+        * stress/module-namespace-access-poly.js: Added.
+        (shouldBe):
+        (access):
+        (import.string_appeared_here.then):
+        * stress/module-namespace-access-transitive-exports.js: Added.
+        (shouldBe):
+        (import.string_appeared_here.then):
+        * stress/module-namespace-access.js: Added.
+        (shouldBe):
+        (import.string_appeared_here.then):
+        * stress/resources/module-namespace-access-transitive-exports-2.js: Added.
+        (export.cocoa):
+        (export.change):
+        * stress/resources/module-namespace-access-transitive-exports.js: Added.
+        * stress/resources/module-namespace-access.js: Added.
+        (export.cocoa):
+        (export.change):
+
+2017-02-21  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
</ins><span class="cx">         ASSERTION FAILED: &quot;!scope.exception()&quot; with Object.isSealed/isFrozen and uninitialized module bindings
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=168605
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJSTestsmodulesmoduleassertaccessbindingjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/module-assert-access-binding.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/module-assert-access-binding.js                                (rev 0)
+++ trunk/JSTests/modules/module-assert-access-binding.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+import {shouldBe} from &quot;./resources/assert.js&quot;;
+
+let array = [];
+for (let i = 0; i &lt; 4000000; i++) {
+    array.push(i);
+}
+
+for (let i = 0; i &lt; 4000000; i++) {
+    shouldBe(array[i], i);
+}
</ins></span></pre></div>
<a id="trunkJSTestsmodulesmoduleassertaccessnamespacejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/module-assert-access-namespace.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/module-assert-access-namespace.js                                (rev 0)
+++ trunk/JSTests/modules/module-assert-access-namespace.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+import * as assert from &quot;./resources/assert.js&quot;;
+
+let array = [];
+for (let i = 0; i &lt; 4000000; i++) {
+    array.push(i);
+}
+
+for (let i = 0; i &lt; 4000000; i++) {
+    assert.shouldBe(array[i], i);
+}
</ins></span></pre></div>
<a id="trunkJSTestsmodulesnamespaceemptyjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/modules/namespace-empty.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/modules/namespace-empty.js                                (rev 0)
+++ trunk/JSTests/modules/namespace-empty.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+import * as ns from &quot;./namespace-empty.js&quot;
+import {shouldThrow} from &quot;./resources/assert.js&quot;
+
+function access(ns)
+{
+    return ns.test;
+}
+noInline(access);
+
+for (var i = 0; i &lt; 1e3; ++i) {
+    shouldThrow(() =&gt; {
+        access(ns);
+    }, `ReferenceError: Cannot access uninitialized variable.`);
+}
+
+
+export let test = 42;
</ins></span></pre></div>
<a id="trunkJSTestsstressmodulenamespaceaccesschangejs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/module-namespace-access-change.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/module-namespace-access-change.js                                (rev 0)
+++ trunk/JSTests/stress/module-namespace-access-change.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function access(namespace)
+{
+    return namespace.test;
+}
+noInline(access);
+
+import(&quot;./resources/module-namespace-access.js&quot;).then((ns) =&gt; {
+    for (var i = 0; i &lt; 1e4; ++i)
+        shouldBe(access(ns), 42)
+    ns.change();
+    for (var i = 0; i &lt; 1e4; ++i)
+        shouldBe(access(ns), 55)
+});
+drainMicrotasks();
</ins></span></pre></div>
<a id="trunkJSTestsstressmodulenamespaceaccessnonconstantjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/module-namespace-access-non-constant.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/module-namespace-access-non-constant.js                                (rev 0)
+++ trunk/JSTests/stress/module-namespace-access-non-constant.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+import(&quot;./resources/module-namespace-access.js&quot;).then((ns) =&gt; {
+    ns.change();
+    for (var i = 0; i &lt; 1e6; ++i) {
+        shouldBe(ns.test, 55);
+        shouldBe(ns.cocoa(), 55);
+    }
+});
+drainMicrotasks();
</ins></span></pre></div>
<a id="trunkJSTestsstressmodulenamespaceaccesspolyjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/module-namespace-access-poly.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/module-namespace-access-poly.js                                (rev 0)
+++ trunk/JSTests/stress/module-namespace-access-poly.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function access(ns)
+{
+    return ns.test;
+}
+noInline(access);
+
+import(&quot;./resources/module-namespace-access.js&quot;).then((ns) =&gt; {
+    for (var i = 0; i &lt; 1e4; ++i) {
+        shouldBe(access(ns), 42);
+    }
+    let nonNS = { test: 50 };
+    let nonNS2 = { ok: 22, test: 52 };
+    for (var i = 0; i &lt; 1e4; ++i) {
+        shouldBe(access(ns), 42);
+        shouldBe(access(nonNS), 50);
+        shouldBe(access(nonNS2), 52);
+    }
+});
+drainMicrotasks();
</ins></span></pre></div>
<a id="trunkJSTestsstressmodulenamespaceaccesstransitiveexportsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/module-namespace-access-transitive-exports.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/module-namespace-access-transitive-exports.js                                (rev 0)
+++ trunk/JSTests/stress/module-namespace-access-transitive-exports.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+import(&quot;./resources/module-namespace-access-transitive-exports.js&quot;).then((ns) =&gt; {
+    for (var i = 0; i &lt; 1e6; ++i) {
+        shouldBe(ns.test, 42);
+        shouldBe(ns.cocoa(), 42);
+    }
+});
+drainMicrotasks();
</ins></span></pre></div>
<a id="trunkJSTestsstressmodulenamespaceaccessjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/module-namespace-access.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/module-namespace-access.js                                (rev 0)
+++ trunk/JSTests/stress/module-namespace-access.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+import(&quot;./resources/module-namespace-access.js&quot;).then((ns) =&gt; {
+    for (var i = 0; i &lt; 1e6; ++i) {
+        shouldBe(ns.test, 42);
+        shouldBe(ns.cocoa(), 42);
+    }
+});
+drainMicrotasks();
</ins></span></pre></div>
<a id="trunkJSTestsstressresourcesmodulenamespaceaccesstransitiveexports2js"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/resources/module-namespace-access-transitive-exports-2.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/resources/module-namespace-access-transitive-exports-2.js                                (rev 0)
+++ trunk/JSTests/stress/resources/module-namespace-access-transitive-exports-2.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+export let test = 42;
+export function cocoa()
+{
+    return test;
+}
+
+export function change()
+{
+    test = 55;
+}
</ins></span></pre></div>
<a id="trunkJSTestsstressresourcesmodulenamespaceaccesstransitiveexportsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/resources/module-namespace-access-transitive-exports.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/resources/module-namespace-access-transitive-exports.js                                (rev 0)
+++ trunk/JSTests/stress/resources/module-namespace-access-transitive-exports.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+export * from &quot;./module-namespace-access-transitive-exports-2.js&quot;
</ins></span></pre></div>
<a id="trunkJSTestsstressresourcesmodulenamespaceaccessjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/resources/module-namespace-access.js (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/resources/module-namespace-access.js                                (rev 0)
+++ trunk/JSTests/stress/resources/module-namespace-access.js        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+export let test = 42;
+export function cocoa()
+{
+    return test;
+}
+
+export function change()
+{
+    test = 55;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -228,6 +228,7 @@
</span><span class="cx">     bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp
</span><span class="cx">     bytecode/LazyOperandValueProfile.cpp
</span><span class="cx">     bytecode/MethodOfGettingAValueProfile.cpp
</span><ins>+    bytecode/ModuleNamespaceAccessCase.cpp
</ins><span class="cx">     bytecode/ModuleProgramCodeBlock.cpp
</span><span class="cx">     bytecode/ObjectPropertyCondition.cpp
</span><span class="cx">     bytecode/ObjectPropertyConditionSet.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -1,5 +1,109 @@
</span><span class="cx"> 2017-02-21  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><ins>+        JSModuleNamespace object should have IC
+        https://bugs.webkit.org/show_bug.cgi?id=160590
+
+        Reviewed by Saam Barati.
+
+        This patch optimizes accesses to module namespace objects.
+
+        1. Cache the resolutions for module namespace objects.
+
+            When constructing the module namespace object, we already resolves all the exports.
+            The module namespace object caches this result and leverage it in the later access in
+            getOwnPropertySlot. This avoids resolving bindings through resolveExport.
+
+        2. Introduce ModuleNamespaceLoad IC.
+
+            This patch adds new IC for module namespace objects. The mechanism is simple, getOwnPropertySlot
+            tells us about module namespace object resolution. The IC first checks whether the given object
+            is an expected module namespace object. If this check succeeds, we load the value from the module
+            environment.
+
+        3. Introduce DFG/FTL optimization.
+
+            After exploiting module namespace object accesses in (2), DFG can recognize this in ByteCodeParser.
+            DFG will convert it to CheckCell with the namespace object and GetClosureVar from the cached environment.
+            At that time, we have a chance to fold it to the constant.
+
+        This optimization improves the performance of accessing to module namespace objects.
+
+        Before
+            $ time ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m module-assert-access-namespace.js
+            ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m   0.43s user 0.03s system 101% cpu 0.451 total
+            $ time ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m module-assert-access-binding.js
+            ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m   0.08s user 0.02s system 103% cpu 0.104 total
+
+        After
+            $ time ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-namespace.js
+            ../../WebKitBuild/module-ic/Release/bin/jsc -m   0.11s user 0.01s system 106% cpu 0.109 total
+            $ time ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-binding.js
+            ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-binding.j  0.08s user 0.02s system 102% cpu 0.105 total
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/AccessCase.cpp:
+        (JSC::AccessCase::create):
+        (JSC::AccessCase::guardedByStructureCheck):
+        (JSC::AccessCase::canReplace):
+        (JSC::AccessCase::visitWeak):
+        (JSC::AccessCase::generateWithGuard):
+        (JSC::AccessCase::generateImpl):
+        * bytecode/AccessCase.h:
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::GetByIdStatus):
+        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
+        (JSC::GetByIdStatus::makesCalls):
+        (JSC::GetByIdStatus::dump):
+        * bytecode/GetByIdStatus.h:
+        (JSC::GetByIdStatus::isModuleNamespace):
+        (JSC::GetByIdStatus::takesSlowPath):
+        (JSC::GetByIdStatus::moduleNamespaceObject):
+        (JSC::GetByIdStatus::moduleEnvironment):
+        (JSC::GetByIdStatus::scopeOffset):
+        * bytecode/ModuleNamespaceAccessCase.cpp: Added.
+        (JSC::ModuleNamespaceAccessCase::ModuleNamespaceAccessCase):
+        (JSC::ModuleNamespaceAccessCase::create):
+        (JSC::ModuleNamespaceAccessCase::~ModuleNamespaceAccessCase):
+        (JSC::ModuleNamespaceAccessCase::clone):
+        (JSC::ModuleNamespaceAccessCase::emit):
+        * bytecode/ModuleNamespaceAccessCase.h: Added.
+        (JSC::ModuleNamespaceAccessCase::moduleNamespaceObject):
+        (JSC::ModuleNamespaceAccessCase::moduleEnvironment):
+        (JSC::ModuleNamespaceAccessCase::scopeOffset):
+        * bytecode/PolymorphicAccess.cpp:
+        (WTF::printInternal):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleModuleNamespaceLoad):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::loadValue):
+        * jit/Repatch.cpp:
+        (JSC::tryCacheGetByID):
+        * runtime/AbstractModuleRecord.cpp:
+        (JSC::AbstractModuleRecord::getModuleNamespace):
+        * runtime/JSModuleNamespaceObject.cpp:
+        (JSC::JSModuleNamespaceObject::finishCreation):
+        (JSC::JSModuleNamespaceObject::visitChildren):
+        (JSC::getValue):
+        (JSC::JSModuleNamespaceObject::getOwnPropertySlot):
+        (JSC::JSModuleNamespaceObject::getOwnPropertyNames):
+        * runtime/JSModuleNamespaceObject.h:
+        (JSC::isJSModuleNamespaceObject):
+        (JSC::JSModuleNamespaceObject::create): Deleted.
+        (JSC::JSModuleNamespaceObject::createStructure): Deleted.
+        (JSC::JSModuleNamespaceObject::moduleRecord): Deleted.
+        * runtime/JSModuleRecord.h:
+        (JSC::JSModuleRecord::moduleEnvironment): Deleted.
+        * runtime/PropertySlot.h:
+        (JSC::PropertySlot::PropertySlot):
+        (JSC::PropertySlot::domJIT):
+        (JSC::PropertySlot::moduleNamespaceSlot):
+        (JSC::PropertySlot::setValueModuleNamespace):
+        (JSC::PropertySlot::setCacheableCustom):
+
+2017-02-21  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
</ins><span class="cx">         ASSERTION FAILED: &quot;!scope.exception()&quot; with Object.isSealed/isFrozen and uninitialized module bindings
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=168605
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -2405,6 +2405,8 @@
</span><span class="cx">                 FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FEF040511AAE662D00BD28B0 /* CompareAndSwapTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */; };
</span><span class="cx">                 FEFD6FC61D5E7992008F2F0B /* JSStringInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FEFD6FC51D5E7970008F2F0B /* JSStringInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                321D9E4CFB67423A97F191A7 /* ModuleNamespaceAccessCase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 20ECB15EFC524624BC2F02D5 /* ModuleNamespaceAccessCase.cpp */; };
+                9F63434577274FAFB9336C38 /* ModuleNamespaceAccessCase.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CE978E385A8498199052153 /* ModuleNamespaceAccessCase.h */; };
</ins><span class="cx"> /* End PBXBuildFile section */
</span><span class="cx"> 
</span><span class="cx"> /* Begin PBXContainerItemProxy section */
</span><span class="lines">@@ -4966,6 +4968,8 @@
</span><span class="cx">                 FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompareAndSwapTest.cpp; path = API/tests/CompareAndSwapTest.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompareAndSwapTest.h; path = API/tests/CompareAndSwapTest.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 FEFD6FC51D5E7970008F2F0B /* JSStringInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                20ECB15EFC524624BC2F02D5 /* ModuleNamespaceAccessCase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleNamespaceAccessCase.cpp; path = ModuleNamespaceAccessCase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                4CE978E385A8498199052153 /* ModuleNamespaceAccessCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleNamespaceAccessCase.h; path = ModuleNamespaceAccessCase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx"> /* End PBXFileReference section */
</span><span class="cx"> 
</span><span class="cx"> /* Begin PBXFrameworksBuildPhase section */
</span><span class="lines">@@ -7499,6 +7503,8 @@
</span><span class="cx">                                 0F426A461460CBAB00131F8F /* VirtualRegister.h */,
</span><span class="cx">                                 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */,
</span><span class="cx">                                 0F919D2315853CDE004A4E7D /* Watchpoint.h */,
</span><ins>+                                20ECB15EFC524624BC2F02D5 /* ModuleNamespaceAccessCase.cpp */,
+                                4CE978E385A8498199052153 /* ModuleNamespaceAccessCase.h */,
</ins><span class="cx">                         );
</span><span class="cx">                         path = bytecode;
</span><span class="cx">                         sourceTree = &quot;&lt;group&gt;&quot;;
</span><span class="lines">@@ -9248,6 +9254,7 @@
</span><span class="cx">                                 86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */,
</span><span class="cx">                                 86704B8A12DBA33700A9FE7B /* YarrPattern.h in Headers */,
</span><span class="cx">                                 86704B4312DB8A8100A9FE7B /* YarrSyntaxChecker.h in Headers */,
</span><ins>+                                9F63434577274FAFB9336C38 /* ModuleNamespaceAccessCase.h in Headers */,
</ins><span class="cx">                         );
</span><span class="cx">                         runOnlyForDeploymentPostprocessing = 0;
</span><span class="cx">                 };
</span><span class="lines">@@ -10650,6 +10657,7 @@
</span><span class="cx">                                 86704B8612DBA33700A9FE7B /* YarrJIT.cpp in Sources */,
</span><span class="cx">                                 86704B8912DBA33700A9FE7B /* YarrPattern.cpp in Sources */,
</span><span class="cx">                                 86704B4212DB8A8100A9FE7B /* YarrSyntaxChecker.cpp in Sources */,
</span><ins>+                                321D9E4CFB67423A97F191A7 /* ModuleNamespaceAccessCase.cpp in Sources */,
</ins><span class="cx">                         );
</span><span class="cx">                         runOnlyForDeploymentPostprocessing = 0;
</span><span class="cx">                 };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeAccessCasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -37,7 +37,10 @@
</span><span class="cx"> #include &quot;HeapInlines.h&quot;
</span><span class="cx"> #include &quot;IntrinsicGetterAccessCase.h&quot;
</span><span class="cx"> #include &quot;JSCJSValueInlines.h&quot;
</span><ins>+#include &quot;JSModuleEnvironment.h&quot;
+#include &quot;JSModuleNamespaceObject.h&quot;
</ins><span class="cx"> #include &quot;LinkBuffer.h&quot;
</span><ins>+#include &quot;ModuleNamespaceAccessCase.h&quot;
</ins><span class="cx"> #include &quot;PolymorphicAccess.h&quot;
</span><span class="cx"> #include &quot;ScopedArguments.h&quot;
</span><span class="cx"> #include &quot;ScratchRegisterAllocator.h&quot;
</span><span class="lines">@@ -65,6 +68,7 @@
</span><span class="cx">     case StringLength:
</span><span class="cx">     case DirectArgumentsLength:
</span><span class="cx">     case ScopedArgumentsLength:
</span><ins>+    case ModuleNamespaceLoad:
</ins><span class="cx">     case Replace:
</span><span class="cx">         break;
</span><span class="cx">     default:
</span><span class="lines">@@ -148,6 +152,7 @@
</span><span class="cx">     case StringLength:
</span><span class="cx">     case DirectArgumentsLength:
</span><span class="cx">     case ScopedArgumentsLength:
</span><ins>+    case ModuleNamespaceLoad:
</ins><span class="cx">         return false;
</span><span class="cx">     default:
</span><span class="cx">         return true;
</span><span class="lines">@@ -193,6 +198,13 @@
</span><span class="cx">     case DirectArgumentsLength:
</span><span class="cx">     case ScopedArgumentsLength:
</span><span class="cx">         return other.type() == type();
</span><ins>+    case ModuleNamespaceLoad: {
+        if (other.type() != type())
+            return false;
+        auto&amp; thisCase = this-&gt;as&lt;ModuleNamespaceAccessCase&gt;();
+        auto&amp; otherCase = this-&gt;as&lt;ModuleNamespaceAccessCase&gt;();
+        return thisCase.moduleNamespaceObject() == otherCase.moduleNamespaceObject();
+    }
</ins><span class="cx">     default:
</span><span class="cx">         if (!guardedByStructureCheck() || !other.guardedByStructureCheck())
</span><span class="cx">             return false;
</span><span class="lines">@@ -239,6 +251,12 @@
</span><span class="cx">         auto&amp; intrinsic = this-&gt;as&lt;IntrinsicGetterAccessCase&gt;();
</span><span class="cx">         if (intrinsic.intrinsicFunction() &amp;&amp; !Heap::isMarked(intrinsic.intrinsicFunction()))
</span><span class="cx">             return false;
</span><ins>+    } else if (type() == ModuleNamespaceLoad) {
+        auto&amp; accessCase = this-&gt;as&lt;ModuleNamespaceAccessCase&gt;();
+        if (accessCase.moduleNamespaceObject() &amp;&amp; !Heap::isMarked(accessCase.moduleNamespaceObject()))
+            return false;
+        if (accessCase.moduleEnvironment() &amp;&amp; !Heap::isMarked(accessCase.moduleEnvironment()))
+            return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="lines">@@ -344,6 +362,11 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case ModuleNamespaceLoad: {
+        this-&gt;as&lt;ModuleNamespaceAccessCase&gt;().emit(state, fallThrough);
+        return;
+    }
+
</ins><span class="cx">     default: {
</span><span class="cx">         if (viaProxy()) {
</span><span class="cx">             fallThrough.append(
</span><span class="lines">@@ -991,6 +1014,7 @@
</span><span class="cx">         
</span><span class="cx">     case DirectArgumentsLength:
</span><span class="cx">     case ScopedArgumentsLength:
</span><ins>+    case ModuleNamespaceLoad:
</ins><span class="cx">         // These need to be handled by generateWithGuard(), since the guard is part of the
</span><span class="cx">         // algorithm. We can be sure that nobody will call generate() directly for these since they
</span><span class="cx">         // are not guarded by structure checks.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeAccessCaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/AccessCase.h (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/AccessCase.h        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/bytecode/AccessCase.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -95,7 +95,8 @@
</span><span class="cx">         ArrayLength,
</span><span class="cx">         StringLength,
</span><span class="cx">         DirectArgumentsLength,
</span><del>-        ScopedArgumentsLength
</del><ins>+        ScopedArgumentsLength,
+        ModuleNamespaceLoad,
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     enum State : uint8_t {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;JSScope.h&quot;
</span><span class="cx"> #include &quot;LLIntData.h&quot;
</span><span class="cx"> #include &quot;LowLevelInterpreter.h&quot;
</span><ins>+#include &quot;ModuleNamespaceAccessCase.h&quot;
</ins><span class="cx"> #include &quot;PolymorphicAccess.h&quot;
</span><span class="cx"> #include &quot;StructureStubInfo.h&quot;
</span><span class="cx"> #include &lt;wtf/ListDump.h&gt;
</span><span class="lines">@@ -43,6 +44,15 @@
</span><span class="cx"> class GetterSetter;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+GetByIdStatus::GetByIdStatus(const ModuleNamespaceAccessCase&amp; accessCase)
+    : m_state(ModuleNamespace)
+    , m_wasSeenInJIT(true)
+    , m_moduleNamespaceObject(accessCase.moduleNamespaceObject())
+    , m_moduleEnvironment(accessCase.moduleEnvironment())
+    , m_scopeOffset(accessCase.scopeOffset())
+{
+}
+
</ins><span class="cx"> bool GetByIdStatus::appendVariant(const GetByIdVariant&amp; variant)
</span><span class="cx"> {
</span><span class="cx">     // Attempt to merge this variant with an already existing variant.
</span><span class="lines">@@ -195,6 +205,16 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case CacheType::Stub: {
</span><ins>+        if (list-&gt;size() == 1) {
+            const AccessCase&amp; access = list-&gt;at(0);
+            switch (access.type()) {
+            case AccessCase::ModuleNamespaceLoad:
+                return GetByIdStatus(access.as&lt;ModuleNamespaceAccessCase&gt;());
+            default:
+                break;
+            }
+        }
+
</ins><span class="cx">         for (unsigned listIndex = 0; listIndex &lt; list-&gt;size(); ++listIndex) {
</span><span class="cx">             const AccessCase&amp; access = list-&gt;at(listIndex);
</span><span class="cx">             if (access.viaProxy())
</span><span class="lines">@@ -376,6 +396,7 @@
</span><span class="cx">     case NoInformation:
</span><span class="cx">     case TakesSlowPath:
</span><span class="cx">     case Custom:
</span><ins>+    case ModuleNamespace:
</ins><span class="cx">         return false;
</span><span class="cx">     case Simple:
</span><span class="cx">         for (unsigned i = m_variants.size(); i--;) {
</span><span class="lines">@@ -420,6 +441,9 @@
</span><span class="cx">     case Custom:
</span><span class="cx">         out.print(&quot;Custom&quot;);
</span><span class="cx">         break;
</span><ins>+    case ModuleNamespace:
+        out.print(&quot;ModuleNamespace&quot;);
+        break;
</ins><span class="cx">     case TakesSlowPath:
</span><span class="cx">         out.print(&quot;TakesSlowPath&quot;);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeGetByIdStatush"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.h (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.h        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -30,10 +30,15 @@
</span><span class="cx"> #include &quot;ConcurrentJSLock.h&quot;
</span><span class="cx"> #include &quot;ExitingJITType.h&quot;
</span><span class="cx"> #include &quot;GetByIdVariant.h&quot;
</span><ins>+#include &quot;ScopeOffset.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+class AccessCase;
</ins><span class="cx"> class CodeBlock;
</span><ins>+class JSModuleEnvironment;
+class JSModuleNamespaceObject;
+class ModuleNamespaceAccessCase;
</ins><span class="cx"> class StructureStubInfo;
</span><span class="cx"> 
</span><span class="cx"> typedef HashMap&lt;CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash&gt; StubInfoMap;
</span><span class="lines">@@ -41,12 +46,19 @@
</span><span class="cx"> class GetByIdStatus {
</span><span class="cx"> public:
</span><span class="cx">     enum State {
</span><del>-        NoInformation,  // It's uncached so we have no information.
-        Simple,         // It's cached for a simple access to a known object property with
-                        // a possible structure chain and a possible specific value.
-        Custom,         // It's cached for a custom accessor with a possible structure chain.
-        TakesSlowPath,  // It's known to often take slow path.
-        MakesCalls      // It's known to take paths that make calls.
</del><ins>+        // It's uncached so we have no information.
+        NoInformation,
+        // It's cached for a simple access to a known object property with
+        // a possible structure chain and a possible specific value.
+        Simple,
+        // It's cached for a custom accessor with a possible structure chain.
+        Custom,
+        // It's cached for an access to a module namespace object's binding.
+        ModuleNamespace,
+        // It's known to often take slow path.
+        TakesSlowPath,
+        // It's known to take paths that make calls.
+        MakesCalls,
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     GetByIdStatus()
</span><span class="lines">@@ -59,6 +71,8 @@
</span><span class="cx">     {
</span><span class="cx">         ASSERT(state == NoInformation || state == TakesSlowPath || state == MakesCalls);
</span><span class="cx">     }
</span><ins>+
+    GetByIdStatus(const ModuleNamespaceAccessCase&amp;);
</ins><span class="cx">     
</span><span class="cx">     GetByIdStatus(
</span><span class="cx">         State state, bool wasSeenInJIT, const GetByIdVariant&amp; variant = GetByIdVariant())
</span><span class="lines">@@ -84,6 +98,7 @@
</span><span class="cx">     bool operator!() const { return !isSet(); }
</span><span class="cx">     bool isSimple() const { return m_state == Simple; }
</span><span class="cx">     bool isCustom() const { return m_state == Custom; }
</span><ins>+    bool isModuleNamespace() const { return m_state == ModuleNamespace; }
</ins><span class="cx"> 
</span><span class="cx">     size_t numVariants() const { return m_variants.size(); }
</span><span class="cx">     const Vector&lt;GetByIdVariant, 1&gt;&amp; variants() const { return m_variants; }
</span><span class="lines">@@ -90,7 +105,7 @@
</span><span class="cx">     const GetByIdVariant&amp; at(size_t index) const { return m_variants[index]; }
</span><span class="cx">     const GetByIdVariant&amp; operator[](size_t index) const { return at(index); }
</span><span class="cx"> 
</span><del>-    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls || m_state == Custom; }
</del><ins>+    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls || m_state == Custom || m_state == ModuleNamespace; }
</ins><span class="cx">     bool makesCalls() const;
</span><span class="cx">     
</span><span class="cx">     bool wasSeenInJIT() const { return m_wasSeenInJIT; }
</span><span class="lines">@@ -97,6 +112,10 @@
</span><span class="cx">     
</span><span class="cx">     // Attempts to reduce the set of variants to fit the given structure set. This may be approximate.
</span><span class="cx">     void filter(const StructureSet&amp;);
</span><ins>+
+    JSModuleNamespaceObject* moduleNamespaceObject() const { return m_moduleNamespaceObject; }
+    JSModuleEnvironment* moduleEnvironment() const { return m_moduleEnvironment; }
+    ScopeOffset scopeOffset() const { return m_scopeOffset; }
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     
</span><span class="lines">@@ -116,6 +135,9 @@
</span><span class="cx">     State m_state;
</span><span class="cx">     Vector&lt;GetByIdVariant, 1&gt; m_variants;
</span><span class="cx">     bool m_wasSeenInJIT;
</span><ins>+    JSModuleNamespaceObject* m_moduleNamespaceObject { nullptr };
+    JSModuleEnvironment* m_moduleEnvironment { nullptr };
+    ScopeOffset m_scopeOffset { };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeModuleNamespaceAccessCasecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.cpp (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,84 @@
</span><ins>+/*
+ * Copyright (C) 2017 Yusuke Suzuki &lt;utatane.tea@gmail.com&gt;.
+ *
+ * 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 &quot;config.h&quot;
+#include &quot;ModuleNamespaceAccessCase.h&quot;
+
+#if ENABLE(JIT)
+
+#include &quot;CCallHelpers.h&quot;
+#include &quot;HeapInlines.h&quot;
+#include &quot;JSModuleEnvironment.h&quot;
+#include &quot;JSModuleNamespaceObject.h&quot;
+#include &quot;PolymorphicAccess.h&quot;
+#include &quot;StructureStubInfo.h&quot;
+
+namespace JSC {
+
+ModuleNamespaceAccessCase::ModuleNamespaceAccessCase(VM&amp; vm, JSCell* owner, JSModuleNamespaceObject* moduleNamespaceObject, JSModuleEnvironment* moduleEnvironment, ScopeOffset scopeOffset)
+    : Base(vm, owner, ModuleNamespaceLoad, invalidOffset, nullptr, ObjectPropertyConditionSet())
+    , m_scopeOffset(scopeOffset)
+{
+    m_moduleNamespaceObject.set(vm, owner, moduleNamespaceObject);
+    m_moduleEnvironment.set(vm, owner, moduleEnvironment);
+}
+
+std::unique_ptr&lt;AccessCase&gt; ModuleNamespaceAccessCase::create(VM&amp; vm, JSCell* owner, JSModuleNamespaceObject* moduleNamespaceObject, JSModuleEnvironment* moduleEnvironment, ScopeOffset scopeOffset)
+{
+    return std::unique_ptr&lt;AccessCase&gt;(new ModuleNamespaceAccessCase(vm, owner, moduleNamespaceObject, moduleEnvironment, scopeOffset));
+}
+
+ModuleNamespaceAccessCase::~ModuleNamespaceAccessCase()
+{
+}
+
+std::unique_ptr&lt;AccessCase&gt; ModuleNamespaceAccessCase::clone() const
+{
+    std::unique_ptr&lt;ModuleNamespaceAccessCase&gt; result(new ModuleNamespaceAccessCase(*this));
+    result-&gt;resetState();
+    return WTFMove(result);
+}
+
+void ModuleNamespaceAccessCase::emit(AccessGenerationState&amp; state, MacroAssembler::JumpList&amp; fallThrough)
+{
+    CCallHelpers&amp; jit = *state.jit;
+    JSValueRegs valueRegs = state.valueRegs;
+    GPRReg baseGPR = state.baseGPR;
+
+    fallThrough.append(
+        jit.branchPtr(
+            CCallHelpers::NotEqual,
+            baseGPR,
+            CCallHelpers::TrustedImmPtr(m_moduleNamespaceObject.get())));
+
+    jit.loadValue(&amp;m_moduleEnvironment-&gt;variableAt(m_scopeOffset), valueRegs);
+    state.failAndIgnore.append(jit.branchIfEmpty(valueRegs));
+    state.succeed();
+}
+
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeModuleNamespaceAccessCaseh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.h (0 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/ModuleNamespaceAccessCase.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+/*
+ * Copyright (C) 2017 Yusuke Suzuki &lt;utatane.tea@gmail.com&gt;.
+ *
+ * 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(JIT)
+
+#include &quot;AccessCase.h&quot;
+
+namespace JSC {
+
+class JSModuleEnvironment;
+class JSModuleNamespaceObject;
+
+class ModuleNamespaceAccessCase : public AccessCase {
+public:
+    using Base = AccessCase;
+    friend class AccessCase;
+
+    JSModuleNamespaceObject* moduleNamespaceObject() const { return m_moduleNamespaceObject.get(); }
+    JSModuleEnvironment* moduleEnvironment() const { return m_moduleEnvironment.get(); }
+    ScopeOffset scopeOffset() const { return m_scopeOffset; }
+
+    static std::unique_ptr&lt;AccessCase&gt; create(VM&amp;, JSCell* owner, JSModuleNamespaceObject*, JSModuleEnvironment*, ScopeOffset);
+
+    std::unique_ptr&lt;AccessCase&gt; clone() const override;
+
+    void emit(AccessGenerationState&amp;, MacroAssembler::JumpList&amp; fallThrough);
+
+    ~ModuleNamespaceAccessCase();
+
+private:
+    ModuleNamespaceAccessCase(VM&amp;, JSCell* owner, JSModuleNamespaceObject*, JSModuleEnvironment*, ScopeOffset);
+
+    WriteBarrier&lt;JSModuleNamespaceObject&gt; m_moduleNamespaceObject;
+    WriteBarrier&lt;JSModuleEnvironment&gt; m_moduleEnvironment;
+    ScopeOffset m_scopeOffset;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -645,6 +645,9 @@
</span><span class="cx">     case AccessCase::ScopedArgumentsLength:
</span><span class="cx">         out.print(&quot;ScopedArgumentsLength&quot;);
</span><span class="cx">         return;
</span><ins>+    case AccessCase::ModuleNamespaceLoad:
+        out.print(&quot;ModuleNamespaceLoad&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -46,6 +46,7 @@
</span><span class="cx"> #include &quot;Heap.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;JSModuleEnvironment.h&quot;
</span><ins>+#include &quot;JSModuleNamespaceObject.h&quot;
</ins><span class="cx"> #include &quot;NumberConstructor.h&quot;
</span><span class="cx"> #include &quot;ObjectConstructor.h&quot;
</span><span class="cx"> #include &quot;PreciseJumpTargets.h&quot;
</span><span class="lines">@@ -223,6 +224,7 @@
</span><span class="cx">     Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, const InferredType::Descriptor&amp;, Node* value);
</span><span class="cx">     Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, const InferredType::Descriptor&amp;, NodeType = GetByOffset);
</span><span class="cx">     bool handleDOMJITGetter(int resultOperand, const GetByIdVariant&amp;, Node* thisNode, unsigned identifierNumber, SpeculatedType prediction);
</span><ins>+    bool handleModuleNamespaceLoad(int resultOperand, SpeculatedType, Node* base, GetByIdStatus);
</ins><span class="cx"> 
</span><span class="cx">     // Create a presence ObjectPropertyCondition based on some known offset and structure set. Does not
</span><span class="cx">     // check the validity of the condition, but it may return a null one if it encounters a contradiction.
</span><span class="lines">@@ -2844,6 +2846,34 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ByteCodeParser::handleModuleNamespaceLoad(int resultOperand, SpeculatedType prediction, Node* base, GetByIdStatus getById)
+{
+    if (m_inlineStackTop-&gt;m_exitProfile.hasExitSite(m_currentIndex, BadCell))
+        return false;
+    addToGraph(CheckCell, OpInfo(m_graph.freeze(getById.moduleNamespaceObject())), Edge(base, CellUse));
+
+    // Ideally we wouldn't have to do this Phantom. But:
+    //
+    // For the constant case: we must do it because otherwise we would have no way of knowing
+    // that the scope is live at OSR here.
+    //
+    // For the non-constant case: GetClosureVar could be DCE'd, but baseline's implementation
+    // won't be able to handle an Undefined scope.
+    addToGraph(Phantom, base);
+
+    // Constant folding in the bytecode parser is important for performance. This may not
+    // have executed yet. If it hasn't, then we won't have a prediction. Lacking a
+    // prediction, we'd otherwise think that it has to exit. Then when it did execute, we
+    // would recompile. But if we can fold it here, we avoid the exit.
+    m_graph.freeze(getById.moduleEnvironment());
+    if (JSValue value = m_graph.tryGetConstantClosureVar(getById.moduleEnvironment(), getById.scopeOffset())) {
+        set(VirtualRegister(resultOperand), weakJSConstant(value));
+        return true;
+    }
+    set(VirtualRegister(resultOperand), addToGraph(GetClosureVar, OpInfo(getById.scopeOffset().offset()), OpInfo(prediction), weakJSConstant(getById.moduleEnvironment())));
+    return true;
+}
+
</ins><span class="cx"> template&lt;typename ChecksFunctor&gt;
</span><span class="cx"> bool ByteCodeParser::handleTypedArrayConstructor(
</span><span class="cx">     int resultOperand, InternalFunction* function, int registerOffset,
</span><span class="lines">@@ -3438,6 +3468,14 @@
</span><span class="cx">     else
</span><span class="cx">         getById = TryGetById;
</span><span class="cx"> 
</span><ins>+    if (getById != TryGetById &amp;&amp; getByIdStatus.isModuleNamespace()) {
+        if (handleModuleNamespaceLoad(destinationOperand, prediction, base, getByIdStatus)) {
+            if (m_graph.compilation())
+                m_graph.compilation()-&gt;noticeInlinedGetById();
+            return;
+        }
+    }
+
</ins><span class="cx">     // Special path for custom accessors since custom's offset does not have any meanings.
</span><span class="cx">     // So, this is completely different from Simple one. But we have a chance to optimize it when we use DOMJIT.
</span><span class="cx">     if (Options::useDOMJIT() &amp;&amp; getByIdStatus.isCustom()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -158,6 +158,16 @@
</span><span class="cx">         }
</span><span class="cx"> #endif
</span><span class="cx">     }
</span><ins>+
+    void loadValue(void* address, JSValueRegs regs)
+    {
+#if USE(JSVALUE64)
+        load64(address, regs.gpr());
+#else
+        load32(bitwise_cast&lt;void*&gt;(bitwise_cast&lt;uintptr_t&gt;(address) + PayloadOffset), regs.payloadGPR());
+        load32(bitwise_cast&lt;void*&gt;(bitwise_cast&lt;uintptr_t&gt;(address) + TagOffset), regs.tagGPR());
+#endif
+    }
</ins><span class="cx">     
</span><span class="cx">     // Note that this clobbers offset.
</span><span class="cx">     void loadProperty(GPRReg object, GPRReg offset, JSValueRegs result);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/Repatch.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/Repatch.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/jit/Repatch.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -46,8 +46,10 @@
</span><span class="cx"> #include &quot;JIT.h&quot;
</span><span class="cx"> #include &quot;JITInlines.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><ins>+#include &quot;JSModuleNamespaceObject.h&quot;
</ins><span class="cx"> #include &quot;JSWebAssembly.h&quot;
</span><span class="cx"> #include &quot;LinkBuffer.h&quot;
</span><ins>+#include &quot;ModuleNamespaceAccessCase.h&quot;
</ins><span class="cx"> #include &quot;PolymorphicAccess.h&quot;
</span><span class="cx"> #include &quot;ScopedArguments.h&quot;
</span><span class="cx"> #include &quot;ScratchRegisterAllocator.h&quot;
</span><span class="lines">@@ -192,6 +194,11 @@
</span><span class="cx">                 newCase = AccessCase::create(vm, codeBlock, AccessCase::ScopedArgumentsLength);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    if (!propertyName.isSymbol() &amp;&amp; isJSModuleNamespaceObject(baseValue) &amp;&amp; !slot.isUnset()) {
+        if (auto moduleNamespaceSlot = slot.moduleNamespaceSlot())
+            newCase = ModuleNamespaceAccessCase::create(vm, codeBlock, jsCast&lt;JSModuleNamespaceObject*&gt;(baseValue), moduleNamespaceSlot-&gt;environment, ScopeOffset(moduleNamespaceSlot-&gt;scopeOffset));
+    }
</ins><span class="cx">     
</span><span class="cx">     if (!newCase) {
</span><span class="cx">         if (!slot.isCacheable() &amp;&amp; !slot.isUnset())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeAbstractModuleRecordcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -697,9 +697,10 @@
</span><span class="cx">     IdentifierSet exportedNames;
</span><span class="cx">     getExportedNames(exec, this, exportedNames);
</span><span class="cx"> 
</span><del>-    IdentifierSet unambiguousNames;
</del><ins>+    Vector&lt;std::pair&lt;Identifier, Resolution&gt;&gt; resolutions;
</ins><span class="cx">     for (auto&amp; name : exportedNames) {
</span><del>-        const AbstractModuleRecord::Resolution resolution = resolveExport(exec, Identifier::fromUid(exec, name.get()));
</del><ins>+        Identifier ident = Identifier::fromUid(exec, name.get());
+        const Resolution resolution = resolveExport(exec, ident);
</ins><span class="cx">         switch (resolution.type) {
</span><span class="cx">         case Resolution::Type::NotFound:
</span><span class="cx">             throwSyntaxError(exec, scope, makeString(&quot;Exported binding name '&quot;, String(name.get()), &quot;' is not found.&quot;));
</span><span class="lines">@@ -713,12 +714,12 @@
</span><span class="cx">             break;
</span><span class="cx"> 
</span><span class="cx">         case Resolution::Type::Resolved:
</span><del>-            unambiguousNames.add(name);
</del><ins>+            resolutions.append({ WTFMove(ident), resolution });
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_moduleNamespaceObject.set(vm, this, JSModuleNamespaceObject::create(exec, globalObject, globalObject-&gt;moduleNamespaceObjectStructure(), this, unambiguousNames));
</del><ins>+    m_moduleNamespaceObject.set(vm, this, JSModuleNamespaceObject::create(exec, globalObject, globalObject-&gt;moduleNamespaceObjectStructure(), this, WTFMove(resolutions)));
</ins><span class="cx">     return m_moduleNamespaceObject.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSModuleNamespaceObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSModuleNamespaceObject::finishCreation(ExecState* exec, JSGlobalObject*, AbstractModuleRecord* moduleRecord, const IdentifierSet&amp; exports)
</del><ins>+void JSModuleNamespaceObject::finishCreation(ExecState* exec, JSGlobalObject*, AbstractModuleRecord* moduleRecord, Vector&lt;std::pair&lt;Identifier, AbstractModuleRecord::Resolution&gt;&gt;&amp;&amp; resolutions)
</ins><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="lines">@@ -54,17 +54,25 @@
</span><span class="cx">     //     The list is ordered as if an Array of those String values had been sorted using Array.prototype.sort using SortCompare as comparefn.
</span><span class="cx">     //
</span><span class="cx">     // Sort the exported names by the code point order.
</span><del>-    Vector&lt;UniquedStringImpl*&gt; temporaryVector(exports.size(), nullptr);
-    std::transform(exports.begin(), exports.end(), temporaryVector.begin(), [](const RefPtr&lt;WTF::UniquedStringImpl&gt;&amp; ref) {
-        return ref.get();
</del><ins>+    std::sort(resolutions.begin(), resolutions.end(), [] (const auto&amp; lhs, const auto&amp; rhs) {
+        return codePointCompare(lhs.first.impl(), rhs.first.impl()) &lt; 0;
</ins><span class="cx">     });
</span><del>-    std::sort(temporaryVector.begin(), temporaryVector.end(), [] (UniquedStringImpl* lhs, UniquedStringImpl* rhs) {
-        return codePointCompare(lhs, rhs) &lt; 0;
-    });
-    for (auto* identifier : temporaryVector)
-        m_exports.add(identifier);
</del><span class="cx"> 
</span><span class="cx">     m_moduleRecord.set(vm, this, moduleRecord);
</span><ins>+    {
+        unsigned moduleRecordOffset = 0;
+        m_names.reserveCapacity(resolutions.size());
+        for (const auto&amp; pair : resolutions) {
+            moduleRecordAt(moduleRecordOffset).set(vm, this, pair.second.moduleRecord);
+            m_names.append(pair.first);
+            m_exports.add(pair.first.impl(), ExportEntry {
+                pair.second.localName,
+                moduleRecordOffset
+            });
+            ++moduleRecordOffset;
+        }
+    }
+
</ins><span class="cx">     putDirect(vm, vm.propertyNames-&gt;toStringTagSymbol, jsString(&amp;vm, &quot;Module&quot;), DontEnum | DontDelete | ReadOnly);
</span><span class="cx"> 
</span><span class="cx">     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getprototypeof
</span><span class="lines">@@ -87,8 +95,24 @@
</span><span class="cx">     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
</span><span class="cx">     Base::visitChildren(thisObject, visitor);
</span><span class="cx">     visitor.append(thisObject-&gt;m_moduleRecord);
</span><ins>+    for (unsigned i = 0; i &lt; thisObject-&gt;m_names.size(); ++i)
+        visitor.appendHidden(thisObject-&gt;moduleRecordAt(i));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static JSValue getValue(JSModuleEnvironment* environment, PropertyName localName, ScopeOffset&amp; scopeOffset)
+{
+    SymbolTable* symbolTable = environment-&gt;symbolTable();
+    {
+        ConcurrentJSLocker locker(symbolTable-&gt;m_lock);
+        auto iter = symbolTable-&gt;find(locker, localName.uid());
+        ASSERT(iter != symbolTable-&gt;end(locker));
+        SymbolTableEntry&amp; entry = iter-&gt;value;
+        ASSERT(!entry.isNull());
+        scopeOffset = entry.scopeOffset();
+    }
+    return environment-&gt;variableAt(scopeOffset).get();
+}
+
</ins><span class="cx"> bool JSModuleNamespaceObject::getOwnPropertySlot(JSObject* cell, ExecState* exec, PropertyName propertyName, PropertySlot&amp; slot)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span><span class="lines">@@ -104,31 +128,19 @@
</span><span class="cx">     if (propertyName.isSymbol())
</span><span class="cx">         return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
</span><span class="cx"> 
</span><del>-    // FIXME: Add IC for module namespace object.
-    // https://bugs.webkit.org/show_bug.cgi?id=160590
-    slot.disableCaching();
</del><span class="cx">     slot.setIsTaintedByOpaqueObject();
</span><del>-    if (!thisObject-&gt;m_exports.contains(propertyName.uid()))
</del><ins>+
+    auto iterator = thisObject-&gt;m_exports.find(propertyName.uid());
+    if (iterator == thisObject-&gt;m_exports.end())
</ins><span class="cx">         return false;
</span><ins>+    ExportEntry&amp; exportEntry = iterator-&gt;value;
</ins><span class="cx"> 
</span><span class="cx">     switch (slot.internalMethodType()) {
</span><del>-    case PropertySlot::InternalMethodType::Get:
-    case PropertySlot::InternalMethodType::GetOwnProperty: {
-        AbstractModuleRecord* moduleRecord = thisObject-&gt;moduleRecord();
-
-        AbstractModuleRecord::Resolution resolution = moduleRecord-&gt;resolveExport(exec, Identifier::fromUid(exec, propertyName.uid()));
-        ASSERT(resolution.type != AbstractModuleRecord::Resolution::Type::NotFound &amp;&amp; resolution.type != AbstractModuleRecord::Resolution::Type::Ambiguous);
-
-        AbstractModuleRecord* targetModule = resolution.moduleRecord;
-        JSModuleEnvironment* targetEnvironment = targetModule-&gt;moduleEnvironment();
-
-        PropertySlot trampolineSlot(targetEnvironment, PropertySlot::InternalMethodType::Get);
-        bool found = targetEnvironment-&gt;methodTable(vm)-&gt;getOwnPropertySlot(targetEnvironment, exec, resolution.localName, trampolineSlot);
-        ASSERT_UNUSED(found, found);
-
-        JSValue value = trampolineSlot.getValue(exec, propertyName);
-        ASSERT(!scope.exception());
-
</del><ins>+    case PropertySlot::InternalMethodType::GetOwnProperty:
+    case PropertySlot::InternalMethodType::Get: {
+        JSModuleEnvironment* environment = thisObject-&gt;moduleRecordAt(exportEntry.moduleRecordOffset)-&gt;moduleEnvironment();
+        ScopeOffset scopeOffset;
+        JSValue value = getValue(environment, exportEntry.localName, scopeOffset);
</ins><span class="cx">         // If the value is filled with TDZ value, throw a reference error.
</span><span class="cx">         if (!value) {
</span><span class="cx">             throwVMError(exec, scope, createTDZError(exec));
</span><span class="lines">@@ -135,9 +147,10 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        slot.setValue(thisObject, DontDelete, value);
</del><ins>+        slot.setValueModuleNamespace(thisObject, DontDelete, value, environment, scopeOffset);
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     case PropertySlot::InternalMethodType::HasProperty: {
</span><span class="cx">         // Do not perform [[Get]] for [[HasProperty]].
</span><span class="cx">         // [[Get]] / [[GetOwnProperty]] onto namespace object could throw an error while [[HasProperty]] just returns true here.
</span><span class="lines">@@ -189,8 +202,8 @@
</span><span class="cx"> {
</span><span class="cx">     // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-ownpropertykeys
</span><span class="cx">     JSModuleNamespaceObject* thisObject = jsCast&lt;JSModuleNamespaceObject*&gt;(cell);
</span><del>-    for (const auto&amp; name : thisObject-&gt;m_exports)
-        propertyNames.add(name.get());
</del><ins>+    for (const auto&amp; name : thisObject-&gt;m_names)
+        propertyNames.add(name.impl());
</ins><span class="cx">     return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSModuleNamespaceObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -25,22 +25,25 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include &quot;AbstractModuleRecord.h&quot;
</ins><span class="cx"> #include &quot;JSDestructibleObject.h&quot;
</span><del>-#include &lt;wtf/ListHashSet.h&gt;
</del><ins>+#include &quot;ScopeOffset.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-class AbstractModuleRecord;
-
-class JSModuleNamespaceObject : public JSDestructibleObject {
</del><ins>+class JSModuleNamespaceObject final : public JSDestructibleObject {
</ins><span class="cx"> public:
</span><span class="cx">     typedef JSDestructibleObject Base;
</span><span class="cx">     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | GetOwnPropertySlotIsImpureForPropertyAbsence | IsImmutablePrototypeExoticObject;
</span><span class="cx"> 
</span><del>-    static JSModuleNamespaceObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, AbstractModuleRecord* moduleRecord, const IdentifierSet&amp; exports)
</del><ins>+    static JSModuleNamespaceObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, AbstractModuleRecord* moduleRecord, Vector&lt;std::pair&lt;Identifier, AbstractModuleRecord::Resolution&gt;&gt;&amp;&amp; resolutions)
</ins><span class="cx">     {
</span><del>-        JSModuleNamespaceObject* object = new (NotNull, allocateCell&lt;JSModuleNamespaceObject&gt;(exec-&gt;vm().heap)) JSModuleNamespaceObject(exec-&gt;vm(), structure);
-        object-&gt;finishCreation(exec, globalObject, moduleRecord, exports);
</del><ins>+        JSModuleNamespaceObject* object =
+            new (
+                NotNull,
+                allocateCell&lt;JSModuleNamespaceObject&gt;(exec-&gt;vm().heap, JSModuleNamespaceObject::allocationSize(resolutions.size())))
+            JSModuleNamespaceObject(exec-&gt;vm(), structure);
+        object-&gt;finishCreation(exec, globalObject, moduleRecord, WTFMove(resolutions));
</ins><span class="cx">         return object;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -61,7 +64,7 @@
</span><span class="cx">     AbstractModuleRecord* moduleRecord() { return m_moduleRecord.get(); }
</span><span class="cx"> 
</span><span class="cx"> protected:
</span><del>-    JS_EXPORT_PRIVATE void finishCreation(ExecState*, JSGlobalObject*, AbstractModuleRecord*, const IdentifierSet&amp; exports);
</del><ins>+    JS_EXPORT_PRIVATE void finishCreation(ExecState*, JSGlobalObject*, AbstractModuleRecord*, Vector&lt;std::pair&lt;Identifier, AbstractModuleRecord::Resolution&gt;&gt;&amp;&amp;);
</ins><span class="cx">     JS_EXPORT_PRIVATE JSModuleNamespaceObject(VM&amp;, Structure*);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="lines">@@ -68,10 +71,43 @@
</span><span class="cx">     static void destroy(JSCell*);
</span><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><span class="cx"> 
</span><del>-    typedef WTF::ListHashSet&lt;RefPtr&lt;UniquedStringImpl&gt;, IdentifierRepHash&gt; OrderedIdentifierSet;
</del><ins>+    WriteBarrierBase&lt;AbstractModuleRecord&gt;&amp; moduleRecordAt(unsigned offset)
+    {
+        return moduleRecords()[offset];
+    }
</ins><span class="cx"> 
</span><del>-    OrderedIdentifierSet m_exports;
</del><ins>+    WriteBarrierBase&lt;AbstractModuleRecord&gt;* moduleRecords()
+    {
+        return bitwise_cast&lt;WriteBarrierBase&lt;AbstractModuleRecord&gt;*&gt;(bitwise_cast&lt;char*&gt;(this) + offsetOfModuleRecords());
+    }
+
+    static size_t offsetOfModuleRecords()
+    {
+        return WTF::roundUpToMultipleOf&lt;sizeof(WriteBarrier&lt;AbstractModuleRecord&gt;)&gt;(sizeof(JSModuleNamespaceObject));
+    }
+
+    static size_t allocationSize(unsigned moduleRecords)
+    {
+        return offsetOfModuleRecords() + moduleRecords * sizeof(WriteBarrier&lt;AbstractModuleRecord&gt;);
+    }
+
+    struct ExportEntry {
+        Identifier localName;
+        unsigned moduleRecordOffset;
+    };
+
+    typedef HashMap&lt;RefPtr&lt;UniquedStringImpl&gt;, ExportEntry, IdentifierRepHash, HashTraits&lt;RefPtr&lt;UniquedStringImpl&gt;&gt;&gt; ExportMap;
+
+    ExportMap m_exports;
+    Vector&lt;Identifier&gt; m_names;
</ins><span class="cx">     WriteBarrier&lt;AbstractModuleRecord&gt; m_moduleRecord;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+inline bool isJSModuleNamespaceObject(JSCell* cell)
+{
+    return cell-&gt;classInfo(*cell-&gt;vm()) == JSModuleNamespaceObject::info();
+}
+
+inline bool isJSModuleNamespaceObject(JSValue v) { return v.isCell() &amp;&amp; isJSModuleNamespaceObject(v.asCell()); }
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSModuleRecordh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSModuleRecord.h (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSModuleRecord.h        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/runtime/JSModuleRecord.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -40,11 +40,6 @@
</span><span class="cx"> 
</span><span class="cx">     DECLARE_EXPORT_INFO;
</span><span class="cx"> 
</span><del>-    JSModuleEnvironment* moduleEnvironment()
-    {
-        ASSERT(m_moduleEnvironment);
-        return m_moduleEnvironment.get();
-    }
</del><span class="cx">     static Structure* createStructure(VM&amp;, JSGlobalObject*, JSValue);
</span><span class="cx">     static JSModuleRecord* create(ExecState*, VM&amp;, Structure*, const Identifier&amp;, const SourceCode&amp;, const VariableEnvironment&amp;, const VariableEnvironment&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimePropertySloth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/PropertySlot.h (212711 => 212712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/PropertySlot.h        2017-02-21 10:37:31 UTC (rev 212711)
+++ trunk/Source/JavaScriptCore/runtime/PropertySlot.h        2017-02-21 10:38:58 UTC (rev 212712)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><span class="cx"> #include &quot;PropertyName.h&quot;
</span><span class="cx"> #include &quot;PropertyOffset.h&quot;
</span><ins>+#include &quot;ScopeOffset.h&quot;
</ins><span class="cx"> #include &lt;wtf/Assertions.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -32,6 +33,7 @@
</span><span class="cx"> class ExecState;
</span><span class="cx"> class GetterSetter;
</span><span class="cx"> class JSObject;
</span><ins>+class JSModuleEnvironment;
</ins><span class="cx"> 
</span><span class="cx"> // ECMA 262-3 8.6.1
</span><span class="cx"> // Property attributes
</span><span class="lines">@@ -86,6 +88,12 @@
</span><span class="cx">         VMInquiry, // Our VM is just poking around. When this is the InternalMethodType, getOwnPropertySlot is not allowed to do user observable actions.
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    enum class AdditionalDataType : uint8_t {
+        None,
+        DOMJIT, // Annotated with DOMJIT information.
+        ModuleNamespace, // ModuleNamespaceObject's environment access.
+    };
+
</ins><span class="cx">     explicit PropertySlot(const JSValue thisValue, InternalMethodType internalMethodType)
</span><span class="cx">         : m_offset(invalidOffset)
</span><span class="cx">         , m_thisValue(thisValue)
</span><span class="lines">@@ -94,6 +102,7 @@
</span><span class="cx">         , m_cacheability(CachingAllowed)
</span><span class="cx">         , m_propertyType(TypeUnset)
</span><span class="cx">         , m_internalMethodType(internalMethodType)
</span><ins>+        , m_additionalDataType(AdditionalDataType::None)
</ins><span class="cx">         , m_isTaintedByOpaqueObject(false)
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="lines">@@ -163,9 +172,23 @@
</span><span class="cx"> 
</span><span class="cx">     DOMJIT::GetterSetter* domJIT() const
</span><span class="cx">     {
</span><del>-        return m_domJIT;
</del><ins>+        if (m_additionalDataType == AdditionalDataType::DOMJIT)
+            return m_additionalData.domJIT;
+        return nullptr;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    struct ModuleNamespaceSlot {
+        JSModuleEnvironment* environment;
+        unsigned scopeOffset;
+    };
+
+    std::optional&lt;ModuleNamespaceSlot&gt; moduleNamespaceSlot() const
+    {
+        if (m_additionalDataType == AdditionalDataType::ModuleNamespace)
+            return m_additionalData.moduleNamespaceSlot;
+        return std::nullopt;
+    }
+
</ins><span class="cx">     void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(attributes == attributesForStructure(attributes));
</span><span class="lines">@@ -206,6 +229,14 @@
</span><span class="cx">         m_offset = invalidOffset;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void setValueModuleNamespace(JSObject* slotBase, unsigned attributes, JSValue value, JSModuleEnvironment* environment, ScopeOffset scopeOffset)
+    {
+        setValue(slotBase, attributes, value);
+        m_additionalDataType = AdditionalDataType::ModuleNamespace;
+        m_additionalData.moduleNamespaceSlot.environment = environment;
+        m_additionalData.moduleNamespaceSlot.scopeOffset = scopeOffset.offset();
+    }
+
</ins><span class="cx">     void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(attributes == attributesForStructure(attributes));
</span><span class="lines">@@ -220,7 +251,7 @@
</span><span class="cx">         m_offset = invalidOffset;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue, DOMJIT::GetterSetter* domJIT = nullptr)
</del><ins>+    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(attributes == attributesForStructure(attributes));
</span><span class="cx">         
</span><span class="lines">@@ -232,9 +263,17 @@
</span><span class="cx">         m_slotBase = slotBase;
</span><span class="cx">         m_propertyType = TypeCustom;
</span><span class="cx">         m_offset = !invalidOffset;
</span><del>-        m_domJIT = domJIT;
</del><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue, DOMJIT::GetterSetter* domJIT)
+    {
+        setCacheableCustom(slotBase, attributes, getValue);
+        if (domJIT) {
+            m_additionalDataType = AdditionalDataType::DOMJIT;
+            m_additionalData.domJIT = domJIT;
+        }
+    }
+
</ins><span class="cx">     void setCustomGetterSetter(JSObject* slotBase, unsigned attributes, CustomGetterSetter* getterSetter)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(attributes == attributesForStructure(attributes));
</span><span class="lines">@@ -328,7 +367,11 @@
</span><span class="cx">     CacheabilityType m_cacheability;
</span><span class="cx">     PropertyType m_propertyType;
</span><span class="cx">     InternalMethodType m_internalMethodType;
</span><del>-    DOMJIT::GetterSetter* m_domJIT { nullptr };
</del><ins>+    AdditionalDataType m_additionalDataType;
+    union {
+        DOMJIT::GetterSetter* domJIT;
+        ModuleNamespaceSlot moduleNamespaceSlot;
+    } m_additionalData;
</ins><span class="cx">     bool m_isTaintedByOpaqueObject;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>