<!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>[210047] trunk/Source/JavaScriptCore</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/210047">210047</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-12-20 16:29:36 -0800 (Tue, 20 Dec 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebAssembly: We should compile wasm functions in parallel
https://bugs.webkit.org/show_bug.cgi?id=165993

Reviewed by Keith Miller.

This patch adds a very simple parallel compiler for Wasm code.
This patch speeds up compiling the Unity headless benchmark by
slightly more than 4x on my MBP. To make this safe, I perform
all linking on the main thread. I also had to change some code
inside Wasmb3IRGenerator to be thread safe.

* b3/air/AirCustom.h:
(JSC::B3::Air::WasmBoundsCheckCustom::generate):
* b3/air/AirGenerationContext.h:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::emitExceptionCheck):
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::parseAndCompile):
* wasm/WasmB3IRGenerator.h:
* wasm/WasmCallingConvention.h:
(JSC::Wasm::CallingConvention::setupFrameInPrologue):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::parseAndValidateModule):
(JSC::Wasm::Plan::run):
* wasm/WasmPlan.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCustomh">trunk/Source/JavaScriptCore/b3/air/AirCustom.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirGenerationContexth">trunk/Source/JavaScriptCore/b3/air/AirGenerationContext.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmB3IRGeneratorh">trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmCallingConventionh">trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmPlancpp">trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmPlanh">trunk/Source/JavaScriptCore/wasm/WasmPlan.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2016-12-20  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        WebAssembly: We should compile wasm functions in parallel
+        https://bugs.webkit.org/show_bug.cgi?id=165993
+
+        Reviewed by Keith Miller.
+
+        This patch adds a very simple parallel compiler for Wasm code.
+        This patch speeds up compiling the Unity headless benchmark by
+        slightly more than 4x on my MBP. To make this safe, I perform
+        all linking on the main thread. I also had to change some code
+        inside Wasmb3IRGenerator to be thread safe.
+
+        * b3/air/AirCustom.h:
+        (JSC::B3::Air::WasmBoundsCheckCustom::generate):
+        * b3/air/AirGenerationContext.h:
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+        (JSC::Wasm::B3IRGenerator::emitExceptionCheck):
+        (JSC::Wasm::createJSToWasmWrapper):
+        (JSC::Wasm::parseAndCompile):
+        * wasm/WasmB3IRGenerator.h:
+        * wasm/WasmCallingConvention.h:
+        (JSC::Wasm::CallingConvention::setupFrameInPrologue):
+        * wasm/WasmPlan.cpp:
+        (JSC::Wasm::Plan::parseAndValidateModule):
+        (JSC::Wasm::Plan::run):
+        * wasm/WasmPlan.h:
+
</ins><span class="cx"> 2016-12-20  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Address some style problems found by static analysis
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCustomh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCustom.h (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCustom.h        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/b3/air/AirCustom.h        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -313,7 +313,7 @@
</span><span class="cx">         CCallHelpers::Jump outOfBounds = Inst(Air::Branch64, value, Arg::relCond(CCallHelpers::AboveOrEqual), inst.args[0], inst.args[1]).generate(jit, context);
</span><span class="cx"> 
</span><span class="cx">         context.latePaths.append(createSharedTask&lt;GenerationContext::LatePathFunction&gt;(
</span><del>-            [=] (CCallHelpers&amp; jit, Air::GenerationContext&amp;) {
</del><ins>+            [outOfBounds, value] (CCallHelpers&amp; jit, Air::GenerationContext&amp; context) {
</ins><span class="cx">                 outOfBounds.link(&amp;jit);
</span><span class="cx">                 context.code-&gt;wasmBoundsCheckGenerator()-&gt;run(jit, value-&gt;pinnedGPR(), value-&gt;offset());
</span><span class="cx">             }));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirGenerationContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirGenerationContext.h (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirGenerationContext.h        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/b3/air/AirGenerationContext.h        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -39,6 +39,11 @@
</span><span class="cx"> class Code;
</span><span class="cx"> 
</span><span class="cx"> struct GenerationContext {
</span><ins>+    WTF_MAKE_NONCOPYABLE(GenerationContext);
+public:
+
+    GenerationContext() = default;
+
</ins><span class="cx">     typedef void LatePathFunction(CCallHelpers&amp;, GenerationContext&amp;);
</span><span class="cx">     typedef SharedTask&lt;LatePathFunction&gt; LatePath;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -257,12 +257,6 @@
</span><span class="cx">             ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
</span><span class="cx">             this-&gt;emitExceptionCheck(jit, ExceptionType::OutOfBoundsMemoryAccess);
</span><span class="cx">         });
</span><del>-
-        B3::PatchpointValue* foo = m_currentBlock-&gt;appendNew&lt;B3::PatchpointValue&gt;(m_proc, B3::Void, Origin());
-        foo-&gt;setGenerator(
-            [=] (CCallHelpers&amp; jit, const B3::StackmapGenerationParams&amp;) {
-                AllowMacroScratchRegisterUsage allowScratch(jit);
-            });
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     wasmCallingConvention().setupFrameInPrologue(&amp;compilation-&gt;wasmCalleeMoveLocation, m_proc, Origin(), m_currentBlock);
</span><span class="lines">@@ -277,7 +271,7 @@
</span><span class="cx">     auto jumpToExceptionStub = jit.jump();
</span><span class="cx"> 
</span><span class="cx">     VM* vm = &amp;m_vm;
</span><del>-    jit.addLinkTask([=] (LinkBuffer&amp; linkBuffer) {
</del><ins>+    jit.addLinkTask([vm, jumpToExceptionStub] (LinkBuffer&amp; linkBuffer) {
</ins><span class="cx">         linkBuffer.link(jumpToExceptionStub, CodeLocationLabel(vm-&gt;getCTIStub(throwExceptionFromWasmThunkGenerator).code()));
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="lines">@@ -691,13 +685,14 @@
</span><span class="cx">             patchpoint-&gt;effects.writesPinned = true;
</span><span class="cx">             patchpoint-&gt;effects.readsPinned = true;
</span><span class="cx"> 
</span><del>-            patchpoint-&gt;setGenerator([=] (CCallHelpers&amp; jit, const B3::StackmapGenerationParams&amp;) {
</del><ins>+            Vector&lt;UnlinkedWasmToWasmCall&gt;* unlinkedWasmToWasmCalls = &amp;m_unlinkedWasmToWasmCalls;
+            patchpoint-&gt;setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers&amp; jit, const B3::StackmapGenerationParams&amp;) {
</ins><span class="cx">                 AllowMacroScratchRegisterUsage allowScratch(jit);
</span><span class="cx"> 
</span><span class="cx">                 CCallHelpers::Call call = jit.call();
</span><span class="cx"> 
</span><del>-                jit.addLinkTask([=] (LinkBuffer&amp; linkBuffer) {
-                    m_unlinkedWasmToWasmCalls.append({ linkBuffer.locationOf(call), functionIndex });
</del><ins>+                jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer&amp; linkBuffer) {
+                    unlinkedWasmToWasmCalls-&gt;append({ linkBuffer.locationOf(call), functionIndex });
</ins><span class="cx">                 });
</span><span class="cx">             });
</span><span class="cx">         });
</span><span class="lines">@@ -819,7 +814,7 @@
</span><span class="cx">     dataLogLn(&quot;\n&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static std::unique_ptr&lt;B3::Compilation&gt; createJSToWasmWrapper(VM&amp; vm, WasmInternalFunction&amp; function, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation&amp; memory)
</del><ins>+static void createJSToWasmWrapper(VM&amp; vm, CompilationContext&amp; compilationContext, WasmInternalFunction&amp; function, const Signature* signature, const MemoryInformation&amp; memory)
</ins><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="cx">     BasicBlock* block = proc.addBlock();
</span><span class="lines">@@ -876,13 +871,12 @@
</span><span class="cx">                 patchpoint-&gt;append(ConstrainedValue(sizes[i], ValueRep::reg(memory.pinnedRegisters().sizeRegisters[i].sizeRegister)));
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        patchpoint-&gt;setGenerator([=] (CCallHelpers&amp; jit, const B3::StackmapGenerationParams&amp;) {
</del><ins>+        CompilationContext* context = &amp;compilationContext;
+        patchpoint-&gt;setGenerator([context] (CCallHelpers&amp; jit, const B3::StackmapGenerationParams&amp;) {
</ins><span class="cx">             AllowMacroScratchRegisterUsage allowScratch(jit);
</span><span class="cx"> 
</span><span class="cx">             CCallHelpers::Call call = jit.call();
</span><del>-            jit.addLinkTask([=] (LinkBuffer&amp; linkBuffer) {
-                linkBuffer.link(call, FunctionPtr(mainFunction.executableAddress()));
-            });
</del><ins>+            context-&gt;jsEntrypointToWasmEntrypointCall = call;
</ins><span class="cx">         });
</span><span class="cx">     });
</span><span class="cx"> 
</span><span class="lines">@@ -904,15 +898,19 @@
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto jsEntrypoint = std::make_unique&lt;Compilation&gt;(B3::compile(vm, proc));
</del><ins>+    B3::prepareForGeneration(proc);
+    B3::generate(proc, *compilationContext.jsEntrypointJIT);
+    compilationContext.jsEntrypointByproducts = proc.releaseByproducts();
</ins><span class="cx">     function.jsToWasmEntrypoint.calleeSaveRegisters = proc.calleeSaveRegisters();
</span><del>-    return jsEntrypoint;
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-Expected&lt;std::unique_ptr&lt;WasmInternalFunction&gt;, String&gt; parseAndCompile(VM&amp; vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector&lt;UnlinkedWasmToWasmCall&gt;&amp; unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace&amp; functionIndexSpace, const ModuleInformation&amp; info, unsigned optLevel)
</del><ins>+Expected&lt;std::unique_ptr&lt;WasmInternalFunction&gt;, String&gt; parseAndCompile(VM&amp; vm, CompilationContext&amp; compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector&lt;UnlinkedWasmToWasmCall&gt;&amp; unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace&amp; functionIndexSpace, const ModuleInformation&amp; info, unsigned optLevel)
</ins><span class="cx"> {
</span><span class="cx">     auto result = std::make_unique&lt;WasmInternalFunction&gt;();
</span><span class="cx"> 
</span><ins>+    compilationContext.jsEntrypointJIT = std::make_unique&lt;CCallHelpers&gt;(&amp;vm);
+    compilationContext.wasmEntrypointJIT = std::make_unique&lt;CCallHelpers&gt;(&amp;vm);
+
</ins><span class="cx">     Procedure procedure;
</span><span class="cx">     B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
</span><span class="cx">     FunctionParser&lt;B3IRGenerator&gt; parser(&amp;vm, context, functionStart, functionLength, signature, functionIndexSpace, info);
</span><span class="lines">@@ -927,10 +925,14 @@
</span><span class="cx">     if (verbose)
</span><span class="cx">         dataLog(&quot;Post SSA: &quot;, procedure);
</span><span class="cx"> 
</span><del>-    result-&gt;wasmEntrypoint.compilation = std::make_unique&lt;B3::Compilation&gt;(B3::compile(vm, procedure, optLevel));
-    result-&gt;wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
</del><ins>+    {
+        B3::prepareForGeneration(procedure, optLevel);
+        B3::generate(procedure, *compilationContext.wasmEntrypointJIT);
+        compilationContext.wasmEntrypointByproducts = procedure.releaseByproducts();
+        result-&gt;wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
+    }
</ins><span class="cx"> 
</span><del>-    result-&gt;jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result-&gt;wasmEntrypoint.compilation-&gt;code(), info.memory);
</del><ins>+    createJSToWasmWrapper(vm, compilationContext, *result, signature, info.memory);
</ins><span class="cx">     return WTFMove(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmB3IRGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #if ENABLE(WEBASSEMBLY)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;B3Compilation.h&quot;
</span><ins>+#include &quot;CCallHelpers.h&quot;
</ins><span class="cx"> #include &quot;VM.h&quot;
</span><span class="cx"> #include &quot;WasmFormat.h&quot;
</span><span class="cx"> #include &lt;wtf/Expected.h&gt;
</span><span class="lines">@@ -38,8 +39,16 @@
</span><span class="cx"> 
</span><span class="cx"> class MemoryInformation;
</span><span class="cx"> 
</span><del>-Expected&lt;std::unique_ptr&lt;WasmInternalFunction&gt;, String&gt; parseAndCompile(VM&amp;, const uint8_t*, size_t, const Signature*, Vector&lt;UnlinkedWasmToWasmCall&gt;&amp;, const ImmutableFunctionIndexSpace&amp;, const ModuleInformation&amp;, unsigned optLevel = 1);
</del><ins>+struct CompilationContext {
+    std::unique_ptr&lt;CCallHelpers&gt; jsEntrypointJIT;
+    std::unique_ptr&lt;B3::OpaqueByproducts&gt; jsEntrypointByproducts;
+    std::unique_ptr&lt;CCallHelpers&gt; wasmEntrypointJIT;
+    std::unique_ptr&lt;B3::OpaqueByproducts&gt; wasmEntrypointByproducts;
+    CCallHelpers::Call jsEntrypointToWasmEntrypointCall;
+};
</ins><span class="cx"> 
</span><ins>+Expected&lt;std::unique_ptr&lt;WasmInternalFunction&gt;, String&gt; parseAndCompile(VM&amp;, CompilationContext&amp;, const uint8_t*, size_t, const Signature*, Vector&lt;UnlinkedWasmToWasmCall&gt;&amp;, const ImmutableFunctionIndexSpace&amp;, const ModuleInformation&amp;, unsigned optLevel = 1);
+
</ins><span class="cx"> } } // namespace JSC::Wasm
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(WEBASSEMBLY)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmCallingConventionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">             [=] (CCallHelpers&amp; jit, const B3::StackmapGenerationParams&amp; params) {
</span><span class="cx">                 GPRReg result = params[0].gpr();
</span><span class="cx">                 MacroAssembler::DataLabelPtr moveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), result);
</span><del>-                jit.addLinkTask([=] (LinkBuffer&amp; linkBuffer) {
</del><ins>+                jit.addLinkTask([calleeMoveLocation, moveLocation] (LinkBuffer&amp; linkBuffer) {
</ins><span class="cx">                     *calleeMoveLocation = linkBuffer.locationOf(moveLocation);
</span><span class="cx">                 });
</span><span class="cx">             });
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -39,6 +39,9 @@
</span><span class="cx"> #include &quot;WasmModuleParser.h&quot;
</span><span class="cx"> #include &quot;WasmValidate.h&quot;
</span><span class="cx"> #include &lt;wtf/DataLog.h&gt;
</span><ins>+#include &lt;wtf/Locker.h&gt;
+#include &lt;wtf/MonotonicTime.h&gt;
+#include &lt;wtf/NumberOfCores.h&gt;
</ins><span class="cx"> #include &lt;wtf/StdLibExtras.h&gt;
</span><span class="cx"> #include &lt;wtf/text/StringBuilder.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -60,6 +63,10 @@
</span><span class="cx"> 
</span><span class="cx"> bool Plan::parseAndValidateModule()
</span><span class="cx"> {
</span><ins>+    MonotonicTime startTime;
+    if (verbose || Options::reportCompileTimes())
+        startTime = MonotonicTime::now();
+
</ins><span class="cx">     {
</span><span class="cx">         ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
</span><span class="cx">         auto parseResult = moduleParser.parse();
</span><span class="lines">@@ -78,7 +85,7 @@
</span><span class="cx">             dataLogLn(&quot;Processing function starting at: &quot;, m_functionLocationInBinary[functionIndex].start, &quot; and ending at: &quot;, m_functionLocationInBinary[functionIndex].end);
</span><span class="cx">         const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
</span><span class="cx">         size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
</span><del>-        ASSERT(Checked&lt;uintptr_t&gt;(bitwise_cast&lt;uintptr_t&gt;(functionStart)) + functionLength &lt;= Checked&lt;uintptr_t&gt;(bitwise_cast&lt;uintptr_t&gt;(m_source)) + m_sourceLength);
</del><ins>+        ASSERT(functionLength &lt;= m_sourceLength);
</ins><span class="cx">         SignatureIndex signatureIndex = m_moduleInformation-&gt;internalFunctionSignatureIndices[functionIndex];
</span><span class="cx">         const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
</span><span class="cx"> 
</span><span class="lines">@@ -94,9 +101,15 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (verbose || Options::reportCompileTimes())
+        dataLogLn(&quot;Took &quot;, (MonotonicTime::now() - startTime).microseconds(), &quot; us to validate module&quot;);
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// We are creating a bunch of threads that touch the main thread's stack. This will make ASAN unhappy.
+// The reason this is OK is that we guarantee that the main thread doesn't continue until all threads
+// that could touch its stack are done executing.
+SUPPRESS_ASAN 
</ins><span class="cx"> void Plan::run()
</span><span class="cx"> {
</span><span class="cx">     if (!parseAndValidateModule())
</span><span class="lines">@@ -114,12 +127,16 @@
</span><span class="cx">         return true;
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    Vector&lt;Vector&lt;UnlinkedWasmToWasmCall&gt;&gt; unlinkedWasmToWasmCalls;
</del><span class="cx">     if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation-&gt;importFunctionSignatureIndices.size(), &quot; WebAssembly to JavaScript stubs&quot;)
</span><del>-        || !tryReserveCapacity(unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), &quot; unlinked WebAssembly to WebAssembly calls&quot;)
-        || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), &quot; WebAssembly functions&quot;))
</del><ins>+        || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), &quot; unlinked WebAssembly to WebAssembly calls&quot;)
+        || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), &quot; WebAssembly functions&quot;)
+        || !tryReserveCapacity(m_compilationContexts, m_functionLocationInBinary.size(), &quot; compilation contexts&quot;))
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    m_unlinkedWasmToWasmCalls.resize(m_functionLocationInBinary.size());
+    m_wasmInternalFunctions.resize(m_functionLocationInBinary.size());
+    m_compilationContexts.resize(m_functionLocationInBinary.size());
+
</ins><span class="cx">     for (unsigned importIndex = 0; importIndex &lt; m_moduleInformation-&gt;imports.size(); ++importIndex) {
</span><span class="cx">         Import* import = &amp;m_moduleInformation-&gt;imports[importIndex];
</span><span class="cx">         if (import-&gt;kind != ExternalKind::Function)
</span><span class="lines">@@ -132,31 +149,92 @@
</span><span class="cx">         m_functionIndexSpace.buffer.get()[importFunctionIndex].code = m_wasmToJSStubs[importFunctionIndex].code().executableAddress();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    for (unsigned functionIndex = 0; functionIndex &lt; m_functionLocationInBinary.size(); ++functionIndex) {
-        if (verbose)
-            dataLogLn(&quot;Processing function starting at: &quot;, m_functionLocationInBinary[functionIndex].start, &quot; and ending at: &quot;, m_functionLocationInBinary[functionIndex].end);
-        const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
-        size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
-        ASSERT(functionLength &lt;= m_sourceLength);
-        SignatureIndex signatureIndex = m_moduleInformation-&gt;internalFunctionSignatureIndices[functionIndex];
-        const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
-        unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
-        ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex == signatureIndex);
</del><ins>+    m_currentIndex = 0;
</ins><span class="cx"> 
</span><del>-        ASSERT(validateFunction(m_vm, functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation));
</del><ins>+    auto doWork = [this] {
+        while (true) {
+            uint32_t functionIndex;
+            {
+                auto locker = holdLock(m_lock);
+                if (m_currentIndex &gt;= m_functionLocationInBinary.size())
+                    return;
+                functionIndex = m_currentIndex;
+                ++m_currentIndex;
+            }
</ins><span class="cx"> 
</span><del>-        unlinkedWasmToWasmCalls.uncheckedAppend(Vector&lt;UnlinkedWasmToWasmCall&gt;());
-        auto parseAndCompileResult = parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation);
-        if (UNLIKELY(!parseAndCompileResult)) {
-            m_errorMessage = parseAndCompileResult.error();
-            return; // FIXME make this an Expected.
</del><ins>+            const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
+            size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
+            ASSERT(functionLength &lt;= m_sourceLength);
+            SignatureIndex signatureIndex = m_moduleInformation-&gt;internalFunctionSignatureIndices[functionIndex];
+            const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
+            unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
+            ASSERT_UNUSED(functionIndexSpace, m_functionIndexSpace.buffer.get()[functionIndexSpace].signatureIndex == signatureIndex);
+            ASSERT(validateFunction(m_vm, functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation));
+
+            m_unlinkedWasmToWasmCalls[functionIndex] = Vector&lt;UnlinkedWasmToWasmCall&gt;();
+            auto parseAndCompileResult = parseAndCompile(*m_vm, m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_functionIndexSpace, *m_moduleInformation);
+
+            if (UNLIKELY(!parseAndCompileResult)) {
+                auto locker = holdLock(m_lock);
+                if (!m_errorMessage) {
+                    // Multiple compiles could fail simultaneously. We arbitrarily choose the first.
+                    m_errorMessage = parseAndCompileResult.error(); // FIXME make this an Expected.
+                }
+                m_currentIndex = m_functionLocationInBinary.size();
+
+                // We will terminate on the next execution.
+                continue; 
+            }
+
+            m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
</ins><span class="cx">         }
</span><del>-        m_wasmInternalFunctions.uncheckedAppend(WTFMove(*parseAndCompileResult));
</del><ins>+    };
+
+    MonotonicTime startTime;
+    if (verbose || Options::reportCompileTimes())
+        startTime = MonotonicTime::now();
+
+    uint32_t threadCount = WTF::numberOfProcessorCores();
+    uint32_t numWorkerThreads = threadCount - 1;
+    Vector&lt;ThreadIdentifier&gt; threads;
+    threads.reserveCapacity(numWorkerThreads);
+    for (uint32_t i = 0; i &lt; numWorkerThreads; i++)
+        threads.uncheckedAppend(createThread(&quot;jsc.wasm-b3-compilation.thread&quot;, doWork));
+
+    doWork(); // Let the main thread do some work too.
+
+    for (uint32_t i = 0; i &lt; numWorkerThreads; i++)
+        waitForThreadCompletion(threads[i]);
+
+    for (uint32_t functionIndex = 0; functionIndex &lt; m_functionLocationInBinary.size(); functionIndex++) {
+        {
+            CompilationContext&amp; context = m_compilationContexts[functionIndex];
+            {
+                LinkBuffer linkBuffer(*m_vm, *context.wasmEntrypointJIT, nullptr);
+                m_wasmInternalFunctions[functionIndex]-&gt;wasmEntrypoint.compilation =
+                    std::make_unique&lt;B3::Compilation&gt;(FINALIZE_CODE(linkBuffer, (&quot;Wasm function&quot;)), WTFMove(context.wasmEntrypointByproducts));
+            }
+
+            {
+                LinkBuffer linkBuffer(*m_vm, *context.jsEntrypointJIT, nullptr);
+                linkBuffer.link(context.jsEntrypointToWasmEntrypointCall, FunctionPtr(m_wasmInternalFunctions[functionIndex]-&gt;wasmEntrypoint.compilation-&gt;code().executableAddress()));
+
+                m_wasmInternalFunctions[functionIndex]-&gt;jsToWasmEntrypoint.compilation =
+                    std::make_unique&lt;B3::Compilation&gt;(FINALIZE_CODE(linkBuffer, (&quot;Wasm JS entrypoint&quot;)), WTFMove(context.jsEntrypointByproducts));
+            }
+        }
+
+        unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
</ins><span class="cx">         m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]-&gt;wasmEntrypoint.compilation-&gt;code().executableAddress();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (verbose || Options::reportCompileTimes()) {
+        dataLogLn(&quot;Took &quot;, (MonotonicTime::now() - startTime).microseconds(),
+            &quot; us to compile and link the module&quot;);
+    }
+
</ins><span class="cx">     // Patch the call sites for each WebAssembly function.
</span><del>-    for (auto&amp; unlinked : unlinkedWasmToWasmCalls) {
</del><ins>+    for (auto&amp; unlinked : m_unlinkedWasmToWasmCalls) {
</ins><span class="cx">         for (auto&amp; call : unlinked)
</span><span class="cx">             MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(m_functionIndexSpace.buffer.get()[call.functionIndex].code));
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmPlanh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmPlan.h (210046 => 210047)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmPlan.h        2016-12-21 00:15:53 UTC (rev 210046)
+++ trunk/Source/JavaScriptCore/wasm/WasmPlan.h        2016-12-21 00:29:36 UTC (rev 210047)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CompilationResult.h&quot;
</span><span class="cx"> #include &quot;VM.h&quot;
</span><ins>+#include &quot;WasmB3IRGenerator.h&quot;
</ins><span class="cx"> #include &quot;WasmFormat.h&quot;
</span><span class="cx"> #include &lt;wtf/Bag.h&gt;
</span><span class="cx"> #include &lt;wtf/ThreadSafeRefCounted.h&gt;
</span><span class="lines">@@ -103,13 +104,17 @@
</span><span class="cx">     Bag&lt;CallLinkInfo&gt; m_callLinkInfos;
</span><span class="cx">     Vector&lt;WasmToJSStub&gt; m_wasmToJSStubs;
</span><span class="cx">     Vector&lt;std::unique_ptr&lt;WasmInternalFunction&gt;&gt; m_wasmInternalFunctions;
</span><ins>+    Vector&lt;CompilationContext&gt; m_compilationContexts;
</ins><span class="cx">     ImmutableFunctionIndexSpace m_functionIndexSpace;
</span><span class="cx"> 
</span><span class="cx">     VM* m_vm;
</span><ins>+    Vector&lt;Vector&lt;UnlinkedWasmToWasmCall&gt;&gt; m_unlinkedWasmToWasmCalls;
</ins><span class="cx">     const uint8_t* m_source;
</span><span class="cx">     const size_t m_sourceLength;
</span><span class="cx">     bool m_failed { true };
</span><span class="cx">     String m_errorMessage;
</span><ins>+    uint32_t m_currentIndex;
+    Lock m_lock;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::Wasm
</span></span></pre>
</div>
</div>

</body>
</html>