WebAssembly: We should compile wasm functions in parallel
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Dec 2016 00:29:36 +0000 (00:29 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Dec 2016 00:29:36 +0000 (00:29 +0000)
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:

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/b3/air/AirCustom.h
Source/JavaScriptCore/b3/air/AirGenerationContext.h
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
Source/JavaScriptCore/wasm/WasmCallingConvention.h
Source/JavaScriptCore/wasm/WasmPlan.cpp
Source/JavaScriptCore/wasm/WasmPlan.h

index e02d848..4ea9072 100644 (file)
@@ -1,3 +1,32 @@
+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:
+
 2016-12-20  Brent Fulgham  <bfulgham@apple.com>
 
         Address some style problems found by static analysis
index 644b7a1..cddc038 100644 (file)
@@ -313,7 +313,7 @@ struct WasmBoundsCheckCustom : public CommonCustomBase<WasmBoundsCheckCustom> {
         CCallHelpers::Jump outOfBounds = Inst(Air::Branch64, value, Arg::relCond(CCallHelpers::AboveOrEqual), inst.args[0], inst.args[1]).generate(jit, context);
 
         context.latePaths.append(createSharedTask<GenerationContext::LatePathFunction>(
-            [=] (CCallHelpers& jit, Air::GenerationContext&) {
+            [outOfBounds, value] (CCallHelpers& jit, Air::GenerationContext& context) {
                 outOfBounds.link(&jit);
                 context.code->wasmBoundsCheckGenerator()->run(jit, value->pinnedGPR(), value->offset());
             }));
index 17e1126..f48b5bb 100644 (file)
@@ -39,6 +39,11 @@ namespace JSC { namespace B3 { namespace Air {
 class Code;
 
 struct GenerationContext {
+    WTF_MAKE_NONCOPYABLE(GenerationContext);
+public:
+
+    GenerationContext() = default;
+
     typedef void LatePathFunction(CCallHelpers&, GenerationContext&);
     typedef SharedTask<LatePathFunction> LatePath;
 
index 5f35a28..ba78299 100644 (file)
@@ -257,12 +257,6 @@ B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
             ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);
             this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsMemoryAccess);
         });
-
-        B3::PatchpointValue* foo = m_currentBlock->appendNew<B3::PatchpointValue>(m_proc, B3::Void, Origin());
-        foo->setGenerator(
-            [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
-                AllowMacroScratchRegisterUsage allowScratch(jit);
-            });
     }
 
     wasmCallingConvention().setupFrameInPrologue(&compilation->wasmCalleeMoveLocation, m_proc, Origin(), m_currentBlock);
@@ -277,7 +271,7 @@ void B3IRGenerator::emitExceptionCheck(CCallHelpers& jit, ExceptionType type)
     auto jumpToExceptionStub = jit.jump();
 
     VM* vm = &m_vm;
-    jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+    jit.addLinkTask([vm, jumpToExceptionStub] (LinkBuffer& linkBuffer) {
         linkBuffer.link(jumpToExceptionStub, CodeLocationLabel(vm->getCTIStub(throwExceptionFromWasmThunkGenerator).code()));
     });
 }
@@ -691,13 +685,14 @@ auto B3IRGenerator::addCall(uint32_t functionIndex, const Signature* signature,
             patchpoint->effects.writesPinned = true;
             patchpoint->effects.readsPinned = true;
 
-            patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls = &m_unlinkedWasmToWasmCalls;
+            patchpoint->setGenerator([unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
                 AllowMacroScratchRegisterUsage allowScratch(jit);
 
                 CCallHelpers::Call call = jit.call();
 
-                jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-                    m_unlinkedWasmToWasmCalls.append({ linkBuffer.locationOf(call), functionIndex });
+                jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) {
+                    unlinkedWasmToWasmCalls->append({ linkBuffer.locationOf(call), functionIndex });
                 });
             });
         });
@@ -819,7 +814,7 @@ void B3IRGenerator::dump(const Vector<ControlEntry>& controlStack, const Express
     dataLogLn("\n");
 }
 
