WebAssembly: Implement tier up
https://bugs.webkit.org/show_bug.cgi?id=170134
Reviewed by Filip Pizlo.
JSTests:
* wasm/function-tests/trap-after-cross-instance-call.js:
* wasm/tier-up/js-to-wasm.js: Added.
(async.test):
* wasm/tier-up/wasm-to-wasm.js: Added.
(async.test):
Source/JavaScriptCore:
This patch implements tier up for wasm functions. Unlike with JS
code, wasm code needs to be able to tier up concurrently with the
running code. Since JS code is synchronous we can always link on
the running thread, wasm, however, can run the same code on more
than one thread. In order to make patching work correctly, we need
to ensure that all patches of callsites are aligned. On ARM we get
this for free since every call is a near call. On X86 we ensure
that the 32-bit relative offset is 32-bit aligned.
This patch also modifies how Wasm::Plan works. Now Plan is a
abstract super class and there are two subclasses, which
correspond to the different tiers of our wasm engine. The first,
Build Bytecode Quickly (BBQ) tier, roughly does what the old plan
code did before. The new tier, Optimized Machine code Generation
(OMG), can be called at any point by BBQ code and compiles exactly
one function. Once an OMGPlan finishes it will link it's code
internally then reset the instruction cache of all running wasm
threads, via, a ThreadMessage. Once the instruction caches have
been reset all the other functions will be patched to call the new
code.
* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::ensureCacheLineSpace):
* assembler/CodeLocation.h:
(JSC::CodeLocationThreadSafeNearCall::CodeLocationThreadSafeNearCall):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::threadSafePatchableNearCall):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::threadSafeNearCall):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::threadSafePatchableNearCall):
* b3/air/AirEmitShuffle.cpp:
(JSC::B3::Air::ShufflePair::inst):
(JSC::B3::Air::ShufflePair::opcode): Deleted.
* b3/air/AirEmitShuffle.h:
* jsc.cpp:
(functionTestWasmModuleFunctions):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
* runtime/Options.h:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::materializeWasmContext):
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::constant):
(JSC::Wasm::B3IRGenerator::emitTierUpCheck):
(JSC::Wasm::B3IRGenerator::addLoop):
(JSC::Wasm::B3IRGenerator::addTopLevel):
(JSC::Wasm::B3IRGenerator::addBlock):
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::parseAndCompile):
* wasm/WasmB3IRGenerator.h:
* wasm/WasmBBQPlan.cpp: Copied from Source/JavaScriptCore/wasm/WasmPlan.cpp.
(JSC::Wasm::BBQPlan::BBQPlan):
(JSC::Wasm::BBQPlan::stateString):
(JSC::Wasm::BBQPlan::moveToState):
(JSC::Wasm::BBQPlan::parseAndValidateModule):
(JSC::Wasm::BBQPlan::prepare):
(JSC::Wasm::BBQPlan::ThreadCountHolder::ThreadCountHolder):
(JSC::Wasm::BBQPlan::ThreadCountHolder::~ThreadCountHolder):
(JSC::Wasm::BBQPlan::compileFunctions):
(JSC::Wasm::BBQPlan::complete):
(JSC::Wasm::BBQPlan::work):
* wasm/WasmBBQPlan.h: Copied from Source/JavaScriptCore/wasm/WasmPlan.h.
* wasm/WasmBBQPlanInlines.h: Copied from Source/JavaScriptCore/wasm/WasmPlanInlines.h.
(JSC::Wasm::BBQPlan::initializeCallees):
* wasm/WasmBinding.cpp:
(JSC::Wasm::wasmToWasm):
* wasm/WasmCallee.h:
(JSC::Wasm::Callee::entrypoint):
* wasm/WasmCodeBlock.cpp:
(JSC::Wasm::CodeBlock::CodeBlock):
* wasm/WasmCodeBlock.h:
(JSC::Wasm::CodeBlock::jsEntrypointCalleeFromFunctionIndexSpace):
(JSC::Wasm::CodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
(JSC::Wasm::CodeBlock::wasmEntrypointLoadLocationFromFunctionIndexSpace):
(JSC::Wasm::CodeBlock::tierUpCount):
(JSC::Wasm::CodeBlock::mode):
* wasm/WasmFormat.h:
(JSC::Wasm::CallableFunction::CallableFunction):
(JSC::Wasm::CallableFunction::offsetOfWasmEntrypointLoadLocation):
* wasm/WasmMachineThreads.cpp: Copied from Source/JavaScriptCore/wasm/WasmPlanInlines.h.
(JSC::Wasm::wasmThreads):
(JSC::Wasm::startTrackingCurrentThread):
(JSC::Wasm::resetInstructionCacheOnAllThreads):
* wasm/WasmMachineThreads.h: Copied from Source/JavaScriptCore/wasm/WasmCallee.h.
* wasm/WasmModule.cpp:
(JSC::Wasm::makeValidationResult):
(JSC::Wasm::makeValidationCallback):
(JSC::Wasm::Module::validateSync):
(JSC::Wasm::Module::validateAsync):
* wasm/WasmModule.h:
(JSC::Wasm::Module::codeBlockFor):
* wasm/WasmOMGPlan.cpp: Added.
(JSC::Wasm::OMGPlan::OMGPlan):
(JSC::Wasm::OMGPlan::work):
(JSC::Wasm::runOMGPlanForIndex):
* wasm/WasmOMGPlan.h: Copied from Source/JavaScriptCore/wasm/WasmPlanInlines.h.
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::Plan):
(JSC::Wasm::Plan::runCompletionTasks):
(JSC::Wasm::Plan::addCompletionTask):
(JSC::Wasm::Plan::waitForCompletion):
(JSC::Wasm::Plan::tryRemoveVMAndCancelIfLast):
(JSC::Wasm::Plan::fail):
(JSC::Wasm::Plan::stateString): Deleted.
(JSC::Wasm::Plan::moveToState): Deleted.
(JSC::Wasm::Plan::parseAndValidateModule): Deleted.
(JSC::Wasm::Plan::prepare): Deleted.
(JSC::Wasm::Plan::ThreadCountHolder::ThreadCountHolder): Deleted.
(JSC::Wasm::Plan::ThreadCountHolder::~ThreadCountHolder): Deleted.
(JSC::Wasm::Plan::compileFunctions): Deleted.
(JSC::Wasm::Plan::complete): Deleted.
* wasm/WasmPlan.h:
(JSC::Wasm::Plan::exports): Deleted.
(JSC::Wasm::Plan::internalFunctionCount): Deleted.
(JSC::Wasm::Plan::takeModuleInformation): Deleted.
(JSC::Wasm::Plan::takeCallLinkInfos): Deleted.
(JSC::Wasm::Plan::takeWasmToWasmExitStubs): Deleted.
(JSC::Wasm::Plan::hasWork): Deleted.
(JSC::Wasm::Plan::hasBeenPrepared): Deleted.
* wasm/WasmTierUpCount.h: Renamed from Source/JavaScriptCore/wasm/WasmPlanInlines.h.
(JSC::Wasm::TierUpCount::TierUpCount):
(JSC::Wasm::TierUpCount::loopDecrement):
(JSC::Wasm::TierUpCount::functionEntryDecrement):
(JSC::Wasm::TierUpCount::shouldStartTierUp):
(JSC::Wasm::TierUpCount::count):
* wasm/WasmWorklist.cpp:
* wasm/WasmWorklist.h:
(JSC::Wasm::Worklist::nextTicket):
* wasm/js/JSWebAssemblyCodeBlock.cpp:
* wasm/js/JSWebAssemblyCodeBlock.h:
(JSC::JSWebAssemblyCodeBlock::wasmEntrypointLoadLocationFromFunctionIndexSpace):
(JSC::JSWebAssemblyCodeBlock::wasmToJsCallStubForImport):
(JSC::JSWebAssemblyCodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace): Deleted.
* wasm/js/JSWebAssemblyTable.cpp:
(JSC::JSWebAssemblyTable::setFunction):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::WebAssemblyFunction::create):
(JSC::WebAssemblyFunction::WebAssemblyFunction):
* wasm/js/WebAssemblyFunction.h:
(JSC::WebAssemblyFunction::signatureIndex):
(JSC::WebAssemblyFunction::wasmEntrypointLoadLocation):
(JSC::WebAssemblyFunction::callableFunction):
(JSC::WebAssemblyFunction::offsetOfWasmEntrypointLoadLocation):
(JSC::WebAssemblyFunction::wasmEntrypoint): Deleted.
(JSC::WebAssemblyFunction::offsetOfWasmEntrypoint): Deleted.
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):
* wasm/js/WebAssemblyPrototype.cpp:
(JSC::webAssemblyValidateFunc):
* wasm/js/WebAssemblyWrapperFunction.cpp:
(JSC::WebAssemblyWrapperFunction::WebAssemblyWrapperFunction):
(JSC::WebAssemblyWrapperFunction::create):
* wasm/js/WebAssemblyWrapperFunction.h:
(JSC::WebAssemblyWrapperFunction::signatureIndex):
(JSC::WebAssemblyWrapperFunction::wasmEntrypointLoadLocation):
(JSC::WebAssemblyWrapperFunction::callableFunction):
(JSC::WebAssemblyWrapperFunction::wasmEntrypoint): Deleted.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@215843 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
new file mode 100644
index 0000000..0d8e54a
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WasmBBQPlan.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "B3Compilation.h"
+#include "JSCInlines.h"
+#include "JSGlobalObject.h"
+#include "WasmB3IRGenerator.h"
+#include "WasmBinding.h"
+#include "WasmCallee.h"
+#include "WasmCallingConvention.h"
+#include "WasmFaultSignalHandler.h"
+#include "WasmMemory.h"
+#include "WasmModuleParser.h"
+#include "WasmTierUpCount.h"
+#include "WasmValidate.h"
+#include <wtf/DataLog.h>
+#include <wtf/Locker.h>
+#include <wtf/MonotonicTime.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/SystemTracing.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace JSC { namespace Wasm {
+
+static const bool verbose = false;
+
+BBQPlan::BBQPlan(VM& vm, Ref<ModuleInformation> info, AsyncWork work, CompletionTask&& task)
+ : Base(vm, WTFMove(info), WTFMove(task))
+ , m_state(State::Validated)
+ , m_asyncWork(work)
+{
+}
+
+BBQPlan::BBQPlan(VM& vm, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task)
+ : BBQPlan(vm, makeRef(*new ModuleInformation(WTFMove(source))), work, WTFMove(task))
+{
+ m_state = State::Initial;
+}
+
+BBQPlan::BBQPlan(VM& vm, const uint8_t* source, size_t sourceLength, AsyncWork work, CompletionTask&& task)
+ : Base(vm, source, sourceLength, WTFMove(task))
+ , m_state(State::Initial)
+ , m_asyncWork(work)
+{
+}
+
+const char* BBQPlan::stateString(State state)
+{
+ switch (state) {
+ case State::Initial: return "Initial";
+ case State::Validated: return "Validated";
+ case State::Prepared: return "Prepared";
+ case State::Compiled: return "Compiled";
+ case State::Completed: return "Completed";
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void BBQPlan::moveToState(State state)
+{
+ ASSERT(state >= m_state);
+ dataLogLnIf(verbose && state != m_state, "moving to state: ", stateString(state), " from state: ", stateString(m_state));
+ m_state = state;
+}
+
+bool BBQPlan::parseAndValidateModule()
+{
+ if (m_state != State::Initial)
+ return true;
+
+ dataLogLnIf(verbose, "starting validation");
+ MonotonicTime startTime;
+ if (verbose || Options::reportCompileTimes())
+ startTime = MonotonicTime::now();
+
+ {
+ ModuleParser moduleParser(m_source, m_sourceLength, m_moduleInformation);
+ auto parseResult = moduleParser.parse();
+ if (!parseResult) {
+ Base::fail(holdLock(m_lock), WTFMove(parseResult.error()));
+ return false;
+ }
+ }
+
+ const auto& functionLocations = m_moduleInformation->functionLocationInBinary;
+ for (unsigned functionIndex = 0; functionIndex < functionLocations.size(); ++functionIndex) {
+ dataLogLnIf(verbose, "Processing function starting at: ", functionLocations[functionIndex].start, " and ending at: ", functionLocations[functionIndex].end);
+ const uint8_t* functionStart = m_source + functionLocations[functionIndex].start;
+ size_t functionLength = functionLocations[functionIndex].end - functionLocations[functionIndex].start;
+ ASSERT(functionLength <= m_sourceLength);
+ SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+ const Signature& signature = SignatureInformation::get(signatureIndex);
+
+ auto validationResult = validateFunction(functionStart, functionLength, signature, m_moduleInformation.get());
+ if (!validationResult) {
+ if (verbose) {
+ for (unsigned i = 0; i < functionLength; ++i)
+ dataLog(RawPointer(reinterpret_cast<void*>(functionStart[i])), ", ");
+ dataLogLn();
+ }
+ Base::fail(holdLock(m_lock), makeString(validationResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected.
+ return false;
+ }
+ }
+
+ if (verbose || Options::reportCompileTimes())
+ dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(), " us to validate module");
+
+ moveToState(State::Validated);
+ if (m_asyncWork == Validation)
+ complete(holdLock(m_lock));
+ return true;
+}
+
+void BBQPlan::prepare()
+{
+ ASSERT(m_state == State::Validated);
+ dataLogLnIf(verbose, "Starting preparation");
+
+ auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
+ if (UNLIKELY(!vector.tryReserveCapacity(size))) {
+ StringBuilder builder;
+ builder.appendLiteral("Failed allocating enough space for ");
+ builder.appendNumber(size);
+ builder.append(what);
+ fail(holdLock(m_lock), builder.toString());
+ return false;
+ }
+ return true;
+ };
+
+ const auto& functionLocations = m_moduleInformation->functionLocationInBinary;
+ if (!tryReserveCapacity(m_wasmToWasmExitStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
+ || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, functionLocations.size(), " unlinked WebAssembly to WebAssembly calls")
+ || !tryReserveCapacity(m_wasmInternalFunctions, functionLocations.size(), " WebAssembly functions")
+ || !tryReserveCapacity(m_compilationContexts, functionLocations.size(), " compilation contexts")
+ || !tryReserveCapacity(m_tierUpCounts, functionLocations.size(), " tier-up counts"))
+ return;
+
+ m_unlinkedWasmToWasmCalls.resize(functionLocations.size());
+ m_wasmInternalFunctions.resize(functionLocations.size());
+ m_compilationContexts.resize(functionLocations.size());
+ m_tierUpCounts.resize(functionLocations.size());
+
+ for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) {
+ Import* import = &m_moduleInformation->imports[importIndex];
+ if (import->kind != ExternalKind::Function)
+ continue;
+ unsigned importFunctionIndex = m_wasmToWasmExitStubs.size();
+ dataLogLnIf(verbose, "Processing import function number ", importFunctionIndex, ": ", makeString(import->module), ": ", makeString(import->field));
+ m_wasmToWasmExitStubs.uncheckedAppend(wasmToWasm(importFunctionIndex));
+ }
+
+ moveToState(State::Prepared);
+}
+
+// We don't have a semaphore class... and this does kinda interesting things.
+class BBQPlan::ThreadCountHolder {
+public:
+ ThreadCountHolder(BBQPlan& plan)
+ : m_plan(plan)
+ {
+ LockHolder locker(m_plan.m_lock);
+ m_plan.m_numberOfActiveThreads++;
+ }
+
+ ~ThreadCountHolder()
+ {
+ LockHolder locker(m_plan.m_lock);
+ m_plan.m_numberOfActiveThreads--;
+
+ if (!m_plan.m_numberOfActiveThreads && !m_plan.hasWork())
+ m_plan.complete(locker);
+ }
+
+ BBQPlan& m_plan;
+};
+
+void BBQPlan::compileFunctions(CompilationEffort effort)
+{
+ ASSERT(m_state >= State::Prepared);
+ dataLogLnIf(verbose, "Starting compilation");
+
+ if (!hasWork())
+ return;
+
+ TraceScope traceScope(WebAssemblyCompileStart, WebAssemblyCompileEnd);
+ ThreadCountHolder holder(*this);
+
+ size_t bytesCompiled = 0;
+ const auto& functionLocations = m_moduleInformation->functionLocationInBinary;
+ while (true) {
+ if (effort == Partial && bytesCompiled >= Options::webAssemblyPartialCompileLimit())
+ return;
+
+ uint32_t functionIndex;
+ {
+ auto locker = holdLock(m_lock);
+ if (m_currentIndex >= functionLocations.size()) {
+ if (hasWork())
+ moveToState(State::Compiled);
+ return;
+ }
+ functionIndex = m_currentIndex;
+ ++m_currentIndex;
+ }
+
+ const uint8_t* functionStart = m_source + functionLocations[functionIndex].start;
+ size_t functionLength = functionLocations[functionIndex].end - functionLocations[functionIndex].start;
+ ASSERT(functionLength <= m_sourceLength);
+ SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+ const Signature& signature = SignatureInformation::get(signatureIndex);
+ unsigned functionIndexSpace = m_wasmToWasmExitStubs.size() + functionIndex;
+ ASSERT_UNUSED(functionIndexSpace, m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace) == signatureIndex);
+ ASSERT(validateFunction(functionStart, functionLength, signature, m_moduleInformation.get()));
+
+ m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
+ TierUpCount* tierUp = &m_tierUpCounts[functionIndex];
+ auto parseAndCompileResult = parseAndCompile(m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, tierUp);
+
+ if (UNLIKELY(!parseAndCompileResult)) {
+ auto locker = holdLock(m_lock);
+ if (!m_errorMessage) {
+ // Multiple compiles could fail simultaneously. We arbitrarily choose the first.
+ fail(locker, makeString(parseAndCompileResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected.
+ }
+ m_currentIndex = functionLocations.size();
+ return;
+ }
+
+ m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
+ bytesCompiled += functionLength;
+ }
+}
+
+void BBQPlan::complete(const AbstractLocker& locker)
+{
+ ASSERT(m_state != State::Compiled || m_currentIndex >= m_moduleInformation->functionLocationInBinary.size());
+ dataLogLnIf(verbose, "Starting Completion");
+
+ if (m_state == State::Compiled) {
+ for (uint32_t functionIndex = 0; functionIndex < m_moduleInformation->functionLocationInBinary.size(); functionIndex++) {
+ CompilationContext& context = m_compilationContexts[functionIndex];
+ SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+ {
+ LinkBuffer linkBuffer(*context.wasmEntrypointJIT, nullptr);
+ m_wasmInternalFunctions[functionIndex]->wasmEntrypoint.compilation = std::make_unique<B3::Compilation>(
+ FINALIZE_CODE(linkBuffer, ("WebAssembly function[%i] %s", functionIndex, SignatureInformation::get(signatureIndex).toString().ascii().data())),
+ WTFMove(context.wasmEntrypointByproducts));
+ }
+
+ {
+ LinkBuffer linkBuffer(*context.jsEntrypointJIT, nullptr);
+ m_wasmInternalFunctions[functionIndex]->jsToWasmEntrypoint.compilation = std::make_unique<B3::Compilation>(
+ FINALIZE_CODE(linkBuffer, ("JavaScript->WebAssembly entrypoint[%i] %s", functionIndex, SignatureInformation::get(signatureIndex).toString().ascii().data())),
+ WTFMove(context.jsEntrypointByproducts));
+ }
+ }
+
+ for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
+ for (auto& call : unlinked) {
+ void* executableAddress;
+ if (m_moduleInformation->isImportedFunctionFromFunctionIndexSpace(call.functionIndexSpace)) {
+ // FIXME imports could have been linked in B3, instead of generating a patchpoint. This condition should be replaced by a RELEASE_ASSERT. https://bugs.webkit.org/show_bug.cgi?id=166462
+ executableAddress = m_wasmToWasmExitStubs.at(call.functionIndexSpace).code().executableAddress();
+ } else
+ executableAddress = m_wasmInternalFunctions.at(call.functionIndexSpace - m_moduleInformation->importFunctionCount())->wasmEntrypoint.compilation->code().executableAddress();
+ MacroAssembler::repatchNearCall(call.callLocation, CodeLocationLabel(executableAddress));
+ }
+ }
+ }
+
+ if (!isComplete()) {
+ moveToState(State::Completed);
+ runCompletionTasks(locker);
+ }
+}
+
+void BBQPlan::work(CompilationEffort effort)
+{
+ switch (m_state) {
+ case State::Initial:
+ parseAndValidateModule();
+ if (!hasWork()) {
+ ASSERT(isComplete());
+ return;
+ }
+ FALLTHROUGH;
+ case State::Validated:
+ prepare();
+ return;
+ case State::Prepared:
+ compileFunctions(effort);
+ return;
+ default:
+ break;
+ }
+ return;
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)