зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1277562 - Part 9: Add Wasm Tier 2 compilation tasks. r=luke
--HG-- extra : rebase_source : 2b95eddcf25d17445b1a377bd3017538b663179c extra : source : da9e75d2e82c3e3564bb3e37230d384bcf7ffacf
This commit is contained in:
Родитель
8d4d063c52
Коммит
691c2c0203
|
@ -66,6 +66,7 @@ enum ThreadType {
|
|||
THREAD_TYPE_GCPARALLEL, // 7
|
||||
THREAD_TYPE_PROMISE_TASK, // 8
|
||||
THREAD_TYPE_ION_FREE, // 9
|
||||
THREAD_TYPE_WASM_TIER2, // 10
|
||||
THREAD_TYPE_MAX // Used to check shell function arguments
|
||||
};
|
||||
|
||||
|
|
|
@ -101,6 +101,24 @@ js::StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::StartOffThreadWasmTier2Generator(wasm::Tier2GeneratorTask* task)
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
|
||||
if (!HelperThreadState().wasmTier2GeneratorWorklist(lock).append(task))
|
||||
return false;
|
||||
|
||||
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
js::CancelOffThreadWasmTier2Generator()
|
||||
{
|
||||
// TODO: Implement this
|
||||
}
|
||||
|
||||
bool
|
||||
js::StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder)
|
||||
{
|
||||
|
@ -880,6 +898,7 @@ GlobalHelperThreadState::GlobalHelperThreadState()
|
|||
void
|
||||
GlobalHelperThreadState::finish()
|
||||
{
|
||||
CancelOffThreadWasmTier2Generator();
|
||||
finishThreads();
|
||||
|
||||
// Make sure there are no Ion free tasks left. We check this here because,
|
||||
|
@ -960,6 +979,7 @@ void
|
|||
GlobalHelperThreadState::waitForAllThreads()
|
||||
{
|
||||
CancelOffThreadIonCompile();
|
||||
CancelOffThreadWasmTier2Generator();
|
||||
|
||||
AutoLockHelperThreadState lock;
|
||||
while (hasActiveThreads(lock))
|
||||
|
@ -1061,6 +1081,12 @@ GlobalHelperThreadState::maxWasmCompilationThreads() const
|
|||
return cpuCount;
|
||||
}
|
||||
|
||||
size_t
|
||||
GlobalHelperThreadState::maxWasmTier2GeneratorThreads() const
|
||||
{
|
||||
return MaxTier2GeneratorTasks;
|
||||
}
|
||||
|
||||
size_t
|
||||
GlobalHelperThreadState::maxParseThreads() const
|
||||
{
|
||||
|
@ -1109,14 +1135,46 @@ GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lo
|
|||
if (wasmWorklist(lock, mode).empty() || wasmFailed(lock, mode))
|
||||
return false;
|
||||
|
||||
// Honor the maximum allowed threads to compile wasm jobs at once,
|
||||
// to avoid oversaturating the machine.
|
||||
if (!checkTaskThreadLimit<wasm::CompileTask*>(maxWasmCompilationThreads()))
|
||||
// For Tier1 and Once compilation, honor the maximum allowed threads to
|
||||
// compile wasm jobs at once, to avoid oversaturating the machine.
|
||||
//
|
||||
// For Tier2 compilation we need to allow other things to happen too, so for
|
||||
// now we only allow one thread.
|
||||
//
|
||||
// TODO: We should investigate more intelligent strategies, see bug 1380033.
|
||||
//
|
||||
// If Tier2 is very backlogged we must give priority to it, since the Tier2
|
||||
// queue holds onto Tier1 tasks. Indeed if Tier2 is backlogged we will
|
||||
// devote more resources to Tier2 and not start any Tier1 work at all.
|
||||
|
||||
bool tier2oversubscribed = wasmTier2GeneratorWorklist(lock).length() > 20;
|
||||
|
||||
size_t threads;
|
||||
if (mode == wasm::CompileMode::Tier2) {
|
||||
if (tier2oversubscribed)
|
||||
threads = maxWasmCompilationThreads();
|
||||
else
|
||||
threads = 1;
|
||||
} else {
|
||||
if (tier2oversubscribed)
|
||||
threads = 0;
|
||||
else
|
||||
threads = maxWasmCompilationThreads();
|
||||
}
|
||||
|
||||
if (!threads || !checkTaskThreadLimit<wasm::CompileTask*>(threads))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalHelperThreadState::canStartWasmTier2Generator(const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
return !wasmTier2GeneratorWorklist(lock).empty() &&
|
||||
checkTaskThreadLimit<wasm::Tier2GeneratorTask*>(maxWasmTier2GeneratorThreads());
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalHelperThreadState::canStartPromiseHelperTask(const AutoLockHelperThreadState& lock)
|
||||
{
|
||||
|
@ -1758,6 +1816,34 @@ HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::Compil
|
|||
currentTask.reset();
|
||||
}
|
||||
|
||||
void
|
||||
HelperThread::handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked)
|
||||
{
|
||||
MOZ_ASSERT(HelperThreadState().canStartWasmTier2Generator(locked));
|
||||
MOZ_ASSERT(idle());
|
||||
|
||||
currentTask.emplace(HelperThreadState().wasmTier2GeneratorWorklist(locked).popCopy());
|
||||
bool success = false;
|
||||
|
||||
wasm::Tier2GeneratorTask* task = wasmTier2GeneratorTask();
|
||||
{
|
||||
AutoUnlockHelperThreadState unlock(locked);
|
||||
success = wasm::GenerateTier2(task);
|
||||
}
|
||||
|
||||
// We silently ignore failures. Such failures must be resource exhaustion,
|
||||
// because all error checking was performed by the initial compilation.
|
||||
mozilla::Unused << success;
|
||||
|
||||
// During shutdown the main thread will wait for any ongoing (cancelled)
|
||||
// tier-2 generation to shut down normally. To do so, it waits on the
|
||||
// CONSUMER condition for the count of finished generators to rise.
|
||||
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
|
||||
|
||||
wasm::DeleteTier2GeneratorTask(task);
|
||||
currentTask.reset();
|
||||
}
|
||||
|
||||
void
|
||||
HelperThread::handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked)
|
||||
{
|
||||
|
@ -2205,6 +2291,8 @@ HelperThread::threadLoop()
|
|||
} else if (HelperThreadState().canStartWasmCompile(lock, wasm::CompileMode::Tier2)) {
|
||||
task = js::THREAD_TYPE_WASM;
|
||||
tier = wasm::CompileMode::Tier2;
|
||||
} else if (HelperThreadState().canStartWasmTier2Generator(lock)) {
|
||||
task = js::THREAD_TYPE_WASM_TIER2;
|
||||
} else {
|
||||
task = js::THREAD_TYPE_NONE;
|
||||
}
|
||||
|
@ -2241,6 +2329,9 @@ HelperThread::threadLoop()
|
|||
case js::THREAD_TYPE_ION_FREE:
|
||||
handleIonFreeWorkload(lock);
|
||||
break;
|
||||
case js::THREAD_TYPE_WASM_TIER2:
|
||||
handleWasmTier2GeneratorWorkload(lock);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("No task to perform");
|
||||
}
|
||||
|
|
|
@ -46,7 +46,9 @@ namespace wasm {
|
|||
class FuncIR;
|
||||
class FunctionCompileResults;
|
||||
class CompileTask;
|
||||
struct Tier2GeneratorTask;
|
||||
typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
|
||||
typedef Vector<Tier2GeneratorTask*, 0, SystemAllocPolicy> Tier2GeneratorTaskPtrVector;
|
||||
} // namespace wasm
|
||||
|
||||
enum class ParseTaskKind
|
||||
|
@ -64,6 +66,10 @@ class GlobalHelperThreadState
|
|||
friend class AutoUnlockHelperThreadState;
|
||||
|
||||
public:
|
||||
// A single tier-2 ModuleGenerator job spawns many compilation jobs, and we
|
||||
// do not want to allow more than one such ModuleGenerator to run at a time.
|
||||
static const size_t MaxTier2GeneratorTasks = 1;
|
||||
|
||||
// Number of CPUs to treat this machine as having when creating threads.
|
||||
// May be accessed without locking.
|
||||
size_t cpuCount;
|
||||
|
@ -91,6 +97,7 @@ class GlobalHelperThreadState
|
|||
// wasm worklist and finished jobs.
|
||||
wasm::CompileTaskPtrVector wasmWorklist_tier1_, wasmFinishedList_tier1_;
|
||||
wasm::CompileTaskPtrVector wasmWorklist_tier2_, wasmFinishedList_tier2_;
|
||||
wasm::Tier2GeneratorTaskPtrVector wasmTier2GeneratorWorklist_;
|
||||
|
||||
// For now, only allow a single parallel wasm compilation at each tier to
|
||||
// happen at a time. This avoids race conditions on
|
||||
|
@ -147,6 +154,7 @@ class GlobalHelperThreadState
|
|||
size_t maxIonCompilationThreads() const;
|
||||
size_t maxUnpausedIonCompilationThreads() const;
|
||||
size_t maxWasmCompilationThreads() const;
|
||||
size_t maxWasmTier2GeneratorThreads() const;
|
||||
size_t maxParseThreads() const;
|
||||
size_t maxCompressionThreads() const;
|
||||
size_t maxGCHelperThreads() const;
|
||||
|
@ -229,6 +237,10 @@ class GlobalHelperThreadState
|
|||
}
|
||||
}
|
||||
|
||||
wasm::Tier2GeneratorTaskPtrVector& wasmTier2GeneratorWorklist(const AutoLockHelperThreadState&) {
|
||||
return wasmTier2GeneratorWorklist_;
|
||||
}
|
||||
|
||||
PromiseHelperTaskVector& promiseHelperTasks(const AutoLockHelperThreadState&) {
|
||||
return promiseHelperTasks_;
|
||||
}
|
||||
|
@ -264,6 +276,7 @@ class GlobalHelperThreadState
|
|||
}
|
||||
|
||||
bool canStartWasmCompile(const AutoLockHelperThreadState& lock, wasm::CompileMode mode);
|
||||
bool canStartWasmTier2Generator(const AutoLockHelperThreadState& lock);
|
||||
bool canStartPromiseHelperTask(const AutoLockHelperThreadState& lock);
|
||||
bool canStartIonCompile(const AutoLockHelperThreadState& lock);
|
||||
bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
|
||||
|
@ -440,6 +453,7 @@ HelperThreadState()
|
|||
|
||||
typedef mozilla::Variant<jit::IonBuilder*,
|
||||
wasm::CompileTask*,
|
||||
wasm::Tier2GeneratorTask*,
|
||||
PromiseHelperTask*,
|
||||
ParseTask*,
|
||||
SourceCompressionTask*,
|
||||
|
@ -481,6 +495,10 @@ struct HelperThread
|
|||
return maybeCurrentTaskAs<wasm::CompileTask*>();
|
||||
}
|
||||
|
||||
wasm::Tier2GeneratorTask* wasmTier2GeneratorTask() {
|
||||
return maybeCurrentTaskAs<wasm::Tier2GeneratorTask*>();
|
||||
}
|
||||
|
||||
/* Any source being parsed/emitted on this thread. */
|
||||
ParseTask* parseTask() {
|
||||
return maybeCurrentTaskAs<ParseTask*>();
|
||||
|
@ -516,6 +534,7 @@ struct HelperThread
|
|||
}
|
||||
|
||||
void handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::CompileMode mode);
|
||||
void handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked);
|
||||
void handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked);
|
||||
void handleIonWorkload(AutoLockHelperThreadState& locked);
|
||||
void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
|
||||
|
@ -556,12 +575,25 @@ PauseCurrentHelperThread();
|
|||
bool
|
||||
StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode);
|
||||
|
||||
// Enqueues a wasm compilation task.
|
||||
bool
|
||||
StartOffThreadWasmTier2Generator(wasm::Tier2GeneratorTask* task);
|
||||
|
||||
// Cancel all background Wasm Tier-2 compilations.
|
||||
void
|
||||
CancelOffThreadWasmTier2Generator();
|
||||
|
||||
namespace wasm {
|
||||
|
||||
// Performs MIR optimization and LIR generation on one or several functions.
|
||||
MOZ_MUST_USE bool
|
||||
CompileFunction(CompileTask* task, UniqueChars* error);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
GenerateTier2(Tier2GeneratorTask* task);
|
||||
|
||||
void
|
||||
DeleteTier2GeneratorTask(Tier2GeneratorTask* task);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
_(ProcessExecutableRegion, 500) \
|
||||
_(WasmCodeProfilingLabels, 500) \
|
||||
_(OffThreadPromiseState, 500) \
|
||||
_(WasmTier2GeneratorComplete, 500) \
|
||||
\
|
||||
_(TraceLoggerGraphState, 600) \
|
||||
_(VTuneLock, 600)
|
||||
|
|
|
@ -1863,8 +1863,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
return false;
|
||||
}
|
||||
|
||||
CompileArgs args;
|
||||
if (!args.initFromContext(cx_, Move(scriptedCaller)))
|
||||
MutableCompileArgs args = cx_->new_<CompileArgs>();
|
||||
if (!args || !args->initFromContext(cx_, Move(scriptedCaller)))
|
||||
return false;
|
||||
|
||||
auto env = MakeUnique<ModuleEnvironment>(ModuleKind::AsmJS);
|
||||
|
@ -1880,7 +1880,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
|
||||
env->minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
|
||||
|
||||
if (!mg_.init(Move(env), args, CompileMode::Once, asmJSMetadata_.get()))
|
||||
if (!mg_.init(Move(env), *args, CompileMode::Once, asmJSMetadata_.get()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -2402,11 +2402,11 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
|
||||
// asm.js does not have any wasm bytecode to save; view-source is
|
||||
// provided through the ScriptSource.
|
||||
SharedBytes bytes = js_new<ShareableBytes>();
|
||||
SharedBytes bytes = cx_->new_<ShareableBytes>();
|
||||
if (!bytes)
|
||||
return nullptr;
|
||||
|
||||
return mg_.finish(*bytes);
|
||||
return mg_.finishModule(*bytes);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -393,6 +393,12 @@ class Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod
|
|||
const MetadataTier& metadata(Tier t) const;
|
||||
MetadataTier& metadata(Tier t);
|
||||
|
||||
UniquePtr<MetadataTier> takeMetadata(Tier tier) {
|
||||
MOZ_ASSERT(!hasTier2());
|
||||
MOZ_ASSERT(metadata1_->tier == tier);
|
||||
return Move(metadata1_);
|
||||
}
|
||||
|
||||
SigWithIdVector sigIds;
|
||||
GlobalDescVector globals;
|
||||
TableDescVector tables;
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
#include "wasm/WasmCompile.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "wasm/WasmBaselineCompile.h"
|
||||
|
@ -125,6 +128,12 @@ CompilerAvailability(ModuleKind kind, const CompileArgs& args, bool* baselineEna
|
|||
*ionEnabled = true;
|
||||
}
|
||||
|
||||
static bool
|
||||
BackgroundWorkPossible()
|
||||
{
|
||||
return CanUseExtraThreads() && HelperThreadState().cpuCount > 1;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm::GetDebugEnabled(const CompileArgs& args, ModuleKind kind)
|
||||
{
|
||||
|
@ -140,7 +149,7 @@ wasm::GetInitialCompileMode(const CompileArgs& args, ModuleKind kind)
|
|||
bool baselineEnabled, debugEnabled, ionEnabled;
|
||||
CompilerAvailability(kind, args, &baselineEnabled, &debugEnabled, &ionEnabled);
|
||||
|
||||
return (baselineEnabled && ionEnabled && !debugEnabled)
|
||||
return BackgroundWorkPossible() && baselineEnabled && ionEnabled && !debugEnabled
|
||||
? CompileMode::Tier1
|
||||
: CompileMode::Once;
|
||||
}
|
||||
|
@ -168,33 +177,106 @@ wasm::GetTier(const CompileArgs& args, CompileMode compileMode, ModuleKind kind)
|
|||
}
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
struct Tier2GeneratorTask
|
||||
{
|
||||
// The module that wants the results of the compilation
|
||||
SharedModule module;
|
||||
|
||||
// The arguments for the compilation
|
||||
SharedCompileArgs compileArgs;
|
||||
|
||||
Tier2GeneratorTask(Module& module, const CompileArgs& compileArgs)
|
||||
: module(&module),
|
||||
compileArgs(&compileArgs)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
Compile(ModuleGenerator& mg, const ShareableBytes& bytecode, const CompileArgs& args,
|
||||
UniqueChars* error, CompileMode compileMode)
|
||||
{
|
||||
auto env = js::MakeUnique<ModuleEnvironment>();
|
||||
if (!env)
|
||||
return false;
|
||||
|
||||
Decoder d(bytecode.bytes, error);
|
||||
if (!DecodeModuleEnvironment(d, env.get()))
|
||||
return false;
|
||||
|
||||
if (!mg.init(Move(env), args, compileMode))
|
||||
return false;
|
||||
|
||||
if (!DecodeCodeSection(d, mg))
|
||||
return false;
|
||||
|
||||
if (!DecodeModuleTail(d, &mg.mutableEnv()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SharedModule
|
||||
wasm::Compile(const ShareableBytes& bytecode, const CompileArgs& args, UniqueChars* error)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
|
||||
|
||||
Decoder d(bytecode.bytes, error);
|
||||
|
||||
auto env = js::MakeUnique<ModuleEnvironment>();
|
||||
if (!env)
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeModuleEnvironment(d, env.get()))
|
||||
return nullptr;
|
||||
|
||||
CompileMode compileMode = GetInitialCompileMode(args);
|
||||
|
||||
ModuleGenerator mg(error);
|
||||
if (!mg.init(Move(env), args, compileMode))
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeCodeSection(d, mg))
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeModuleTail(d, &mg.mutableEnv()))
|
||||
CompileMode mode = GetInitialCompileMode(args);
|
||||
if (!::Compile(mg, bytecode, args, error, mode))
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(!*error, "unreported error in decoding");
|
||||
|
||||
return mg.finish(bytecode);
|
||||
SharedModule module = mg.finishModule(bytecode);
|
||||
if (!module)
|
||||
return nullptr;
|
||||
|
||||
if (mode == CompileMode::Tier1) {
|
||||
MOZ_ASSERT(BackgroundWorkPossible());
|
||||
|
||||
auto task = js::MakeUnique<Tier2GeneratorTask>(*module, args);
|
||||
if (!task) {
|
||||
module->unblockOnTier2GeneratorFinished(CompileMode::Once);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!StartOffThreadWasmTier2Generator(&*task)) {
|
||||
module->unblockOnTier2GeneratorFinished(CompileMode::Once);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::Unused << task.release();
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
// This runs on a helper thread.
|
||||
bool
|
||||
wasm::GenerateTier2(Tier2GeneratorTask* task)
|
||||
{
|
||||
UniqueChars error;
|
||||
ModuleGenerator mg(&error);
|
||||
|
||||
bool res =
|
||||
::Compile(mg, task->module->bytecode(), *task->compileArgs, &error, CompileMode::Tier2) &&
|
||||
mg.finishTier2(task->module->bytecode(), task->module);
|
||||
|
||||
task->module->unblockOnTier2GeneratorFinished(res ? CompileMode::Tier2 : CompileMode::Once);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
wasm::DeleteTier2GeneratorTask(Tier2GeneratorTask* task)
|
||||
{
|
||||
js_delete(task);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ struct ScriptedCaller
|
|||
|
||||
// Describes all the parameters that control wasm compilation.
|
||||
|
||||
struct CompileArgs
|
||||
struct CompileArgs : ShareableBase<CompileArgs>
|
||||
{
|
||||
Assumptions assumptions;
|
||||
ScriptedCaller scriptedCaller;
|
||||
|
@ -57,6 +57,9 @@ struct CompileArgs
|
|||
bool initFromContext(JSContext* cx, ScriptedCaller&& scriptedCaller);
|
||||
};
|
||||
|
||||
typedef RefPtr<CompileArgs> MutableCompileArgs;
|
||||
typedef RefPtr<const CompileArgs> SharedCompileArgs;
|
||||
|
||||
// Compile the given WebAssembly bytecode with the given arguments into a
|
||||
// wasm::Module. On success, the Module is returned. On failure, the returned
|
||||
// SharedModule pointer is null and either:
|
||||
|
@ -75,10 +78,11 @@ bool
|
|||
GetDebugEnabled(const CompileArgs& args, ModuleKind kind = ModuleKind::Wasm);
|
||||
|
||||
// Select the mode for the initial compilation of a module. The mode is "Tier1"
|
||||
// precisely if both compilers are available and we're not debugging, and in
|
||||
// that case, we'll compile twice, with the mode set to "Tier2" during the
|
||||
// second compilation. Otherwise, the tier is "Once" and we'll compile once,
|
||||
// with the appropriate compiler.
|
||||
// precisely if both compilers are available, we're not debugging, and it is
|
||||
// possible to compile in the background, and in that case, we'll compile twice,
|
||||
// with the mode set to "Tier2" during the second (background) compilation.
|
||||
// Otherwise, the tier is "Once" and we'll compile once, with the appropriate
|
||||
// compiler.
|
||||
|
||||
CompileMode
|
||||
GetInitialCompileMode(const CompileArgs& args, ModuleKind kind = ModuleKind::Wasm);
|
||||
|
|
|
@ -1133,22 +1133,13 @@ ModuleGenerator::generateBytecodeHash(const ShareableBytes& bytecode)
|
|||
memcpy(metadata_->hash, hash, sizeof(ModuleHash));
|
||||
}
|
||||
|
||||
SharedModule
|
||||
ModuleGenerator::finish(const ShareableBytes& bytecode)
|
||||
bool
|
||||
ModuleGenerator::finishMetadata(const ShareableBytes& bytecode)
|
||||
{
|
||||
MOZ_ASSERT(!activeFuncDef_);
|
||||
MOZ_ASSERT(finishedFuncDefs_);
|
||||
|
||||
if (!finishFuncExports())
|
||||
return nullptr;
|
||||
|
||||
if (!finishCodegen())
|
||||
return nullptr;
|
||||
|
||||
// Convert the CallSiteAndTargetVector (needed during generation) to a
|
||||
// CallSiteVector (what is stored in the Module).
|
||||
if (!metadataTier_->callSites.appendAll(masm_.callSites()))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
// The MacroAssembler has accumulated all the memory accesses during codegen.
|
||||
metadataTier_->memoryAccesses = masm_.extractMemoryAccesses();
|
||||
|
@ -1179,7 +1170,27 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
|||
// For asm.js, the tables vector is over-allocated (to avoid resize during
|
||||
// parallel copilation). Shrink it back down to fit.
|
||||
if (isAsmJS() && !metadata_->tables.resize(numTables_))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
generateBytecodeHash(bytecode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishCommon(const ShareableBytes& bytecode)
|
||||
{
|
||||
MOZ_ASSERT(!activeFuncDef_);
|
||||
MOZ_ASSERT(finishedFuncDefs_);
|
||||
|
||||
if (!finishFuncExports())
|
||||
return false;
|
||||
|
||||
if (!finishCodegen())
|
||||
return false;
|
||||
|
||||
if (!finishMetadata(bytecode))
|
||||
return false;
|
||||
|
||||
// Assert CodeRanges are sorted.
|
||||
#ifdef DEBUG
|
||||
|
@ -1200,9 +1211,18 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
|||
#endif
|
||||
|
||||
if (!finishLinkData())
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
generateBytecodeHash(bytecode);
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedModule
|
||||
ModuleGenerator::finishModule(const ShareableBytes& bytecode)
|
||||
{
|
||||
MOZ_ASSERT(compileMode_ == CompileMode::Once || compileMode_ == CompileMode::Tier1);
|
||||
|
||||
if (!finishCommon(bytecode))
|
||||
return nullptr;
|
||||
|
||||
UniqueConstCodeSegment codeSegment = CodeSegment::create(tier_,
|
||||
masm_,
|
||||
|
@ -1227,7 +1247,8 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
|||
if (!code)
|
||||
return nullptr;
|
||||
|
||||
return SharedModule(js_new<Module>(Move(assumptions_),
|
||||
return SharedModule(js_new<Module>(compileMode_,
|
||||
Move(assumptions_),
|
||||
*code,
|
||||
Move(maybeDebuggingBytes),
|
||||
Move(linkData_),
|
||||
|
@ -1238,6 +1259,31 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
|
|||
bytecode));
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishTier2(const ShareableBytes& bytecode, SharedModule module)
|
||||
{
|
||||
MOZ_ASSERT(compileMode_ == CompileMode::Tier2);
|
||||
|
||||
if (!finishCommon(bytecode))
|
||||
return false;
|
||||
|
||||
UniqueConstCodeSegment codeSegment = CodeSegment::create(tier_,
|
||||
masm_,
|
||||
bytecode,
|
||||
*linkDataTier_,
|
||||
*metadata_);
|
||||
if (!codeSegment)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!metadata_->debugEnabled);
|
||||
|
||||
module->finishTier2Generator(linkData_.takeLinkData(tier_),
|
||||
metadata_->takeMetadata(tier_),
|
||||
Move(codeSegment),
|
||||
Move(env_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm::CompileFunction(CompileTask* task, UniqueChars* error)
|
||||
{
|
||||
|
|
|
@ -201,6 +201,8 @@ class CompileTask
|
|||
}
|
||||
};
|
||||
|
||||
struct Tier2GeneratorTask;
|
||||
|
||||
// A ModuleGenerator encapsulates the creation of a wasm module. During the
|
||||
// lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created
|
||||
// and destroyed to compile the individual function bodies. After generating all
|
||||
|
@ -268,6 +270,8 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
MOZ_MUST_USE bool finishCodegen();
|
||||
MOZ_MUST_USE bool finishLinkData();
|
||||
void generateBytecodeHash(const ShareableBytes& bytecode);
|
||||
MOZ_MUST_USE bool finishMetadata(const ShareableBytes& bytecode);
|
||||
MOZ_MUST_USE bool finishCommon(const ShareableBytes& bytecode);
|
||||
MOZ_MUST_USE bool addFuncImport(const Sig& sig, uint32_t globalDataOffset);
|
||||
MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
|
||||
MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
|
||||
|
@ -328,7 +332,11 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
MOZ_MUST_USE bool addExport(CacheableChars&& fieldChars, uint32_t funcIndex);
|
||||
|
||||
// Finish compilation of the given bytecode.
|
||||
SharedModule finish(const ShareableBytes& bytecode);
|
||||
SharedModule finishModule(const ShareableBytes& bytecode);
|
||||
|
||||
// Finish compilation of the given bytecode, installing tier-variant parts
|
||||
// for Tier 2 into module.
|
||||
MOZ_MUST_USE bool finishTier2(const ShareableBytes& bytecode, SharedModule module);
|
||||
};
|
||||
|
||||
// A FunctionGenerator encapsulates the generation of a single function body.
|
||||
|
|
|
@ -385,12 +385,12 @@ wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj
|
|||
if (!DescribeScriptedCaller(cx, &scriptedCaller))
|
||||
return false;
|
||||
|
||||
CompileArgs compileArgs;
|
||||
if (!compileArgs.initFromContext(cx, Move(scriptedCaller)))
|
||||
MutableCompileArgs compileArgs = cx->new_<CompileArgs>();
|
||||
if (!compileArgs || !compileArgs->initFromContext(cx, Move(scriptedCaller)))
|
||||
return false;
|
||||
|
||||
UniqueChars error;
|
||||
SharedModule module = Compile(*bytecode, compileArgs, &error);
|
||||
SharedModule module = Compile(*bytecode, *compileArgs, &error);
|
||||
if (!module) {
|
||||
if (error) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
|
||||
|
@ -887,12 +887,12 @@ WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!GetBufferSource(cx, &callArgs[0].toObject(), JSMSG_WASM_BAD_BUF_ARG, &bytecode))
|
||||
return false;
|
||||
|
||||
CompileArgs compileArgs;
|
||||
if (!InitCompileArgs(cx, &compileArgs))
|
||||
MutableCompileArgs compileArgs = cx->new_<CompileArgs>();
|
||||
if (!compileArgs || !InitCompileArgs(cx, compileArgs.get()))
|
||||
return false;
|
||||
|
||||
UniqueChars error;
|
||||
SharedModule module = Compile(*bytecode, compileArgs, &error);
|
||||
SharedModule module = Compile(*bytecode, *compileArgs, &error);
|
||||
if (!module) {
|
||||
if (error) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
|
||||
|
@ -1899,7 +1899,8 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<Promise
|
|||
}
|
||||
|
||||
static bool
|
||||
ResolveCompilation(JSContext* cx, Module& module, Handle<PromiseObject*> promise)
|
||||
ResolveCompilation(JSContext* cx, Module& module, const CompileArgs& compileArgs,
|
||||
Handle<PromiseObject*> promise)
|
||||
{
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
|
||||
RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
|
||||
|
@ -1912,23 +1913,23 @@ ResolveCompilation(JSContext* cx, Module& module, Handle<PromiseObject*> promise
|
|||
|
||||
struct CompilePromiseTask : PromiseHelperTask
|
||||
{
|
||||
MutableBytes bytecode;
|
||||
CompileArgs compileArgs;
|
||||
UniqueChars error;
|
||||
SharedModule module;
|
||||
MutableBytes bytecode;
|
||||
SharedCompileArgs compileArgs;
|
||||
UniqueChars error;
|
||||
SharedModule module;
|
||||
|
||||
CompilePromiseTask(JSContext* cx, Handle<PromiseObject*> promise)
|
||||
: PromiseHelperTask(cx, promise)
|
||||
{}
|
||||
|
||||
void execute() override {
|
||||
module = Compile(*bytecode, compileArgs, &error);
|
||||
module = Compile(*bytecode, *compileArgs, &error);
|
||||
}
|
||||
|
||||
bool resolve(JSContext* cx, Handle<PromiseObject*> promise) override {
|
||||
return module
|
||||
? ResolveCompilation(cx, *module, promise)
|
||||
: Reject(cx, compileArgs, Move(error), promise);
|
||||
? ResolveCompilation(cx, *module, *compileArgs, promise)
|
||||
: Reject(cx, *compileArgs, Move(error), promise);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1998,8 +1999,10 @@ WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!GetBufferSource(cx, callArgs, "WebAssembly.compile", &task->bytecode))
|
||||
return RejectWithPendingException(cx, promise, callArgs);
|
||||
|
||||
if (!InitCompileArgs(cx, &task->compileArgs))
|
||||
MutableCompileArgs compileArgs = cx->new_<CompileArgs>();
|
||||
if (!compileArgs || !InitCompileArgs(cx, compileArgs))
|
||||
return false;
|
||||
task->compileArgs = compileArgs;
|
||||
|
||||
if (!StartOffThreadPromiseHelperTask(cx, Move(task)))
|
||||
return false;
|
||||
|
@ -2009,8 +2012,8 @@ WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
static bool
|
||||
ResolveInstantiation(JSContext* cx, Module& module, HandleObject importObj,
|
||||
Handle<PromiseObject*> promise)
|
||||
ResolveInstantiation(JSContext* cx, Module& module, const CompileArgs& compileArgs,
|
||||
HandleObject importObj, Handle<PromiseObject*> promise)
|
||||
{
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
|
||||
RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
|
||||
|
@ -2040,24 +2043,26 @@ ResolveInstantiation(JSContext* cx, Module& module, HandleObject importObj,
|
|||
struct InstantiatePromiseTask : PromiseHelperTask
|
||||
{
|
||||
MutableBytes bytecode;
|
||||
CompileArgs compileArgs;
|
||||
SharedCompileArgs compileArgs;
|
||||
UniqueChars error;
|
||||
SharedModule module;
|
||||
PersistentRootedObject importObj;
|
||||
|
||||
InstantiatePromiseTask(JSContext* cx, Handle<PromiseObject*> promise, HandleObject importObj)
|
||||
InstantiatePromiseTask(JSContext* cx, Handle<PromiseObject*> promise,
|
||||
const CompileArgs& compileArgs, HandleObject importObj)
|
||||
: PromiseHelperTask(cx, promise),
|
||||
compileArgs(&compileArgs),
|
||||
importObj(cx, importObj)
|
||||
{}
|
||||
|
||||
void execute() override {
|
||||
module = Compile(*bytecode, compileArgs, &error);
|
||||
module = Compile(*bytecode, *compileArgs, &error);
|
||||
}
|
||||
|
||||
bool resolve(JSContext* cx, Handle<PromiseObject*> promise) override {
|
||||
return module
|
||||
? ResolveInstantiation(cx, *module, importObj, promise)
|
||||
: Reject(cx, compileArgs, Move(error), promise);
|
||||
? ResolveInstantiation(cx, *module, *compileArgs, importObj, promise)
|
||||
: Reject(cx, *compileArgs, Move(error), promise);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2105,16 +2110,17 @@ WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!PromiseObject::resolve(cx, promise, resolutionValue))
|
||||
return false;
|
||||
} else {
|
||||
auto task = cx->make_unique<InstantiatePromiseTask>(cx, promise, importObj);
|
||||
MutableCompileArgs compileArgs = cx->new_<CompileArgs>();
|
||||
if (!compileArgs || !InitCompileArgs(cx, compileArgs.get()))
|
||||
return false;
|
||||
|
||||
auto task = cx->make_unique<InstantiatePromiseTask>(cx, promise, *compileArgs, importObj);
|
||||
if (!task || !task->init(cx))
|
||||
return false;
|
||||
|
||||
if (!GetBufferSource(cx, firstArg, JSMSG_WASM_BAD_BUF_MOD_ARG, &task->bytecode))
|
||||
return RejectWithPendingException(cx, promise, callArgs);
|
||||
|
||||
if (!InitCompileArgs(cx, &task->compileArgs))
|
||||
return false;
|
||||
|
||||
if (!StartOffThreadPromiseHelperTask(cx, Move(task)))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "jsnspr.h"
|
||||
|
||||
#include "jit/JitOptions.h"
|
||||
#include "threading/LockGuard.h"
|
||||
#include "wasm/WasmCompile.h"
|
||||
#include "wasm/WasmInstance.h"
|
||||
#include "wasm/WasmJS.h"
|
||||
|
@ -262,6 +263,10 @@ Module::compiledSerializedSize() const
|
|||
if (metadata().debugEnabled)
|
||||
return 0;
|
||||
|
||||
blockOnIonCompileFinished();
|
||||
if (!code_->hasTier(Tier::Serialized))
|
||||
return 0;
|
||||
|
||||
return assumptions_.serializedSize() +
|
||||
linkData_.serializedSize() +
|
||||
SerializedVectorSize(imports_) +
|
||||
|
@ -279,9 +284,11 @@ Module::compiledSerialize(uint8_t* compiledBegin, size_t compiledSize) const
|
|||
return;
|
||||
}
|
||||
|
||||
// Assumption must be serialized at the beginning of the compiled bytes so
|
||||
// that compiledAssumptionsMatch can detect a build-id mismatch before any
|
||||
// other decoding occurs.
|
||||
blockOnIonCompileFinished();
|
||||
if (!code_->hasTier(Tier::Serialized)) {
|
||||
MOZ_RELEASE_ASSERT(compiledSize == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* cursor = compiledBegin;
|
||||
cursor = assumptions_.serialize(cursor);
|
||||
|
@ -294,6 +301,40 @@ Module::compiledSerialize(uint8_t* compiledBegin, size_t compiledSize) const
|
|||
MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
|
||||
}
|
||||
|
||||
void
|
||||
Module::finishTier2Generator(UniqueLinkDataTier linkData2, UniqueMetadataTier metadata2,
|
||||
UniqueConstCodeSegment code2, UniqueModuleEnvironment env2)
|
||||
{
|
||||
// Install the data in the data structures. They will not be visible yet.
|
||||
|
||||
metadata().setTier2(Move(metadata2));
|
||||
linkData().setTier2(Move(linkData2));
|
||||
code().setTier2(Move(code2));
|
||||
for (uint32_t i = 0; i < elemSegments_.length(); i++)
|
||||
elemSegments_[i].setTier2(Move(env2->elemSegments[i].elemCodeRangeIndices(Tier::Ion)));
|
||||
|
||||
// Set the flag atomically to make the tier 2 data visible everywhere at
|
||||
// once.
|
||||
|
||||
metadata().commitTier2();
|
||||
}
|
||||
|
||||
void
|
||||
Module::blockOnIonCompileFinished() const
|
||||
{
|
||||
LockGuard<Mutex> l(tier2Lock_);
|
||||
while (mode_ == CompileMode::Tier1 && !metadata().hasTier2())
|
||||
tier2Cond_.wait(l);
|
||||
}
|
||||
|
||||
void
|
||||
Module::unblockOnTier2GeneratorFinished(CompileMode newMode) const
|
||||
{
|
||||
LockGuard<Mutex> l(tier2Lock_);
|
||||
mode_ = newMode;
|
||||
tier2Cond_.notify_all();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Module::assumptionsMatch(const Assumptions& current, const uint8_t* compiledBegin, size_t remain)
|
||||
{
|
||||
|
@ -367,9 +408,10 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
|
|||
MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
|
||||
MOZ_RELEASE_ASSERT(!!maybeMetadata == code->metadata().isAsmJS());
|
||||
|
||||
return js_new<Module>(Move(assumptions),
|
||||
return js_new<Module>(CompileMode::Tier2, // Serialized code is always Tier 2
|
||||
Move(assumptions),
|
||||
*code,
|
||||
nullptr, // Serialized code is never debuggable
|
||||
nullptr, // Serialized code is never debuggable
|
||||
Move(linkData),
|
||||
Move(imports),
|
||||
Move(exports),
|
||||
|
@ -463,10 +505,12 @@ wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
|
|||
scriptedCaller.line = line;
|
||||
scriptedCaller.column = column;
|
||||
|
||||
CompileArgs args(Assumptions(Move(buildId)), Move(scriptedCaller));
|
||||
SharedCompileArgs args = js_new<CompileArgs>(Assumptions(Move(buildId)), Move(scriptedCaller));
|
||||
if (!args)
|
||||
return nullptr;
|
||||
|
||||
UniqueChars error;
|
||||
return Compile(*bytecode, Move(args), &error);
|
||||
return Compile(*bytecode, *args, &error);
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
|
|
|
@ -20,13 +20,18 @@
|
|||
#define wasm_module_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "threading/ConditionVariable.h"
|
||||
#include "threading/Mutex.h"
|
||||
#include "vm/MutexIDs.h"
|
||||
#include "wasm/WasmCode.h"
|
||||
#include "wasm/WasmTable.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
struct CompileArgs;
|
||||
|
||||
// LinkData contains all the metadata necessary to patch all the locations
|
||||
// that depend on the absolute address of a CodeSegment.
|
||||
//
|
||||
|
@ -95,6 +100,12 @@ class LinkData
|
|||
const LinkDataTier& linkData(Tier tier) const;
|
||||
LinkDataTier& linkData(Tier tier);
|
||||
|
||||
UniquePtr<LinkDataTier> takeLinkData(Tier tier) {
|
||||
MOZ_ASSERT(!hasTier2());
|
||||
MOZ_ASSERT(linkData1_->tier == tier);
|
||||
return Move(linkData1_);
|
||||
}
|
||||
|
||||
WASM_DECLARE_SERIALIZABLE(LinkData)
|
||||
};
|
||||
|
||||
|
@ -130,6 +141,20 @@ class Module : public JS::WasmModule
|
|||
|
||||
mutable mozilla::Atomic<bool> codeIsBusy_;
|
||||
|
||||
// The lock guards the mode_ member, and the lock/cond pair are used to
|
||||
// allow threads to wait for the availability of Ion code and signal the
|
||||
// completion of tier-2 compilation; see blockOnIonCompileFinished and
|
||||
// unblockOnTier2GeneratorFinished, below.
|
||||
|
||||
mutable Mutex tier2Lock_;
|
||||
mutable ConditionVariable tier2Cond_;
|
||||
|
||||
// Access mode_ only under the lock. It will be changed from Tier1 to Tier2
|
||||
// once Tier2 compilation is finished, and from Tier1 to Once if Tier2
|
||||
// compilation is disabled (in testing modes) or cancelled.
|
||||
|
||||
mutable CompileMode mode_;
|
||||
|
||||
bool instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const;
|
||||
bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const;
|
||||
bool instantiateTable(JSContext* cx,
|
||||
|
@ -142,7 +167,8 @@ class Module : public JS::WasmModule
|
|||
const ValVector& globalImports) const;
|
||||
|
||||
public:
|
||||
Module(Assumptions&& assumptions,
|
||||
Module(CompileMode mode,
|
||||
Assumptions&& assumptions,
|
||||
const Code& code,
|
||||
UniqueConstBytes unlinkedCodeForDebugging,
|
||||
LinkData&& linkData,
|
||||
|
@ -160,18 +186,23 @@ class Module : public JS::WasmModule
|
|||
dataSegments_(Move(dataSegments)),
|
||||
elemSegments_(Move(elemSegments)),
|
||||
bytecode_(&bytecode),
|
||||
codeIsBusy_(false)
|
||||
codeIsBusy_(false),
|
||||
tier2Lock_(js::mutexid::WasmTier2GeneratorComplete),
|
||||
mode_(mode)
|
||||
{
|
||||
MOZ_ASSERT_IF(metadata().debugEnabled, unlinkedCodeForDebugging_);
|
||||
}
|
||||
~Module() override { /* Note: can be called on any thread */ }
|
||||
|
||||
const Code& code() const { return *code_; }
|
||||
const CodeSegment& codeSegment(Tier t) const { return code_->segment(t); }
|
||||
const Metadata& metadata() const { return code_->metadata(); }
|
||||
const MetadataTier& metadata(Tier t) const { return code_->metadata(t); }
|
||||
const LinkData& linkData() const { return linkData_; }
|
||||
const LinkDataTier& linkData(Tier t) const { return linkData_.linkData(t); }
|
||||
const ImportVector& imports() const { return imports_; }
|
||||
const ExportVector& exports() const { return exports_; }
|
||||
const Bytes& bytecode() const { return bytecode_->bytes; }
|
||||
const ShareableBytes& bytecode() const { return *bytecode_; }
|
||||
uint32_t codeLength(Tier t) const { return code_->segment(t).length(); }
|
||||
|
||||
// Instantiate this module with the given imports:
|
||||
|
@ -184,6 +215,29 @@ class Module : public JS::WasmModule
|
|||
HandleObject instanceProto,
|
||||
MutableHandleWasmInstanceObject instanceObj) const;
|
||||
|
||||
// Tiered compilation support: these run on the compilation thread.
|
||||
|
||||
// Will be invoked once the second-tier compilation of the module is
|
||||
// finished; it is passed the tier-variant data for Tier 2, which it
|
||||
// installs in the module and makes visible.
|
||||
|
||||
void finishTier2Generator(UniqueLinkDataTier linkData2, UniqueMetadataTier metadata2,
|
||||
UniqueConstCodeSegment code2, UniqueModuleEnvironment env2);
|
||||
|
||||
// Wait until Ion-compiled code is available, which will be true either
|
||||
// immediately (first-level compile was Ion and is already done), not at all
|
||||
// (first-level compile was Baseline and there's not a second level), or
|
||||
// later (ongoing second-level compilation). Once this returns, one can use
|
||||
// code().hasTier() to check code availability - there is no guarantee that
|
||||
// Ion code will be available, but if it isn't then it never will.
|
||||
|
||||
void blockOnIonCompileFinished() const;
|
||||
|
||||
// Signal all waiters that are waiting on tier-2 compilation to be done that
|
||||
// they should wake up. They will be waiting in blockOnIonCompileFinished.
|
||||
|
||||
void unblockOnTier2GeneratorFinished(CompileMode newMode) const;
|
||||
|
||||
// Structured clone support:
|
||||
|
||||
size_t bytecodeSerializedSize() const override;
|
||||
|
|
Загрузка…
Ссылка в новой задаче