-static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmInternalFunction& function, const Signature* signature, MacroAssemblerCodePtr mainFunction, const MemoryInformation& memory)
+static void createJSToWasmWrapper(VM& vm, CompilationContext& compilationContext, WasmInternalFunction& function, const Signature* signature, const MemoryInformation& memory)
 {
     Procedure proc;
     BasicBlock* block = proc.addBlock();
@@ -876,13 +871,12 @@ static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmIntern
                 patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory.pinnedRegisters().sizeRegisters[i].sizeRegister)));
         }
 
-        patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+        CompilationContext* context = &compilationContext;
+        patchpoint->setGenerator([context] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
 
             CCallHelpers::Call call = jit.call();
-            jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-                linkBuffer.link(call, FunctionPtr(mainFunction.executableAddress()));
-            });
+            context->jsEntrypointToWasmEntrypointCall = call;
         });
     });
 
@@ -904,15 +898,19 @@ static std::unique_ptr<B3::Compilation> createJSToWasmWrapper(VM& vm, WasmIntern
         RELEASE_ASSERT_NOT_REACHED();
     }
 
-    auto jsEntrypoint = std::make_unique<Compilation>(B3::compile(vm, proc));
+    B3::prepareForGeneration(proc);
+    B3::generate(proc, *compilationContext.jsEntrypointJIT);
+    compilationContext.jsEntrypointByproducts = proc.releaseByproducts();
     function.jsToWasmEntrypoint.calleeSaveRegisters = proc.calleeSaveRegisters();
-    return jsEntrypoint;
 }
 
-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)
+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)
 {
     auto result = std::make_unique<WasmInternalFunction>();
 
+    compilationContext.jsEntrypointJIT = std::make_unique<CCallHelpers>(&vm);
+    compilationContext.wasmEntrypointJIT = std::make_unique<CCallHelpers>(&vm);
+
     Procedure procedure;
     B3IRGenerator context(vm, info, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
     FunctionParser<B3IRGenerator> parser(&vm, context, functionStart, functionLength, signature, functionIndexSpace, info);
@@ -927,10 +925,14 @@ Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM& vm,
     if (verbose)
         dataLog("Post SSA: ", procedure);
 
-    result->wasmEntrypoint.compilation = std::make_unique<B3::Compilation>(B3::compile(vm, procedure, optLevel));
-    result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
+    {
+        B3::prepareForGeneration(procedure, optLevel);
+        B3::generate(procedure, *compilationContext.wasmEntrypointJIT);
+        compilationContext.wasmEntrypointByproducts = procedure.releaseByproducts();
+        result->wasmEntrypoint.calleeSaveRegisters = procedure.calleeSaveRegisters();
+    }
 
-    result->jsToWasmEntrypoint.compilation = createJSToWasmWrapper(vm, *result, signature, result->wasmEntrypoint.compilation->code(), info.memory);
+    createJSToWasmWrapper(vm, compilationContext, *result, signature, info.memory);
     return WTFMove(result);
 }
 
index dfe6a46..b5c9f46 100644 (file)
@@ -28,6 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "B3Compilation.h"
+#include "CCallHelpers.h"
 #include "VM.h"
 #include "WasmFormat.h"
 #include <wtf/Expected.h>
@@ -38,7 +39,15 @@ namespace JSC { namespace Wasm {
 
 class MemoryInformation;
 
-Expected<std::unique_ptr<WasmInternalFunction>, String> parseAndCompile(VM&, const uint8_t*, size_t, const Signature*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&, const ModuleInformation&, unsigned optLevel = 1);
+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;
+};
+
+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);
 
 } } // namespace JSC::Wasm
 
index 928ffa5..d79014f 100644 (file)
@@ -95,7 +95,7 @@ public:
             [=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
                 GPRReg result = params[0].gpr();
                 MacroAssembler::DataLabelPtr moveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), result);
-                jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+                jit.addLinkTask([calleeMoveLocation, moveLocation] (LinkBuffer& linkBuffer) {
                     *calleeMoveLocation = linkBuffer.locationOf(moveLocation);
                 });
             });
index 1e59842..dbde52e 100644 (file)
@@ -39,6 +39,9 @@
 #include "WasmModuleParser.h"
 #include "WasmValidate.h"
 #include <wtf/DataLog.h>
