<!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 <sbarati@apple.com>
+
+ 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 <bfulgham@apple.com>
</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<GenerationContext::LatePathFunction>(
</span><del>- [=] (CCallHelpers& jit, Air::GenerationContext&) {
</del><ins>+ [outOfBounds, value] (CCallHelpers& jit, Air::GenerationContext& context) {
</ins><span class="cx"> outOfBounds.link(&jit);
</span><span class="cx"> context.code->wasmBoundsCheckGenerator()->run(jit, value->pinnedGPR(), value->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&, GenerationContext&);
</span><span class="cx"> typedef SharedTask<LatePathFunction> 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->emitExceptionCheck(jit, ExceptionType::OutOfBoundsMemoryAccess);
</span><span class="cx"> });
</span><del>-
- B3::PatchpointValue* foo = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
- foo->setGenerator(
- [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
- AllowMacroScratchRegisterUsage allowScratch(jit);
- });
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> wasmCallingConvention().setupFrameInPrologue(&compilation->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 = &m_vm;
</span><del>- jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
</del><ins>+ jit.addLinkTask([vm, jumpToExceptionStub] (LinkBuffer& linkBuffer) {
</ins><span class="cx"> linkBuffer.link(jumpToExceptionStub, CodeLocationLabel(vm->getCTIStub(throwExceptionFromWasmThunkGenerator).code()));
</span><span class="cx"> });
</span><span class="cx"> }
</span><span class="lines">@@ -691,13 +685,14 @@
</span><span class="cx"> patchpoint->effects.writesPinned = true;
</span><span class="cx"> patchpoint->effects.readsPinned = true;
</span><span class="cx">
</span><del>- patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
</del><ins>+ Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls = &m_unlinkedWasmToWasmCalls;
+ patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
</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& linkBuffer) {
- m_unlinkedWasmToWasmCalls.append({ linkBuffer.locationOf(call), functionIndex });
</del><ins>+ jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) {
+ unlinkedWasmToWasmCalls->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("\n");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFunction& function, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation& memory)
</del><ins>+static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext, WasmInternalFunction& function, const Signature* signature, const MemoryInformation& 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->append(ConstrainedValue(sizes[i], ValueRep::reg(memory.pinnedRegisters().sizeRegisters[i].sizeRegister)));
</span><span class="cx"> }
</span><span class="cx">
</span><del>- patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
</del><ins>+ CompilationContext* context = &compilationContext;
+ patchpoint->setGenerator([context] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
</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& linkBuffer) {
- linkBuffer.link(call, FunctionPtr(mainFunction.executableAddress()));
- });
</del><ins>+ context->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<Compilation>(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<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)
</del><ins>+Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm, CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature* signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace, const ModuleInformation& info, unsigned optLevel)
</ins><span class="cx"> {
</span><span class="cx"> auto result = std::make_unique<WasmInternalFunction>();
</span><span class="cx">
</span><ins>+ compilationContext.jsEntrypointJIT = std::make_unique<CCallHelpers>(&vm);
+ compilationContext.wasmEntrypointJIT = std::make_unique<CCallHelpers>(&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<B3IRGenerator> parser(&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("Post SSA: ", procedure);
</span><span class="cx">
</span><del>- result->wasmEntrypoint.compilation = std::make_unique<B3::Compilation>(B3::compile(vm, procedure, optLevel));
- result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
</del><ins>+ {
+ B3::prepareForGeneration(procedure, optLevel);
+ B3::generate(procedure, *compilationContext.wasmEntrypointJIT);
+ compilationContext.wasmEntrypointByproducts = procedure.releaseByproducts();
+ result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
+ }
</ins><span class="cx">
</span><del>- result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->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 "B3Compilation.h"
</span><ins>+#include "CCallHelpers.h"
</ins><span class="cx"> #include "VM.h"
</span><span class="cx"> #include "WasmFormat.h"
</span><span class="cx"> #include <wtf/Expected.h>
</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<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
</del><ins>+struct CompilationContext {
+ std::unique_ptr<CCallHelpers> jsEntrypointJIT;
+ std::unique_ptr<B3::OpaqueByproducts> jsEntrypointByproducts;
+ std::unique_ptr<CCallHelpers> wasmEntrypointJIT;
+ std::unique_ptr<B3::OpaqueByproducts> wasmEntrypointByproducts;
+ CCallHelpers::Call jsEntrypointToWasmEntrypointCall;
+};
</ins><span class="cx">
</span><ins>+Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, CompilationContext&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, 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& jit, const B3::StackmapGenerationParams& 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& linkBuffer) {
</del><ins>+ jit.addLinkTask([calleeMoveLocation, moveLocation] (LinkBuffer& 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 "WasmModuleParser.h"
</span><span class="cx"> #include "WasmValidate.h"
</span><span class="cx"> #include <wtf/DataLog.h>
</span><ins>+#include <wtf/Locker.h>
+#include <wtf/MonotonicTime.h>
+#include <wtf/NumberOfCores.h>
</ins><span class="cx"> #include <wtf/StdLibExtras.h>
</span><span class="cx"> #include <wtf/text/StringBuilder.h>
</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("Processing function starting at: ", m_functionLocationInBinary[functionIndex].start, " and ending at: ", 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<uintptr_t>(bitwise_cast<uintptr_t>(functionStart)) + functionLength <= Checked<uintptr_t>(bitwise_cast<uintptr_t>(m_source)) + m_sourceLength);
</del><ins>+ ASSERT(functionLength <= m_sourceLength);
</ins><span class="cx"> SignatureIndex signatureIndex = m_moduleInformation->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("Took ", (MonotonicTime::now() - startTime).microseconds(), " us to validate module");
</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<Vector<UnlinkedWasmToWasmCall>> unlinkedWasmToWasmCalls;
</del><span class="cx"> if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
</span><del>- || !tryReserveCapacity(unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
- || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions"))
</del><ins>+ || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
+ || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions")
+ || !tryReserveCapacity(m_compilationContexts, m_functionLocationInBinary.size(), " compilation contexts"))
</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 < m_moduleInformation->imports.size(); ++importIndex) {
</span><span class="cx"> Import* import = &m_moduleInformation->imports[importIndex];
</span><span class="cx"> if (import->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 < m_functionLocationInBinary.size(); ++functionIndex) {
- if (verbose)
- dataLogLn("Processing function starting at: ", m_functionLocationInBinary[functionIndex].start, " and ending at: ", 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 <= m_sourceLength);
- SignatureIndex signatureIndex = m_moduleInformation->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 >= m_functionLocationInBinary.size())
+ return;
+ functionIndex = m_currentIndex;
+ ++m_currentIndex;
+ }
</ins><span class="cx">
</span><del>- unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
- 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 <= m_sourceLength);
+ SignatureIndex signatureIndex = m_moduleInformation->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<UnlinkedWasmToWasmCall>();
+ 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<ThreadIdentifier> threads;
+ threads.reserveCapacity(numWorkerThreads);
+ for (uint32_t i = 0; i < numWorkerThreads; i++)
+ threads.uncheckedAppend(createThread("jsc.wasm-b3-compilation.thread", doWork));
+
+ doWork(); // Let the main thread do some work too.
+
+ for (uint32_t i = 0; i < numWorkerThreads; i++)
+ waitForThreadCompletion(threads[i]);
+
+ for (uint32_t functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); functionIndex++) {
+ {
+ CompilationContext& context = m_compilationContexts[functionIndex];
+ {
+ LinkBuffer linkBuffer(*m_vm, *context.wasmEntrypointJIT, nullptr);
+ m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation =
+ std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("Wasm function")), WTFMove(context.wasmEntrypointByproducts));
+ }
+
+ {
+ LinkBuffer linkBuffer(*m_vm, *context.jsEntrypointJIT, nullptr);
+ linkBuffer.link(context.jsEntrypointToWasmEntrypointCall, FunctionPtr(m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress()));
+
+ m_wasmInternalFunctions[functionIndex]->jsToWasmEntrypoint.compilation =
+ std::make_unique<B3::Compilation>(FINALIZE_CODE(linkBuffer, ("Wasm JS entrypoint")), WTFMove(context.jsEntrypointByproducts));
+ }
+ }
+
+ unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
</ins><span class="cx"> m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (verbose || Options::reportCompileTimes()) {
+ dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(),
+ " us to compile and link the module");
+ }
+
</ins><span class="cx"> // Patch the call sites for each WebAssembly function.
</span><del>- for (auto& unlinked : unlinkedWasmToWasmCalls) {
</del><ins>+ for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
</ins><span class="cx"> for (auto& 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 "CompilationResult.h"
</span><span class="cx"> #include "VM.h"
</span><ins>+#include "WasmB3IRGenerator.h"
</ins><span class="cx"> #include "WasmFormat.h"
</span><span class="cx"> #include <wtf/Bag.h>
</span><span class="cx"> #include <wtf/ThreadSafeRefCounted.h>
</span><span class="lines">@@ -103,13 +104,17 @@
</span><span class="cx"> Bag<CallLinkInfo> m_callLinkInfos;
</span><span class="cx"> Vector<WasmToJSStub> m_wasmToJSStubs;
</span><span class="cx"> Vector<std::unique_ptr<WasmInternalFunction>> m_wasmInternalFunctions;
</span><ins>+ Vector<CompilationContext> m_compilationContexts;
</ins><span class="cx"> ImmutableFunctionIndexSpace m_functionIndexSpace;
</span><span class="cx">
</span><span class="cx"> VM* m_vm;
</span><ins>+ Vector<Vector<UnlinkedWasmToWasmCall>> 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>