зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1320374: Batch function compilations; r=luke
MozReview-Commit-ID: BmFx1UuesSL --HG-- extra : rebase_source : c43ae49d7cb048ec06b0c592894b8361758d7543
This commit is contained in:
Родитель
8a763f40ff
Коммит
ec79f44e1f
|
@ -173,7 +173,7 @@ struct TempObject
|
|||
"Placement new argument type must inherit from TempObject");
|
||||
MOZ_ASSERT(pos);
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -237,6 +237,16 @@ DefaultJitOptions::DefaultJitOptions()
|
|||
// included in the bounds check.
|
||||
SET_DEFAULT(wasmFoldOffsets, true);
|
||||
|
||||
// Until which wasm bytecode size should we accumulate functions, in order
|
||||
// to compile efficiently on helper threads (see also bug 1320374).
|
||||
SET_DEFAULT(wasmBatchThreshold, 10000);
|
||||
|
||||
// In order to have different batching thresholds for Ion and the wasm
|
||||
// baseline, and since a same batch can contain both Ion and baseline
|
||||
// compiled functions, we make Ion functions weight more by using a scaling
|
||||
// factor.
|
||||
SET_DEFAULT(wasmBatchIonScaleFactor, 9);
|
||||
|
||||
// Determines whether we suppress using signal handlers
|
||||
// for interrupting jit-ed code. This is used only for testing.
|
||||
SET_DEFAULT(ionInterruptWithoutSignals, false);
|
||||
|
|
|
@ -87,6 +87,8 @@ struct DefaultJitOptions
|
|||
uint32_t branchPruningBlockSpanFactor;
|
||||
uint32_t branchPruningEffectfulInstFactor;
|
||||
uint32_t branchPruningThreshold;
|
||||
uint32_t wasmBatchThreshold;
|
||||
uint32_t wasmBatchIonScaleFactor;
|
||||
mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
|
||||
mozilla::Maybe<uint32_t> forcedDefaultIonSmallFunctionWarmUpThreshold;
|
||||
mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
|
||||
|
|
|
@ -512,7 +512,7 @@ class BaseCompiler
|
|||
Assembler::Condition latentIntCmp_; // Comparison operator, if latentOp_ == Compare, int types
|
||||
Assembler::DoubleCondition latentDoubleCmp_;// Comparison operator, if latentOp_ == Compare, float types
|
||||
|
||||
FuncCompileResults& compileResults_;
|
||||
FuncOffsets offsets_;
|
||||
MacroAssembler& masm; // No '_' suffix - too tedious...
|
||||
|
||||
AllocatableGeneralRegisterSet availGPR_;
|
||||
|
@ -567,11 +567,12 @@ class BaseCompiler
|
|||
Decoder& decoder,
|
||||
const FuncBytes& func,
|
||||
const ValTypeVector& locals,
|
||||
FuncCompileResults& compileResults);
|
||||
TempAllocator* alloc,
|
||||
MacroAssembler* masm);
|
||||
|
||||
MOZ_MUST_USE bool init();
|
||||
|
||||
void finish();
|
||||
FuncOffsets finish();
|
||||
|
||||
MOZ_MUST_USE bool emitFunction();
|
||||
|
||||
|
@ -2053,7 +2054,7 @@ class BaseCompiler
|
|||
JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code");
|
||||
|
||||
SigIdDesc sigId = env_.funcSigs[func_.index()]->id;
|
||||
GenerateFunctionPrologue(masm, localSize_, sigId, &compileResults_.offsets());
|
||||
GenerateFunctionPrologue(masm, localSize_, sigId, &offsets_);
|
||||
|
||||
MOZ_ASSERT(masm.framePushed() == uint32_t(localSize_));
|
||||
|
||||
|
@ -2148,7 +2149,7 @@ class BaseCompiler
|
|||
// Restore the TLS register in case it was overwritten by the function.
|
||||
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
|
||||
|
||||
GenerateFunctionEpilogue(masm, localSize_, &compileResults_.offsets());
|
||||
GenerateFunctionEpilogue(masm, localSize_, &offsets_);
|
||||
|
||||
#if defined(JS_ION_PERF)
|
||||
// FIXME - profiling code missing. Bug 1286948.
|
||||
|
@ -2162,7 +2163,7 @@ class BaseCompiler
|
|||
|
||||
masm.wasmEmitTrapOutOfLineCode();
|
||||
|
||||
compileResults_.offsets().end = masm.currentOffset();
|
||||
offsets_.end = masm.currentOffset();
|
||||
|
||||
// A frame greater than 256KB is implausible, probably an attack,
|
||||
// so fail the compilation.
|
||||
|
@ -7540,12 +7541,13 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
|
|||
Decoder& decoder,
|
||||
const FuncBytes& func,
|
||||
const ValTypeVector& locals,
|
||||
FuncCompileResults& compileResults)
|
||||
TempAllocator* alloc,
|
||||
MacroAssembler* masm)
|
||||
: env_(env),
|
||||
iter_(decoder, func.lineOrBytecode()),
|
||||
func_(func),
|
||||
lastReadCallSite_(0),
|
||||
alloc_(compileResults.alloc()),
|
||||
alloc_(*alloc),
|
||||
locals_(locals),
|
||||
localSize_(0),
|
||||
varLow_(0),
|
||||
|
@ -7558,8 +7560,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
|
|||
latentType_(ValType::I32),
|
||||
latentIntCmp_(Assembler::Equal),
|
||||
latentDoubleCmp_(Assembler::DoubleEqual),
|
||||
compileResults_(compileResults),
|
||||
masm(compileResults_.masm()),
|
||||
masm(*masm),
|
||||
availGPR_(GeneralRegisterSet::All()),
|
||||
availFPU_(FloatRegisterSet::All()),
|
||||
#ifdef DEBUG
|
||||
|
@ -7702,13 +7703,15 @@ BaseCompiler::init()
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FuncOffsets
|
||||
BaseCompiler::finish()
|
||||
{
|
||||
MOZ_ASSERT(done(), "all bytes must be consumed");
|
||||
MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_);
|
||||
|
||||
masm.flushBuffer();
|
||||
|
||||
return offsets_;
|
||||
}
|
||||
|
||||
static LiveRegisterSet
|
||||
|
@ -7756,12 +7759,11 @@ js::wasm::BaselineCanCompile(const FunctionGenerator* fg)
|
|||
}
|
||||
|
||||
bool
|
||||
js::wasm::BaselineCompileFunction(CompileTask* task)
|
||||
js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit)
|
||||
{
|
||||
MOZ_ASSERT(task->mode() == CompileTask::CompileMode::Baseline);
|
||||
MOZ_ASSERT(unit->mode() == CompileMode::Baseline);
|
||||
|
||||
const FuncBytes& func = task->func();
|
||||
FuncCompileResults& results = task->results();
|
||||
const FuncBytes& func = unit->func();
|
||||
|
||||
Decoder d(func.bytes());
|
||||
|
||||
|
@ -7775,19 +7777,18 @@ js::wasm::BaselineCompileFunction(CompileTask* task)
|
|||
|
||||
// The MacroAssembler will sometimes access the jitContext.
|
||||
|
||||
JitContext jitContext(&results.alloc());
|
||||
JitContext jitContext(&task->alloc());
|
||||
|
||||
// One-pass baseline compilation.
|
||||
|
||||
BaseCompiler f(task->env(), d, func, locals, results);
|
||||
BaseCompiler f(task->env(), d, func, locals, &task->alloc(), &task->masm());
|
||||
if (!f.init())
|
||||
return false;
|
||||
|
||||
if (!f.emitFunction())
|
||||
return false;
|
||||
|
||||
f.finish();
|
||||
|
||||
unit->finish(f.finish());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace wasm {
|
|||
|
||||
class FunctionGenerator;
|
||||
class CompileTask;
|
||||
class FuncCompileUnit;
|
||||
|
||||
// Return true if BaselineCompileFunction can generate code for the
|
||||
// function held in the FunctionGenerator. If false is returned a
|
||||
|
@ -39,7 +40,7 @@ BaselineCanCompile(const FunctionGenerator* fg);
|
|||
|
||||
// Generate adequate code quickly.
|
||||
bool
|
||||
BaselineCompileFunction(CompileTask* task);
|
||||
BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -55,6 +55,8 @@ ModuleGenerator::ModuleGenerator()
|
|||
startOfUnpatchedCallsites_(0),
|
||||
parallel_(false),
|
||||
outstanding_(0),
|
||||
currentTask_(nullptr),
|
||||
batchedBytecode_(0),
|
||||
activeFuncDef_(nullptr),
|
||||
startedFuncDefs_(false),
|
||||
finishedFuncDefs_(false),
|
||||
|
@ -96,6 +98,8 @@ ModuleGenerator::~ModuleGenerator()
|
|||
} else {
|
||||
MOZ_ASSERT(!outstanding_);
|
||||
}
|
||||
MOZ_ASSERT_IF(finishedFuncDefs_, !batchedBytecode_);
|
||||
MOZ_ASSERT_IF(finishedFuncDefs_, !currentTask_);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -391,42 +395,45 @@ ModuleGenerator::patchFarJumps(const TrapExitOffsetArray& trapExits)
|
|||
bool
|
||||
ModuleGenerator::finishTask(CompileTask* task)
|
||||
{
|
||||
const FuncBytes& func = task->func();
|
||||
FuncCompileResults& results = task->results();
|
||||
|
||||
masm_.haltingAlign(CodeAlignment);
|
||||
|
||||
// Before merging in the new function's code, if calls in a prior function
|
||||
// body might go out of range, insert far jumps to extend the range.
|
||||
if ((masm_.size() - startOfUnpatchedCallsites_) + results.masm().size() > JumpRange()) {
|
||||
if ((masm_.size() - startOfUnpatchedCallsites_) + task->masm().size() > JumpRange()) {
|
||||
startOfUnpatchedCallsites_ = masm_.size();
|
||||
if (!patchCallSites())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Offset the recorded FuncOffsets by the offset of the function in the
|
||||
// whole module's code segment.
|
||||
uint32_t offsetInWhole = masm_.size();
|
||||
results.offsets().offsetBy(offsetInWhole);
|
||||
for (const FuncCompileUnit& unit : task->units()) {
|
||||
const FuncBytes& func = unit.func();
|
||||
|
||||
// Add the CodeRange for this function.
|
||||
uint32_t funcCodeRangeIndex = metadata_->codeRanges.length();
|
||||
if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
|
||||
return false;
|
||||
// Offset the recorded FuncOffsets by the offset of the function in the
|
||||
// whole module's code segment.
|
||||
FuncOffsets offsets = unit.offsets();
|
||||
offsets.offsetBy(offsetInWhole);
|
||||
|
||||
MOZ_ASSERT(!funcIsCompiled(func.index()));
|
||||
funcToCodeRange_[func.index()] = funcCodeRangeIndex;
|
||||
// Add the CodeRange for this function.
|
||||
uint32_t funcCodeRangeIndex = metadata_->codeRanges.length();
|
||||
if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), offsets))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!funcIsCompiled(func.index()));
|
||||
funcToCodeRange_[func.index()] = funcCodeRangeIndex;
|
||||
}
|
||||
|
||||
// Merge the compiled results into the whole-module masm.
|
||||
mozilla::DebugOnly<size_t> sizeBefore = masm_.size();
|
||||
if (!masm_.asmMergeWith(results.masm()))
|
||||
if (!masm_.asmMergeWith(task->masm()))
|
||||
return false;
|
||||
MOZ_ASSERT(masm_.size() == offsetInWhole + task->masm().size());
|
||||
|
||||
if (!task->reset(&freeFuncBytes_))
|
||||
return false;
|
||||
MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size());
|
||||
|
||||
UniqueBytes recycled;
|
||||
task->reset(&recycled);
|
||||
freeTasks_.infallibleAppend(task);
|
||||
return freeBytes_.emplaceBack(Move(recycled));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -864,15 +871,6 @@ ModuleGenerator::startFuncDefs()
|
|||
for (size_t i = 0; i < numTasks; i++)
|
||||
freeTasks_.infallibleAppend(&tasks_[i]);
|
||||
|
||||
if (!freeBytes_.reserve(numTasks))
|
||||
return false;
|
||||
for (size_t i = 0; i < numTasks; i++) {
|
||||
auto bytes = js::MakeUnique<Bytes>();
|
||||
if (!bytes)
|
||||
return false;
|
||||
freeBytes_.infallibleAppend(Move(bytes));
|
||||
}
|
||||
|
||||
startedFuncDefs_ = true;
|
||||
MOZ_ASSERT(!finishedFuncDefs_);
|
||||
return true;
|
||||
|
@ -885,58 +883,81 @@ ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg)
|
|||
MOZ_ASSERT(!activeFuncDef_);
|
||||
MOZ_ASSERT(!finishedFuncDefs_);
|
||||
|
||||
if (!freeBytes_.empty()) {
|
||||
fg->bytes_ = Move(freeBytes_.back());
|
||||
freeBytes_.popBack();
|
||||
if (!freeFuncBytes_.empty()) {
|
||||
fg->funcBytes_ = Move(freeFuncBytes_.back());
|
||||
freeFuncBytes_.popBack();
|
||||
} else {
|
||||
fg->bytes_ = js::MakeUnique<Bytes>();
|
||||
if (!fg->bytes_)
|
||||
fg->funcBytes_ = js::MakeUnique<FuncBytes>();
|
||||
if (!fg->funcBytes_)
|
||||
return false;
|
||||
}
|
||||
|
||||
fg->lineOrBytecode_ = lineOrBytecode;
|
||||
if (!currentTask_) {
|
||||
if (freeTasks_.empty() && !finishOutstandingTask())
|
||||
return false;
|
||||
currentTask_ = freeTasks_.popCopy();
|
||||
}
|
||||
|
||||
fg->funcBytes_->setLineOrBytecode(lineOrBytecode);
|
||||
fg->m_ = this;
|
||||
activeFuncDef_ = fg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::launchBatchCompile()
|
||||
{
|
||||
MOZ_ASSERT(currentTask_);
|
||||
|
||||
size_t numBatchedFuncs = currentTask_->units().length();
|
||||
MOZ_ASSERT(numBatchedFuncs);
|
||||
|
||||
if (parallel_) {
|
||||
if (!StartOffThreadWasmCompile(currentTask_))
|
||||
return false;
|
||||
outstanding_++;
|
||||
} else {
|
||||
if (!CompileFunction(currentTask_))
|
||||
return false;
|
||||
if (!finishTask(currentTask_))
|
||||
return false;
|
||||
}
|
||||
|
||||
currentTask_ = nullptr;
|
||||
batchedBytecode_ = 0;
|
||||
|
||||
numFinishedFuncDefs_ += numBatchedFuncs;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg)
|
||||
{
|
||||
MOZ_ASSERT(activeFuncDef_ == fg);
|
||||
|
||||
auto func = js::MakeUnique<FuncBytes>(Move(fg->bytes_),
|
||||
funcIndex,
|
||||
funcSig(funcIndex),
|
||||
fg->lineOrBytecode_,
|
||||
Move(fg->callSiteLineNums_));
|
||||
if (!func)
|
||||
return false;
|
||||
UniqueFuncBytes func = Move(fg->funcBytes_);
|
||||
|
||||
func->setFunc(funcIndex, &funcSig(funcIndex));
|
||||
|
||||
auto mode = alwaysBaseline_ && BaselineCanCompile(fg)
|
||||
? CompileTask::CompileMode::Baseline
|
||||
: CompileTask::CompileMode::Ion;
|
||||
? CompileMode::Baseline
|
||||
: CompileMode::Ion;
|
||||
|
||||
if (freeTasks_.empty() && !finishOutstandingTask())
|
||||
CheckedInt<uint32_t> newBatched = func->bytes().length();
|
||||
if (mode == CompileMode::Ion)
|
||||
newBatched *= JitOptions.wasmBatchIonScaleFactor;
|
||||
newBatched += batchedBytecode_;
|
||||
|
||||
if (!currentTask_->units().emplaceBack(Move(func), mode))
|
||||
return false;
|
||||
|
||||
CompileTask* task = freeTasks_.popCopy();
|
||||
task->init(Move(func), mode);
|
||||
|
||||
if (parallel_) {
|
||||
if (!StartOffThreadWasmCompile(task))
|
||||
return false;
|
||||
outstanding_++;
|
||||
} else {
|
||||
if (!CompileFunction(task))
|
||||
return false;
|
||||
if (!finishTask(task))
|
||||
return false;
|
||||
}
|
||||
if (newBatched.isValid() && newBatched.value() < JitOptions.wasmBatchThreshold)
|
||||
batchedBytecode_ = newBatched.value();
|
||||
else if (!launchBatchCompile())
|
||||
return false;
|
||||
|
||||
fg->m_ = nullptr;
|
||||
activeFuncDef_ = nullptr;
|
||||
numFinishedFuncDefs_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -947,6 +968,9 @@ ModuleGenerator::finishFuncDefs()
|
|||
MOZ_ASSERT(!activeFuncDef_);
|
||||
MOZ_ASSERT(!finishedFuncDefs_);
|
||||
|
||||
if (currentTask_ && !launchBatchCompile())
|
||||
return false;
|
||||
|
||||
while (outstanding_ > 0) {
|
||||
if (!finishOutstandingTask())
|
||||
return false;
|
||||
|
@ -1146,14 +1170,18 @@ wasm::CompileFunction(CompileTask* task)
|
|||
TraceLoggerThread* logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logCompile(logger, TraceLogger_WasmCompilation);
|
||||
|
||||
switch (task->mode()) {
|
||||
case wasm::CompileTask::CompileMode::Ion:
|
||||
return wasm::IonCompileFunction(task);
|
||||
case wasm::CompileTask::CompileMode::Baseline:
|
||||
return wasm::BaselineCompileFunction(task);
|
||||
case wasm::CompileTask::CompileMode::None:
|
||||
break;
|
||||
for (FuncCompileUnit& unit : task->units()) {
|
||||
switch (unit.mode()) {
|
||||
case CompileMode::Ion:
|
||||
if (!IonCompileFunction(task, &unit))
|
||||
return false;
|
||||
break;
|
||||
case CompileMode::Baseline:
|
||||
if (!BaselineCompileFunction(task, &unit))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CRASH("Uninitialized task");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -36,124 +36,158 @@ struct CompileArgs;
|
|||
|
||||
class FunctionGenerator;
|
||||
|
||||
typedef Vector<UniqueBytes, 0, SystemAllocPolicy> UniqueBytesVector;
|
||||
|
||||
// The FuncBytes class represents a single, concurrently-compilable function.
|
||||
// A FuncBytes object is composed of the wasm function body bytes along with the
|
||||
// ambient metadata describing the function necessary to compile it.
|
||||
|
||||
class FuncBytes
|
||||
{
|
||||
UniqueBytes bytes_;
|
||||
Bytes bytes_;
|
||||
uint32_t index_;
|
||||
const SigWithId& sig_;
|
||||
const SigWithId* sig_;
|
||||
uint32_t lineOrBytecode_;
|
||||
Uint32Vector callSiteLineNums_;
|
||||
|
||||
public:
|
||||
FuncBytes(UniqueBytes bytes,
|
||||
uint32_t index,
|
||||
const SigWithId& sig,
|
||||
uint32_t lineOrBytecode,
|
||||
Uint32Vector&& callSiteLineNums)
|
||||
: bytes_(Move(bytes)),
|
||||
index_(index),
|
||||
sig_(sig),
|
||||
lineOrBytecode_(lineOrBytecode),
|
||||
callSiteLineNums_(Move(callSiteLineNums))
|
||||
FuncBytes()
|
||||
: index_(UINT32_MAX),
|
||||
sig_(nullptr),
|
||||
lineOrBytecode_(UINT32_MAX)
|
||||
{}
|
||||
|
||||
Bytes& bytes() { return *bytes_; }
|
||||
const Bytes& bytes() const { return *bytes_; }
|
||||
UniqueBytes recycle() { return Move(bytes_); }
|
||||
Bytes& bytes() {
|
||||
return bytes_;
|
||||
}
|
||||
MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
|
||||
return callSiteLineNums_.append(lineno);
|
||||
}
|
||||
void setLineOrBytecode(uint32_t lineOrBytecode) {
|
||||
MOZ_ASSERT(lineOrBytecode_ == UINT32_MAX);
|
||||
lineOrBytecode_ = lineOrBytecode;
|
||||
}
|
||||
void setFunc(uint32_t index, const SigWithId* sig) {
|
||||
MOZ_ASSERT(index_ == UINT32_MAX);
|
||||
MOZ_ASSERT(sig_ == nullptr);
|
||||
index_ = index;
|
||||
sig_ = sig;
|
||||
}
|
||||
void reset() {
|
||||
bytes_.clear();
|
||||
index_ = UINT32_MAX;
|
||||
sig_ = nullptr;
|
||||
lineOrBytecode_ = UINT32_MAX;
|
||||
callSiteLineNums_.clear();
|
||||
}
|
||||
|
||||
const Bytes& bytes() const { return bytes_; }
|
||||
uint32_t index() const { return index_; }
|
||||
const SigWithId& sig() const { return sig_; }
|
||||
const SigWithId& sig() const { return *sig_; }
|
||||
uint32_t lineOrBytecode() const { return lineOrBytecode_; }
|
||||
const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; }
|
||||
};
|
||||
|
||||
typedef UniquePtr<FuncBytes> UniqueFuncBytes;
|
||||
typedef Vector<UniqueFuncBytes, 8, SystemAllocPolicy> UniqueFuncBytesVector;
|
||||
|
||||
// The FuncCompileResults class contains the results of compiling a single
|
||||
// function body, ready to be merged into the whole-module MacroAssembler.
|
||||
|
||||
class FuncCompileResults
|
||||
enum class CompileMode
|
||||
{
|
||||
jit::TempAllocator alloc_;
|
||||
jit::MacroAssembler masm_;
|
||||
FuncOffsets offsets_;
|
||||
|
||||
FuncCompileResults(const FuncCompileResults&) = delete;
|
||||
FuncCompileResults& operator=(const FuncCompileResults&) = delete;
|
||||
|
||||
public:
|
||||
explicit FuncCompileResults(LifoAlloc& lifo)
|
||||
: alloc_(&lifo),
|
||||
masm_(jit::MacroAssembler::WasmToken(), alloc_)
|
||||
{}
|
||||
|
||||
jit::TempAllocator& alloc() { return alloc_; }
|
||||
jit::MacroAssembler& masm() { return masm_; }
|
||||
FuncOffsets& offsets() { return offsets_; }
|
||||
Baseline,
|
||||
Ion
|
||||
};
|
||||
|
||||
// A CompileTask represents the task of compiling a single function body. An
|
||||
// CompileTask is filled with the wasm code to be compiled on the main
|
||||
// validation thread, sent off to a compilation helper thread which creates
|
||||
// the FuncCompileResults, and finally sent back to the validation thread. To
|
||||
// save time allocating and freeing memory, CompileTasks are reset() and
|
||||
// reused.
|
||||
// FuncCompileUnit contains all the data necessary to produce and store the
|
||||
// results of a single function's compilation.
|
||||
|
||||
class FuncCompileUnit
|
||||
{
|
||||
UniqueFuncBytes func_;
|
||||
CompileMode mode_;
|
||||
FuncOffsets offsets_;
|
||||
DebugOnly<bool> finished_;
|
||||
|
||||
public:
|
||||
FuncCompileUnit(UniqueFuncBytes func, CompileMode mode)
|
||||
: func_(Move(func)),
|
||||
mode_(mode),
|
||||
finished_(false)
|
||||
{}
|
||||
|
||||
const FuncBytes& func() const { return *func_; }
|
||||
CompileMode mode() const { return mode_; }
|
||||
FuncOffsets offsets() const { MOZ_ASSERT(finished_); return offsets_; }
|
||||
|
||||
void finish(FuncOffsets offsets) {
|
||||
MOZ_ASSERT(!finished_);
|
||||
offsets_ = offsets;
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
UniqueFuncBytes recycle() {
|
||||
MOZ_ASSERT(finished_);
|
||||
func_->reset();
|
||||
return Move(func_);
|
||||
}
|
||||
};
|
||||
|
||||
typedef Vector<FuncCompileUnit, 8, SystemAllocPolicy> FuncCompileUnitVector;
|
||||
|
||||
// A CompileTask represents the task of compiling a batch of functions. It is
|
||||
// filled with a certain number of function's bodies that are sent off to a
|
||||
// compilation helper thread, which fills in the resulting code offsets, and
|
||||
// finally sent back to the validation thread. To save time allocating and
|
||||
// freeing memory, CompileTasks are reset() and reused.
|
||||
|
||||
class CompileTask
|
||||
{
|
||||
public:
|
||||
enum class CompileMode { None, Baseline, Ion };
|
||||
|
||||
private:
|
||||
const ModuleEnvironment& env_;
|
||||
LifoAlloc lifo_;
|
||||
UniqueFuncBytes func_;
|
||||
CompileMode mode_;
|
||||
Maybe<FuncCompileResults> results_;
|
||||
const ModuleEnvironment& env_;
|
||||
LifoAlloc lifo_;
|
||||
Maybe<jit::TempAllocator> alloc_;
|
||||
Maybe<jit::MacroAssembler> masm_;
|
||||
FuncCompileUnitVector units_;
|
||||
|
||||
CompileTask(const CompileTask&) = delete;
|
||||
CompileTask& operator=(const CompileTask&) = delete;
|
||||
|
||||
void init() {
|
||||
alloc_.emplace(&lifo_);
|
||||
masm_.emplace(jit::MacroAssembler::WasmToken(), *alloc_);
|
||||
}
|
||||
|
||||
public:
|
||||
CompileTask(const ModuleEnvironment& env, size_t defaultChunkSize)
|
||||
: env_(env), lifo_(defaultChunkSize), func_(nullptr), mode_(CompileMode::None)
|
||||
{}
|
||||
: env_(env),
|
||||
lifo_(defaultChunkSize)
|
||||
{
|
||||
init();
|
||||
}
|
||||
LifoAlloc& lifo() {
|
||||
return lifo_;
|
||||
}
|
||||
jit::TempAllocator& alloc() {
|
||||
return *alloc_;
|
||||
}
|
||||
const ModuleEnvironment& env() const {
|
||||
return env_;
|
||||
}
|
||||
void init(UniqueFuncBytes func, CompileMode mode) {
|
||||
MOZ_ASSERT(!func_);
|
||||
func_ = Move(func);
|
||||
results_.emplace(lifo_);
|
||||
mode_ = mode;
|
||||
jit::MacroAssembler& masm() {
|
||||
return *masm_;
|
||||
}
|
||||
CompileMode mode() const {
|
||||
return mode_;
|
||||
FuncCompileUnitVector& units() {
|
||||
return units_;
|
||||
}
|
||||
const FuncBytes& func() const {
|
||||
MOZ_ASSERT(func_);
|
||||
return *func_;
|
||||
}
|
||||
FuncCompileResults& results() {
|
||||
return *results_;
|
||||
}
|
||||
void reset(UniqueBytes* recycled) {
|
||||
if (func_) {
|
||||
*recycled = Move(func_->recycle());
|
||||
(*recycled)->clear();
|
||||
bool reset(UniqueFuncBytesVector* freeFuncBytes) {
|
||||
for (FuncCompileUnit& unit : units_) {
|
||||
if (!freeFuncBytes->emplaceBack(Move(unit.recycle())))
|
||||
return false;
|
||||
}
|
||||
func_.reset(nullptr);
|
||||
results_.reset();
|
||||
|
||||
units_.clear();
|
||||
masm_.reset();
|
||||
alloc_.reset();
|
||||
lifo_.releaseAll();
|
||||
mode_ = CompileMode::None;
|
||||
|
||||
init();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -196,7 +230,9 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
uint32_t outstanding_;
|
||||
CompileTaskVector tasks_;
|
||||
CompileTaskPtrVector freeTasks_;
|
||||
UniqueBytesVector freeBytes_;
|
||||
UniqueFuncBytesVector freeFuncBytes_;
|
||||
CompileTask* currentTask_;
|
||||
uint32_t batchedBytecode_;
|
||||
|
||||
// Assertions
|
||||
DebugOnly<FunctionGenerator*> activeFuncDef_;
|
||||
|
@ -206,6 +242,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
|
||||
bool funcIsCompiled(uint32_t funcIndex) const;
|
||||
const CodeRange& funcCodeRange(uint32_t funcIndex) const;
|
||||
uint32_t numFuncImports() const;
|
||||
MOZ_MUST_USE bool patchCallSites(TrapExitOffsetArray* maybeTrapExits = nullptr);
|
||||
MOZ_MUST_USE bool patchFarJumps(const TrapExitOffsetArray& trapExits);
|
||||
MOZ_MUST_USE bool finishTask(CompileTask* task);
|
||||
|
@ -217,12 +254,11 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
|
||||
MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
|
||||
|
||||
MOZ_MUST_USE bool launchBatchCompile();
|
||||
|
||||
MOZ_MUST_USE bool initAsmJS(Metadata* asmJSMetadata);
|
||||
MOZ_MUST_USE bool initWasm();
|
||||
|
||||
// Functions declarations:
|
||||
uint32_t numFuncImports() const;
|
||||
|
||||
public:
|
||||
explicit ModuleGenerator();
|
||||
~ModuleGenerator();
|
||||
|
@ -275,10 +311,11 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
};
|
||||
|
||||
// A FunctionGenerator encapsulates the generation of a single function body.
|
||||
// ModuleGenerator::startFunc must be called after construction and before doing
|
||||
// anything else. After the body is complete, ModuleGenerator::finishFunc must
|
||||
// be called before the FunctionGenerator is destroyed and the next function is
|
||||
// started.
|
||||
// ModuleGenerator::startFuncDef must be called after construction and before
|
||||
// doing anything else.
|
||||
//
|
||||
// After the body is complete, ModuleGenerator::finishFuncDef must be called
|
||||
// before the FunctionGenerator is destroyed and the next function is started.
|
||||
|
||||
class MOZ_STACK_CLASS FunctionGenerator
|
||||
{
|
||||
|
@ -288,16 +325,11 @@ class MOZ_STACK_CLASS FunctionGenerator
|
|||
bool usesSimd_;
|
||||
bool usesAtomics_;
|
||||
|
||||
// Data created during function generation, then handed over to the
|
||||
// FuncBytes in ModuleGenerator::finishFunc().
|
||||
UniqueBytes bytes_;
|
||||
Uint32Vector callSiteLineNums_;
|
||||
|
||||
uint32_t lineOrBytecode_;
|
||||
UniqueFuncBytes funcBytes_;
|
||||
|
||||
public:
|
||||
FunctionGenerator()
|
||||
: m_(nullptr), usesSimd_(false), usesAtomics_(false), bytes_(nullptr), lineOrBytecode_(0)
|
||||
: m_(nullptr), usesSimd_(false), usesAtomics_(false), funcBytes_(nullptr)
|
||||
{}
|
||||
|
||||
bool usesSimd() const {
|
||||
|
@ -315,10 +347,10 @@ class MOZ_STACK_CLASS FunctionGenerator
|
|||
}
|
||||
|
||||
Bytes& bytes() {
|
||||
return *bytes_;
|
||||
return funcBytes_->bytes();
|
||||
}
|
||||
MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
|
||||
return callSiteLineNums_.append(lineno);
|
||||
return funcBytes_->addCallSiteLineNum(lineno);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -168,8 +168,6 @@ class FunctionCompiler
|
|||
uint32_t blockDepth_;
|
||||
ControlFlowPatchsVector blockPatches_;
|
||||
|
||||
FuncCompileResults& compileResults_;
|
||||
|
||||
// TLS pointer argument to the current function.
|
||||
MWasmParameter* tlsPointer_;
|
||||
|
||||
|
@ -178,8 +176,7 @@ class FunctionCompiler
|
|||
Decoder& decoder,
|
||||
const FuncBytes& func,
|
||||
const ValTypeVector& locals,
|
||||
MIRGenerator& mirGen,
|
||||
FuncCompileResults& compileResults)
|
||||
MIRGenerator& mirGen)
|
||||
: env_(env),
|
||||
iter_(decoder, func.lineOrBytecode()),
|
||||
func_(func),
|
||||
|
@ -194,14 +191,12 @@ class FunctionCompiler
|
|||
maxStackArgBytes_(0),
|
||||
loopDepth_(0),
|
||||
blockDepth_(0),
|
||||
compileResults_(compileResults),
|
||||
tlsPointer_(nullptr)
|
||||
{}
|
||||
|
||||
const ModuleEnvironment& env() const { return env_; }
|
||||
IonOpIter& iter() { return iter_; }
|
||||
TempAllocator& alloc() const { return alloc_; }
|
||||
MacroAssembler& masm() const { return compileResults_.masm(); }
|
||||
const Sig& sig() const { return func_.sig(); }
|
||||
|
||||
TrapOffset trapOffset() const {
|
||||
|
@ -3697,12 +3692,12 @@ EmitExpr(FunctionCompiler& f)
|
|||
}
|
||||
|
||||
bool
|
||||
wasm::IonCompileFunction(CompileTask* task)
|
||||
wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit)
|
||||
{
|
||||
MOZ_ASSERT(task->mode() == CompileTask::CompileMode::Ion);
|
||||
MOZ_ASSERT(unit->mode() == CompileMode::Ion);
|
||||
|
||||
const FuncBytes& func = task->func();
|
||||
FuncCompileResults& results = task->results();
|
||||
const FuncBytes& func = unit->func();
|
||||
const ModuleEnvironment& env = task->env();
|
||||
|
||||
Decoder d(func.bytes());
|
||||
|
||||
|
@ -3711,18 +3706,18 @@ wasm::IonCompileFunction(CompileTask* task)
|
|||
ValTypeVector locals;
|
||||
if (!locals.appendAll(func.sig().args()))
|
||||
return false;
|
||||
if (!DecodeLocalEntries(d, task->env().kind, &locals))
|
||||
if (!DecodeLocalEntries(d, env.kind, &locals))
|
||||
return false;
|
||||
|
||||
// Set up for Ion compilation.
|
||||
|
||||
JitContext jitContext(&results.alloc());
|
||||
JitContext jitContext(&task->alloc());
|
||||
const JitCompileOptions options;
|
||||
MIRGraph graph(&results.alloc());
|
||||
MIRGraph graph(&task->alloc());
|
||||
CompileInfo compileInfo(locals.length());
|
||||
MIRGenerator mir(nullptr, options, &results.alloc(), &graph, &compileInfo,
|
||||
MIRGenerator mir(nullptr, options, &task->alloc(), &graph, &compileInfo,
|
||||
IonOptimizations.get(OptimizationLevel::Wasm));
|
||||
mir.initMinWasmHeapLength(task->env().minMemoryLength);
|
||||
mir.initMinWasmHeapLength(env.minMemoryLength);
|
||||
|
||||
// Capture the prologue's trap site before decoding the function.
|
||||
|
||||
|
@ -3730,7 +3725,7 @@ wasm::IonCompileFunction(CompileTask* task)
|
|||
|
||||
// Build MIR graph
|
||||
{
|
||||
FunctionCompiler f(task->env(), d, func, locals, mir, results);
|
||||
FunctionCompiler f(env, d, func, locals, mir);
|
||||
if (!f.init())
|
||||
return false;
|
||||
|
||||
|
@ -3770,11 +3765,15 @@ wasm::IonCompileFunction(CompileTask* task)
|
|||
if (!lir)
|
||||
return false;
|
||||
|
||||
SigIdDesc sigId = task->env().funcSigs[func.index()]->id;
|
||||
SigIdDesc sigId = env.funcSigs[func.index()]->id;
|
||||
|
||||
CodeGenerator codegen(&mir, lir, &results.masm());
|
||||
if (!codegen.generateWasm(sigId, prologueTrapOffset, &results.offsets()))
|
||||
CodeGenerator codegen(&mir, lir, &task->masm());
|
||||
|
||||
FuncOffsets offsets;
|
||||
if (!codegen.generateWasm(sigId, prologueTrapOffset, &offsets))
|
||||
return false;
|
||||
|
||||
unit->finish(offsets);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -25,10 +25,11 @@ namespace js {
|
|||
namespace wasm {
|
||||
|
||||
class CompileTask;
|
||||
class FuncCompileUnit;
|
||||
|
||||
// Generates very fast code at the expense of compilation time.
|
||||
MOZ_MUST_USE bool
|
||||
IonCompileFunction(CompileTask* task);
|
||||
IonCompileFunction(CompileTask* task, FuncCompileUnit* unit);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
Загрузка…
Ссылка в новой задаче