+#include <wtf/Locker.h>
+#include <wtf/MonotonicTime.h>
+#include <wtf/NumberOfCores.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/text/StringBuilder.h>
 
@@ -60,6 +63,10 @@ Plan::Plan(VM* vm, const uint8_t* source, size_t sourceLength)
 
 bool Plan::parseAndValidateModule()
 {
+    MonotonicTime startTime;
+    if (verbose || Options::reportCompileTimes())
+        startTime = MonotonicTime::now();
+
     {
         ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
         auto parseResult = moduleParser.parse();
@@ -78,7 +85,7 @@ bool Plan::parseAndValidateModule()
             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(Checked<uintptr_t>(bitwise_cast<uintptr_t>(functionStart)) + functionLength <= Checked<uintptr_t>(bitwise_cast<uintptr_t>(m_source)) + m_sourceLength);
+        ASSERT(functionLength <= m_sourceLength);
         SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
         const Signature* signature = SignatureInformation::get(m_vm, signatureIndex);
 
@@ -94,9 +101,15 @@ bool Plan::parseAndValidateModule()
         }
     }
 
+    if (verbose || Options::reportCompileTimes())
+        dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(), " us to validate module");
     return true;
 }
 
+// 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 
 void Plan::run()
 {
     if (!parseAndValidateModule())
@@ -114,12 +127,16 @@ void Plan::run()
         return true;
     };
 
-    Vector<Vector<UnlinkedWasmToWasmCall>> unlinkedWasmToWasmCalls;
     if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
-        || !tryReserveCapacity(unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
-        || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions"))
+        || !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"))
         return;
 
+    m_unlinkedWasmToWasmCalls.resize(m_functionLocationInBinary.size());
+    m_wasmInternalFunctions.resize(m_functionLocationInBinary.size());
+    m_compilationContexts.resize(m_functionLocationInBinary.size());
+
     for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) {
         Import* import = &m_moduleInformation->imports[importIndex];
         if (import->kind != ExternalKind::Function)
@@ -132,31 +149,92 @@ void Plan::run()
         m_functionIndexSpace.buffer.get()[importFunctionIndex].code = m_wasmToJSStubs[importFunctionIndex].code().executableAddress();
     }
 
-    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);
+    m_currentIndex = 0;
+
+    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;
+            }
+
+            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));
 
-        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);
 
-        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.
+            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);
+        }
+    };
+
+    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));
+            }
         }
-        m_wasmInternalFunctions.uncheckedAppend(WTFMove(*parseAndCompileResult));
+
+        unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
         m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation->code().executableAddress();
     }
 
+    if (verbose || Options::reportCompileTimes()) {
+        dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(),
+            " us to compile and link the module");
+    }
+
     // Patch the call sites for each WebAssembly function.
-    for (auto& unlinked : unlinkedWasmToWasmCalls) {
+    for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
         for (auto& call : unlinked)
             MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(m_functionIndexSpace.buffer.get()[call.functionIndex].code));
     }
index 34879c0..3bb01c8 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "CompilationResult.h"
 #include "VM.h"
+#include "WasmB3IRGenerator.h"
 #include "WasmFormat.h"
 #include <wtf/Bag.h>
 #include <wtf/ThreadSafeRefCounted.h>
@@ -103,13 +104,17 @@ private:
     Bag<CallLinkInfo> m_callLinkInfos;
     Vector<WasmToJSStub> m_wasmToJSStubs;
     Vector<std::unique_ptr<WasmInternalFunction>> m_wasmInternalFunctions;
+    Vector<CompilationContext> m_compilationContexts;
     ImmutableFunctionIndexSpace m_functionIndexSpace;
 
     VM* m_vm;
+    Vector<Vector<UnlinkedWasmToWasmCall>> m_unlinkedWasmToWasmCalls;
     const uint8_t* m_source;
     const size_t m_sourceLength;
     bool m_failed { true };
     String m_errorMessage;
+    uint32_t m_currentIndex;
+    Lock m_lock;
 };
 
 } } // namespace JSC::Wasm