зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1224389 - Odin: simplify AsmJSModule global data allocation (r=bbouvier)
--HG-- extra : rebase_source : 20f174a9593293674e20e768f6d19f6ede861083
This commit is contained in:
Родитель
f7c5ebaa66
Коммит
4ef42db6e3
|
@ -130,9 +130,7 @@ static bool
|
|||
ValidateGlobalVariable(JSContext* cx, const AsmJSModule& module, AsmJSModule::Global& global,
|
||||
HandleValue importVal)
|
||||
{
|
||||
MOZ_ASSERT(global.which() == AsmJSModule::Global::Variable);
|
||||
|
||||
void* datum = module.globalVarToGlobalDatum(global);
|
||||
void* datum = module.globalData() + global.varGlobalDataOffset();
|
||||
|
||||
switch (global.varInitKind()) {
|
||||
case AsmJSModule::Global::InitConstant: {
|
||||
|
@ -588,10 +586,10 @@ DynamicallyLinkModule(JSContext* cx, const CallArgs& args, AsmJSModule& module)
|
|||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < module.numExits(); i++)
|
||||
module.exitIndexToGlobalDatum(i).fun = &ffis[module.exit(i).ffiIndex()]->as<JSFunction>();
|
||||
|
||||
module.initGlobalNaN();
|
||||
for (unsigned i = 0; i < module.numExits(); i++) {
|
||||
const AsmJSModule::Exit& exit = module.exit(i);
|
||||
exit.datum(module).fun = &ffis[exit.ffiIndex()]->as<JSFunction>();
|
||||
}
|
||||
|
||||
// See the comment in AllocateExecutableMemory.
|
||||
ExecutableAllocator::makeExecutable(module.codeBase(), module.codeBytes());
|
||||
|
@ -957,12 +955,7 @@ SendModuleToAttachedProfiler(JSContext* cx, AsmJSModule& module)
|
|||
if (IsVTuneProfilingActive() && !SendFunctionsToVTune(cx, module))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if defined(JS_ION_PERF)
|
||||
if (module.numExportedFunctions() > 0) {
|
||||
size_t firstEntryCode = size_t(module.codeBase() + module.functionBytes());
|
||||
writePerfSpewerAsmJSEntriesAndExits(firstEntryCode, module.codeBytes() - module.functionBytes());
|
||||
}
|
||||
if (!SendFunctionsToPerf(cx, module))
|
||||
return false;
|
||||
#endif
|
||||
|
|
|
@ -88,8 +88,7 @@ AsmJSModule::AsmJSModule(ScriptSource* scriptSource, uint32_t srcStart, uint32_t
|
|||
interrupted_(false)
|
||||
{
|
||||
mozilla::PodZero(&pod);
|
||||
pod.funcPtrTableAndExitBytes_ = SIZE_MAX;
|
||||
pod.functionBytes_ = UINT32_MAX;
|
||||
pod.globalBytes_ = sInitialGlobalDataBytes;
|
||||
pod.minHeapLength_ = RoundUpToNextValidAsmJSHeapLength(0);
|
||||
pod.maxHeapLength_ = 0x80000000;
|
||||
pod.strict_ = strict;
|
||||
|
@ -110,7 +109,7 @@ AsmJSModule::~AsmJSModule()
|
|||
|
||||
if (code_) {
|
||||
for (unsigned i = 0; i < numExits(); i++) {
|
||||
AsmJSModule::ExitDatum& exitDatum = exitIndexToGlobalDatum(i);
|
||||
AsmJSModule::ExitDatum& exitDatum = exit(i).datum(*this);
|
||||
if (!exitDatum.baselineScript)
|
||||
continue;
|
||||
|
||||
|
@ -130,19 +129,19 @@ AsmJSModule::~AsmJSModule()
|
|||
void
|
||||
AsmJSModule::trace(JSTracer* trc)
|
||||
{
|
||||
for (unsigned i = 0; i < globals_.length(); i++)
|
||||
globals_[i].trace(trc);
|
||||
for (unsigned i = 0; i < exits_.length(); i++) {
|
||||
if (exitIndexToGlobalDatum(i).fun)
|
||||
TraceEdge(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function");
|
||||
for (Global& global : globals_)
|
||||
global.trace(trc);
|
||||
for (Exit& exit : exits_) {
|
||||
if (exit.datum(*this).fun)
|
||||
TraceEdge(trc, &exit.datum(*this).fun, "asm.js imported function");
|
||||
}
|
||||
for (unsigned i = 0; i < exports_.length(); i++)
|
||||
exports_[i].trace(trc);
|
||||
for (unsigned i = 0; i < names_.length(); i++)
|
||||
TraceManuallyBarrieredEdge(trc, &names_[i].name(), "asm.js module function name");
|
||||
for (ExportedFunction& exp : exports_)
|
||||
exp.trace(trc);
|
||||
for (Name& name : names_)
|
||||
TraceManuallyBarrieredEdge(trc, &name.name(), "asm.js module function name");
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
for (unsigned i = 0; i < profiledFunctions_.length(); i++)
|
||||
profiledFunctions_[i].trace(trc);
|
||||
for (ProfiledFunction& profiledFunction : profiledFunctions_)
|
||||
profiledFunction.trace(trc);
|
||||
#endif
|
||||
if (globalArgumentName_)
|
||||
TraceManuallyBarrieredEdge(trc, &globalArgumentName_, "asm.js global argument name");
|
||||
|
@ -269,7 +268,7 @@ bool
|
|||
AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembler& masm,
|
||||
const Label& interruptLabel, const Label& outOfBoundsLabel)
|
||||
{
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
|
||||
uint32_t endBeforeCurly = tokenStream.currentToken().pos.end;
|
||||
TokenPos pos;
|
||||
|
@ -284,10 +283,11 @@ AsmJSModule::finish(ExclusiveContext* cx, TokenStream& tokenStream, MacroAssembl
|
|||
// Start global data on a new page so JIT code may be given independent
|
||||
// protection flags.
|
||||
pod.codeBytes_ = AlignBytes(masm.bytesNeeded(), AsmJSPageSize);
|
||||
MOZ_ASSERT(pod.functionBytes_ <= pod.codeBytes_);
|
||||
|
||||
// The entire region is allocated via mmap/VirtualAlloc which requires
|
||||
// units of pages.
|
||||
pod.totalBytes_ = AlignBytes(pod.codeBytes_ + globalDataBytes(), AsmJSPageSize);
|
||||
pod.totalBytes_ = AlignBytes(pod.codeBytes_ + pod.globalBytes_, AsmJSPageSize);
|
||||
|
||||
MOZ_ASSERT(!code_);
|
||||
code_ = AllocateExecutableMemory(cx, pod.totalBytes_);
|
||||
|
@ -506,14 +506,15 @@ TryEnablingJit(JSContext* cx, AsmJSModule& module, HandleFunction fun, uint32_t
|
|||
}
|
||||
|
||||
// The exit may have become optimized while executing the FFI.
|
||||
if (module.exitIsOptimized(exitIndex))
|
||||
AsmJSModule::Exit& exit = module.exit(exitIndex);
|
||||
if (exit.isOptimized(module))
|
||||
return true;
|
||||
|
||||
BaselineScript* baselineScript = script->baselineScript();
|
||||
if (!baselineScript->addDependentAsmJSModule(cx, DependentAsmJSModuleExit(&module, exitIndex)))
|
||||
return false;
|
||||
|
||||
module.optimizeExit(exitIndex, baselineScript);
|
||||
exit.optimize(module, baselineScript);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -524,7 +525,7 @@ InvokeFromAsmJS(AsmJSActivation* activation, int32_t exitIndex, int32_t argc, Va
|
|||
JSContext* cx = activation->cx();
|
||||
AsmJSModule& module = activation->module();
|
||||
|
||||
RootedFunction fun(cx, module.exitIndexToGlobalDatum(exitIndex).fun);
|
||||
RootedFunction fun(cx, module.exit(exitIndex).datum(module).fun);
|
||||
RootedValue fval(cx, ObjectValue(*fun));
|
||||
if (!Invoke(cx, UndefinedValue(), fval, argc, argv, rval))
|
||||
return false;
|
||||
|
@ -710,7 +711,6 @@ void
|
|||
AsmJSModule::staticallyLink(ExclusiveContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(!isStaticallyLinked());
|
||||
|
||||
// Process staticLinkData_
|
||||
|
||||
|
@ -762,14 +762,11 @@ AsmJSModule::staticallyLink(ExclusiveContext* cx)
|
|||
|
||||
// Initialize global data segment
|
||||
|
||||
for (size_t i = 0; i < exits_.length(); i++) {
|
||||
ExitDatum& exitDatum = exitIndexToGlobalDatum(i);
|
||||
exitDatum.exit = interpExitTrampoline(exits_[i]);
|
||||
exitDatum.fun = nullptr;
|
||||
exitDatum.baselineScript = nullptr;
|
||||
}
|
||||
*(double*)(globalData() + AsmJSNaN64GlobalDataOffset) = GenericNaN();
|
||||
*(float*)(globalData() + AsmJSNaN32GlobalDataOffset) = GenericNaN();
|
||||
|
||||
MOZ_ASSERT(isStaticallyLinked());
|
||||
for (AsmJSModule::Exit& exit : exits_)
|
||||
exit.initDatum(*this);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1801,7 +1798,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext* cx)
|
|||
// profiling prologues:
|
||||
for (size_t i = 0; i < funcPtrTables_.length(); i++) {
|
||||
FuncPtrTable& funcPtrTable = funcPtrTables_[i];
|
||||
uint8_t** array = globalDataOffsetToFuncPtrTable(funcPtrTable.globalDataOffset());
|
||||
auto array = reinterpret_cast<uint8_t**>(globalData() + funcPtrTable.globalDataOffset());
|
||||
for (size_t j = 0; j < funcPtrTable.numElems(); j++) {
|
||||
void* callee = array[j];
|
||||
const CodeRange* codeRange = lookupCodeRange(callee);
|
||||
|
|
|
@ -114,7 +114,7 @@ class AsmJSModule
|
|||
Which which_;
|
||||
union {
|
||||
struct {
|
||||
uint32_t index_;
|
||||
uint32_t globalDataOffset_;
|
||||
VarInitKind initKind_;
|
||||
union {
|
||||
wasm::ValType importType_;
|
||||
|
@ -157,9 +157,9 @@ class AsmJSModule
|
|||
Which which() const {
|
||||
return pod.which_;
|
||||
}
|
||||
uint32_t varIndex() const {
|
||||
uint32_t varGlobalDataOffset() const {
|
||||
MOZ_ASSERT(pod.which_ == Variable);
|
||||
return pod.u.var.index_;
|
||||
return pod.u.var.globalDataOffset_;
|
||||
}
|
||||
VarInitKind varInitKind() const {
|
||||
MOZ_ASSERT(pod.which_ == Variable);
|
||||
|
@ -259,6 +259,17 @@ class AsmJSModule
|
|||
bool clone(ExclusiveContext* cx, Global* out) const;
|
||||
};
|
||||
|
||||
// An Exit holds bookkeeping information about an exit; the ExitDatum
|
||||
// struct overlays the actual runtime data stored in the global data
|
||||
// section.
|
||||
|
||||
struct ExitDatum
|
||||
{
|
||||
uint8_t* exit;
|
||||
jit::BaselineScript* baselineScript;
|
||||
HeapPtrFunction fun;
|
||||
};
|
||||
|
||||
class Exit
|
||||
{
|
||||
unsigned ffiIndex_;
|
||||
|
@ -266,8 +277,6 @@ class AsmJSModule
|
|||
unsigned interpCodeOffset_;
|
||||
unsigned jitCodeOffset_;
|
||||
|
||||
friend class AsmJSModule;
|
||||
|
||||
public:
|
||||
Exit() {}
|
||||
Exit(unsigned ffiIndex, unsigned globalDataOffset)
|
||||
|
@ -288,6 +297,29 @@ class AsmJSModule
|
|||
MOZ_ASSERT(!jitCodeOffset_);
|
||||
jitCodeOffset_ = off;
|
||||
}
|
||||
ExitDatum& datum(const AsmJSModule& module) const {
|
||||
return *reinterpret_cast<ExitDatum*>(module.globalData() + globalDataOffset_);
|
||||
}
|
||||
void initDatum(const AsmJSModule& module) const {
|
||||
MOZ_ASSERT(interpCodeOffset_);
|
||||
ExitDatum& d = datum(module);
|
||||
d.exit = module.codeBase() + interpCodeOffset_;
|
||||
d.baselineScript = nullptr;
|
||||
d.fun = nullptr;
|
||||
}
|
||||
bool isOptimized(const AsmJSModule& module) const {
|
||||
return datum(module).exit == module.codeBase() + jitCodeOffset_;
|
||||
}
|
||||
void optimize(const AsmJSModule& module, jit::BaselineScript* baselineScript) const {
|
||||
ExitDatum& d = datum(module);
|
||||
d.exit = module.codeBase() + jitCodeOffset_;
|
||||
d.baselineScript = baselineScript;
|
||||
}
|
||||
void deoptimize(const AsmJSModule& module) const {
|
||||
ExitDatum& d = datum(module);
|
||||
d.exit = module.codeBase() + interpCodeOffset_;
|
||||
d.baselineScript = nullptr;
|
||||
}
|
||||
|
||||
size_t serializedSize() const;
|
||||
uint8_t* serialize(uint8_t* cursor) const;
|
||||
|
@ -302,16 +334,6 @@ class AsmJSModule
|
|||
|
||||
typedef int32_t (*CodePtr)(EntryArg* args, uint8_t* global);
|
||||
|
||||
// An Exit holds bookkeeping information about an exit; the ExitDatum
|
||||
// struct overlays the actual runtime data stored in the global data
|
||||
// section.
|
||||
struct ExitDatum
|
||||
{
|
||||
uint8_t* exit;
|
||||
jit::BaselineScript* baselineScript;
|
||||
HeapPtrFunction fun;
|
||||
};
|
||||
|
||||
class ExportedFunction
|
||||
{
|
||||
PropertyName* name_;
|
||||
|
@ -679,15 +701,13 @@ class AsmJSModule
|
|||
|
||||
private:
|
||||
struct Pod {
|
||||
size_t funcPtrTableAndExitBytes_;
|
||||
size_t functionBytes_; // just the function bodies, no stubs
|
||||
size_t codeBytes_; // function bodies and stubs
|
||||
size_t totalBytes_; // function bodies, stubs, and global data
|
||||
uint32_t functionBytes_;
|
||||
uint32_t codeBytes_;
|
||||
uint32_t globalBytes_;
|
||||
uint32_t totalBytes_;
|
||||
uint32_t minHeapLength_;
|
||||
uint32_t maxHeapLength_;
|
||||
uint32_t heapLengthMask_;
|
||||
uint32_t numGlobalScalarVars_;
|
||||
uint32_t numGlobalSimdVars_;
|
||||
uint32_t numFFIs_;
|
||||
uint32_t srcLength_;
|
||||
uint32_t srcLengthWithRightBrace_;
|
||||
|
@ -744,11 +764,8 @@ class AsmJSModule
|
|||
void trace(JSTracer* trc);
|
||||
~AsmJSModule();
|
||||
|
||||
// An AsmJSModule transitions monotonically through these states:
|
||||
bool isFinishedWithModulePrologue() const { return pod.funcPtrTableAndExitBytes_ != SIZE_MAX; }
|
||||
bool isFinishedWithFunctionBodies() const { return pod.functionBytes_ != UINT32_MAX; }
|
||||
// An AsmJSModule transitions from !finished to finished to dynamically linked.
|
||||
bool isFinished() const { return !!code_; }
|
||||
bool isStaticallyLinked() const { return !!interruptExit_; }
|
||||
bool isDynamicallyLinked() const { return dynamicallyLinked_; }
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -812,17 +829,17 @@ class AsmJSModule
|
|||
// module prologue (before the function bodies):
|
||||
|
||||
void initGlobalArgumentName(PropertyName* n) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT_IF(n, n->isTenured());
|
||||
globalArgumentName_ = n;
|
||||
}
|
||||
void initImportArgumentName(PropertyName* n) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT_IF(n, n->isTenured());
|
||||
importArgumentName_ = n;
|
||||
}
|
||||
void initBufferArgumentName(PropertyName* n) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT_IF(n, n->isTenured());
|
||||
bufferArgumentName_ = n;
|
||||
}
|
||||
|
@ -835,36 +852,54 @@ class AsmJSModule
|
|||
PropertyName* bufferArgumentName() const {
|
||||
return bufferArgumentName_;
|
||||
}
|
||||
bool addGlobalVarInit(const wasm::Val& v, uint32_t* globalIndex) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
|
||||
/*************************************************************************/
|
||||
// These functions may only be called before finish():
|
||||
|
||||
private:
|
||||
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
uint32_t pad = ComputeByteAlignment(pod.globalBytes_, align);
|
||||
if (UINT32_MAX - pod.globalBytes_ < pad + bytes)
|
||||
return false;
|
||||
pod.globalBytes_ += pad;
|
||||
*globalDataOffset = pod.globalBytes_;
|
||||
pod.globalBytes_ += bytes;
|
||||
return true;
|
||||
}
|
||||
bool addGlobalVar(wasm::ValType type, uint32_t* globalDataOffset) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
unsigned width = 0;
|
||||
switch (type) {
|
||||
case wasm::ValType::I32: case wasm::ValType::F32: width = 4; break;
|
||||
case wasm::ValType::I64: case wasm::ValType::F64: width = 8; break;
|
||||
case wasm::ValType::I32x4: case wasm::ValType::F32x4: width = 16; break;
|
||||
}
|
||||
return allocateGlobalBytes(width, width, globalDataOffset);
|
||||
}
|
||||
public:
|
||||
bool addGlobalVarInit(const wasm::Val& v, uint32_t* globalDataOffset) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
if (!addGlobalVar(v.type(), globalDataOffset))
|
||||
return false;
|
||||
Global g(Global::Variable, nullptr);
|
||||
g.pod.u.var.initKind_ = Global::InitConstant;
|
||||
g.pod.u.var.u.val_ = v;
|
||||
if (v.isSimd()) {
|
||||
if (pod.numGlobalSimdVars_ == UINT32_MAX)
|
||||
return false;
|
||||
*globalIndex = pod.numGlobalSimdVars_++;
|
||||
} else {
|
||||
if (pod.numGlobalScalarVars_ == UINT32_MAX)
|
||||
return false;
|
||||
*globalIndex = pod.numGlobalScalarVars_++;
|
||||
}
|
||||
g.pod.u.var.index_ = *globalIndex;
|
||||
g.pod.u.var.globalDataOffset_ = *globalDataOffset;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addGlobalVarImport(PropertyName* name, wasm::ValType importType, uint32_t* globalIndex) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
bool addGlobalVarImport(PropertyName* name, wasm::ValType importType, uint32_t* globalDataOffset) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
if (!addGlobalVar(importType, globalDataOffset))
|
||||
return false;
|
||||
Global g(Global::Variable, name);
|
||||
g.pod.u.var.initKind_ = Global::InitImport;
|
||||
g.pod.u.var.u.importType_ = importType;
|
||||
*globalIndex = IsSimdType(importType)
|
||||
? pod.numGlobalSimdVars_++
|
||||
: pod.numGlobalScalarVars_++;
|
||||
g.pod.u.var.index_ = *globalIndex;
|
||||
g.pod.u.var.globalDataOffset_ = *globalDataOffset;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addFFI(PropertyName* field, uint32_t* ffiIndex) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
if (pod.numFFIs_ == UINT32_MAX)
|
||||
return false;
|
||||
Global g(Global::FFI, field);
|
||||
|
@ -872,7 +907,7 @@ class AsmJSModule
|
|||
return globals_.append(g);
|
||||
}
|
||||
bool addArrayView(Scalar::Type vt, PropertyName* maybeField, bool isSharedView) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(!pod.hasArrayView_ || (pod.isSharedView_ == isSharedView));
|
||||
pod.hasArrayView_ = true;
|
||||
pod.isSharedView_ = isSharedView;
|
||||
|
@ -881,7 +916,7 @@ class AsmJSModule
|
|||
return globals_.append(g);
|
||||
}
|
||||
bool addArrayViewCtor(Scalar::Type vt, PropertyName* field, bool isSharedView) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(field);
|
||||
MOZ_ASSERT(!pod.isSharedView_ || isSharedView);
|
||||
pod.isSharedView_ = isSharedView;
|
||||
|
@ -890,42 +925,44 @@ class AsmJSModule
|
|||
return globals_.append(g);
|
||||
}
|
||||
bool addByteLength() {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::ByteLength, nullptr);
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName* field) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::MathBuiltinFunction, field);
|
||||
g.pod.u.mathBuiltinFunc_ = func;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addMathBuiltinConstant(double value, PropertyName* field) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::Constant, field);
|
||||
g.pod.u.constant.value_ = value;
|
||||
g.pod.u.constant.kind_ = Global::MathConstant;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addAtomicsBuiltinFunction(AsmJSAtomicsBuiltinFunction func, PropertyName* field) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::AtomicsBuiltinFunction, field);
|
||||
g.pod.u.atomicsBuiltinFunc_ = func;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addSimdCtor(AsmJSSimdType type, PropertyName* field) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::SimdCtor, field);
|
||||
g.pod.u.simdCtorType_ = type;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addSimdOperation(AsmJSSimdType type, AsmJSSimdOperation op, PropertyName* field) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::SimdOperation, field);
|
||||
g.pod.u.simdOp.type_ = type;
|
||||
g.pod.u.simdOp.which_ = op;
|
||||
return globals_.append(g);
|
||||
}
|
||||
bool addGlobalConstant(double value, PropertyName* name) {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
Global g(Global::Constant, name);
|
||||
g.pod.u.constant.value_ = value;
|
||||
g.pod.u.constant.kind_ = Global::GlobalConstant;
|
||||
|
@ -952,19 +989,10 @@ class AsmJSModule
|
|||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void startFunctionBodies() {
|
||||
MOZ_ASSERT(!isFinishedWithModulePrologue());
|
||||
pod.funcPtrTableAndExitBytes_ = 0;
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
// These functions are called while parsing/compiling function bodies:
|
||||
|
||||
bool hasArrayView() const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return pod.hasArrayView_;
|
||||
}
|
||||
bool isSharedView() const {
|
||||
|
@ -972,7 +1000,7 @@ class AsmJSModule
|
|||
return pod.isSharedView_;
|
||||
}
|
||||
void addChangeHeap(uint32_t mask, uint32_t min, uint32_t max) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(!pod.hasFixedMinHeapLength_);
|
||||
MOZ_ASSERT(IsValidAsmJSHeapLength(mask + 1));
|
||||
MOZ_ASSERT(min >= RoundUpToNextValidAsmJSHeapLength(0));
|
||||
|
@ -984,7 +1012,7 @@ class AsmJSModule
|
|||
pod.hasFixedMinHeapLength_ = true;
|
||||
}
|
||||
bool tryRequireHeapLengthToBeAtLeast(uint32_t len) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
if (pod.hasFixedMinHeapLength_ && len > pod.minHeapLength_)
|
||||
return false;
|
||||
if (len > pod.maxHeapLength_)
|
||||
|
@ -1013,69 +1041,43 @@ class AsmJSModule
|
|||
codeRanges_.append(CodeRange(builtin, offsets));
|
||||
}
|
||||
bool addExit(unsigned ffiIndex, unsigned* exitIndex) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum))
|
||||
MOZ_ASSERT(!isFinished());
|
||||
static_assert(sizeof(ExitDatum) % sizeof(void*) == 0, "word aligned");
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(sizeof(ExitDatum), sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
uint32_t globalDataOffset = globalDataBytes();
|
||||
JS_STATIC_ASSERT(sizeof(ExitDatum) % sizeof(void*) == 0);
|
||||
pod.funcPtrTableAndExitBytes_ += sizeof(ExitDatum);
|
||||
*exitIndex = unsigned(exits_.length());
|
||||
return exits_.append(Exit(ffiIndex, globalDataOffset));
|
||||
}
|
||||
unsigned numExits() const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return exits_.length();
|
||||
}
|
||||
Exit& exit(unsigned i) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return exits_[i];
|
||||
}
|
||||
const Exit& exit(unsigned i) const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return exits_[i];
|
||||
}
|
||||
bool addFuncPtrTable(unsigned numElems, uint32_t* globalDataOffset) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinished());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(IsPowerOfTwo(numElems));
|
||||
if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < numElems * sizeof(void*))
|
||||
if (!allocateGlobalBytes(numElems * sizeof(void*), sizeof(void*), globalDataOffset))
|
||||
return false;
|
||||
*globalDataOffset = globalDataBytes();
|
||||
if (!funcPtrTables_.append(FuncPtrTable(*globalDataOffset, numElems)))
|
||||
return false;
|
||||
pod.funcPtrTableAndExitBytes_ += numElems * sizeof(void*);
|
||||
return true;
|
||||
return funcPtrTables_.append(FuncPtrTable(*globalDataOffset, numElems));
|
||||
}
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
bool addProfiledFunction(ProfiledFunction&& func)
|
||||
{
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
return profiledFunctions_.append(mozilla::Move(func));
|
||||
bool addProfiledFunction(ProfiledFunction func) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
return profiledFunctions_.append(func);
|
||||
}
|
||||
unsigned numProfiledFunctions() const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return profiledFunctions_.length();
|
||||
}
|
||||
ProfiledFunction& profiledFunction(unsigned i) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return profiledFunctions_[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// This function is called after compiling the function bodies (before
|
||||
// compiling entries/exits) to record the extent of compiled function code.
|
||||
void finishFunctionBodies(size_t functionBytes) {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
|
||||
pod.functionBytes_ = functionBytes;
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies());
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
// Exported functions are added after finishFunctionBodies() and before
|
||||
// finish(). The list of exported functions can be accessed any time after
|
||||
// the exported functions have been added.
|
||||
|
||||
bool addExportedFunction(PropertyName* name,
|
||||
uint32_t funcSrcBegin,
|
||||
uint32_t funcSrcEnd,
|
||||
|
@ -1085,7 +1087,7 @@ class AsmJSModule
|
|||
// NB: funcSrcBegin/funcSrcEnd are given relative to the ScriptSource
|
||||
// (the entire file) and ExportedFunctions store offsets relative to
|
||||
// the beginning of the module (so that they are caching-invariant).
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(srcStart_ < funcSrcBegin);
|
||||
MOZ_ASSERT(funcSrcBegin < funcSrcEnd);
|
||||
ExportedFunction func(name, funcSrcBegin - srcStart_, funcSrcEnd - srcStart_,
|
||||
|
@ -1098,7 +1100,7 @@ class AsmJSModule
|
|||
PropertyName* maybeFieldName)
|
||||
{
|
||||
// See addExportedFunction.
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(srcStart_ < funcSrcBegin);
|
||||
MOZ_ASSERT(funcSrcBegin < funcSrcEnd);
|
||||
ExportedFunction func(name, funcSrcBegin - srcStart_, funcSrcEnd - srcStart_,
|
||||
|
@ -1106,15 +1108,12 @@ class AsmJSModule
|
|||
return exports_.length() < UINT32_MAX && exports_.append(mozilla::Move(func));
|
||||
}
|
||||
unsigned numExportedFunctions() const {
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies());
|
||||
return exports_.length();
|
||||
}
|
||||
const ExportedFunction& exportedFunction(unsigned i) const {
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies());
|
||||
return exports_[i];
|
||||
}
|
||||
ExportedFunction& exportedFunction(unsigned i) {
|
||||
MOZ_ASSERT(isFinishedWithFunctionBodies());
|
||||
return exports_[i];
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1132,44 @@ class AsmJSModule
|
|||
/*************************************************************************/
|
||||
// These accessor functions can be used after finish():
|
||||
|
||||
uint8_t* codeBase() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
|
||||
return code_;
|
||||
}
|
||||
uint32_t codeBytes() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.codeBytes_;
|
||||
}
|
||||
bool containsCodePC(void* pc) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pc >= code_ && pc < (code_ + codeBytes());
|
||||
}
|
||||
|
||||
// The range [0, functionBytes) is a subrange of [0, codeBytes) that
|
||||
// contains only function body code, not the stub code. This distinction is
|
||||
// used by the async interrupt handler to only interrupt when the pc is in
|
||||
// function code which, in turn, simplifies reasoning about how stubs
|
||||
// enter/exit.
|
||||
void setFunctionBytes(uint32_t functionBytes) {
|
||||
MOZ_ASSERT(!isFinished());
|
||||
MOZ_ASSERT(!pod.functionBytes_);
|
||||
pod.functionBytes_ = functionBytes;
|
||||
}
|
||||
uint32_t functionBytes() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.functionBytes_;
|
||||
}
|
||||
bool containsFunctionPC(void* pc) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pc >= code_ && pc < (code_ + functionBytes());
|
||||
}
|
||||
|
||||
uint32_t globalBytes() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.globalBytes_;
|
||||
}
|
||||
|
||||
unsigned numFFIs() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.numFFIs_;
|
||||
|
@ -1145,39 +1182,6 @@ class AsmJSModule
|
|||
MOZ_ASSERT(isFinished());
|
||||
return srcStart_ + pod.srcLengthWithRightBrace_;
|
||||
}
|
||||
uint8_t* codeBase() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
|
||||
return code_;
|
||||
}
|
||||
size_t functionBytes() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.functionBytes_;
|
||||
}
|
||||
size_t codeBytes() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.codeBytes_;
|
||||
}
|
||||
bool containsFunctionPC(void* pc) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pc >= code_ && pc < (code_ + functionBytes());
|
||||
}
|
||||
bool containsCodePC(void* pc) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pc >= code_ && pc < (code_ + codeBytes());
|
||||
}
|
||||
private:
|
||||
uint8_t* interpExitTrampoline(const Exit& exit) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(exit.interpCodeOffset_);
|
||||
return code_ + exit.interpCodeOffset_;
|
||||
}
|
||||
uint8_t* jitExitTrampoline(const Exit& exit) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(exit.jitCodeOffset_);
|
||||
return code_ + exit.jitCodeOffset_;
|
||||
}
|
||||
public:
|
||||
|
||||
// Lookup a callsite by the return pc (from the callee to the caller).
|
||||
// Return null if no callsite was found.
|
||||
|
@ -1193,145 +1197,51 @@ class AsmJSModule
|
|||
|
||||
// The global data section is placed after the executable code (i.e., at
|
||||
// offset codeBytes_) in the module's linear allocation. The global data
|
||||
// are laid out in this order:
|
||||
// 0. a pointer to the current AsmJSActivation
|
||||
// 1. a pointer to the heap that was linked to the module
|
||||
// 2. the double float constant NaN
|
||||
// 3. the float32 constant NaN, padded to Simd128DataSize
|
||||
// 4. global SIMD variable state (elements are Simd128DataSize)
|
||||
// 5. global variable state (elements are sizeof(uint64_t))
|
||||
// 6. interleaved function-pointer tables and exits. These are allocated
|
||||
// while type checking function bodies (as exits and uses of
|
||||
// function-pointer tables are encountered).
|
||||
size_t offsetOfGlobalData() const {
|
||||
// starts with some fixed allocations followed by interleaved global,
|
||||
// function-pointer table and exit allocations.
|
||||
uint32_t offsetOfGlobalData() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return pod.codeBytes_;
|
||||
}
|
||||
uint8_t* globalData() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return code_ + offsetOfGlobalData();
|
||||
return codeBase() + offsetOfGlobalData();
|
||||
}
|
||||
size_t globalSimdVarsOffset() const {
|
||||
return AlignBytes(/* 0 */ sizeof(void*) +
|
||||
/* 1 */ sizeof(void*) +
|
||||
/* 2 */ sizeof(double) +
|
||||
/* 3 */ sizeof(float),
|
||||
jit::Simd128DataSize);
|
||||
}
|
||||
size_t globalDataBytes() const {
|
||||
return globalSimdVarsOffset() +
|
||||
/* 4 */ pod.numGlobalSimdVars_ * jit::Simd128DataSize +
|
||||
/* 5 */ pod.numGlobalScalarVars_ * sizeof(uint64_t) +
|
||||
/* 6 */ pod.funcPtrTableAndExitBytes_;
|
||||
}
|
||||
static unsigned activationGlobalDataOffset() {
|
||||
JS_STATIC_ASSERT(jit::AsmJSActivationGlobalDataOffset == 0);
|
||||
return 0;
|
||||
static void assertGlobalDataOffsets() {
|
||||
static_assert(jit::AsmJSActivationGlobalDataOffset == 0,
|
||||
"global data goes first");
|
||||
static_assert(jit::AsmJSHeapGlobalDataOffset == jit::AsmJSActivationGlobalDataOffset + sizeof(void*),
|
||||
"then an AsmJSActivation*");
|
||||
static_assert(jit::AsmJSNaN64GlobalDataOffset == jit::AsmJSHeapGlobalDataOffset + sizeof(uint8_t*),
|
||||
"then a pointer to the heap");
|
||||
static_assert(jit::AsmJSNaN32GlobalDataOffset == jit::AsmJSNaN64GlobalDataOffset + sizeof(double),
|
||||
"then a 32-bit NaN");
|
||||
static_assert(sInitialGlobalDataBytes == jit::AsmJSNaN32GlobalDataOffset + sizeof(float),
|
||||
"then a 64-bit NaN");
|
||||
}
|
||||
static const uint32_t sInitialGlobalDataBytes = jit::AsmJSNaN32GlobalDataOffset + sizeof(float);
|
||||
|
||||
AsmJSActivation*& activation() const {
|
||||
return *(AsmJSActivation**)(globalData() + activationGlobalDataOffset());
|
||||
MOZ_ASSERT(isFinished());
|
||||
return *(AsmJSActivation**)(globalData() + jit::AsmJSActivationGlobalDataOffset);
|
||||
}
|
||||
bool active() const {
|
||||
return activation() != nullptr;
|
||||
}
|
||||
static unsigned heapGlobalDataOffset() {
|
||||
JS_STATIC_ASSERT(jit::AsmJSHeapGlobalDataOffset == sizeof(void*));
|
||||
return sizeof(void*);
|
||||
}
|
||||
private:
|
||||
// The pointer may reference shared memory, use with care.
|
||||
// Generally you want to use maybeHeap(), not heapDatum().
|
||||
uint8_t*& heapDatum() const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return *(uint8_t**)(globalData() + heapGlobalDataOffset());
|
||||
return *(uint8_t**)(globalData() + jit::AsmJSHeapGlobalDataOffset);
|
||||
}
|
||||
public:
|
||||
static unsigned nan64GlobalDataOffset() {
|
||||
static_assert(jit::AsmJSNaN64GlobalDataOffset % sizeof(double) == 0,
|
||||
"Global data NaN should be aligned");
|
||||
return heapGlobalDataOffset() + sizeof(void*);
|
||||
}
|
||||
static unsigned nan32GlobalDataOffset() {
|
||||
static_assert(jit::AsmJSNaN32GlobalDataOffset % sizeof(double) == 0,
|
||||
"Global data NaN should be aligned");
|
||||
return nan64GlobalDataOffset() + sizeof(double);
|
||||
}
|
||||
void initGlobalNaN() {
|
||||
MOZ_ASSERT(jit::AsmJSNaN64GlobalDataOffset == nan64GlobalDataOffset());
|
||||
MOZ_ASSERT(jit::AsmJSNaN32GlobalDataOffset == nan32GlobalDataOffset());
|
||||
*(double*)(globalData() + nan64GlobalDataOffset()) = GenericNaN();
|
||||
*(float*)(globalData() + nan32GlobalDataOffset()) = GenericNaN();
|
||||
}
|
||||
unsigned globalSimdVarIndexToGlobalDataOffset(unsigned i) const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(i < pod.numGlobalSimdVars_);
|
||||
return globalSimdVarsOffset() +
|
||||
i * jit::Simd128DataSize;
|
||||
}
|
||||
unsigned globalScalarVarIndexToGlobalDataOffset(unsigned i) const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
MOZ_ASSERT(i < pod.numGlobalScalarVars_);
|
||||
return globalSimdVarsOffset() +
|
||||
pod.numGlobalSimdVars_ * jit::Simd128DataSize +
|
||||
i * sizeof(uint64_t);
|
||||
}
|
||||
void* globalScalarVarIndexToGlobalDatum(unsigned i) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return (void*)(globalData() + globalScalarVarIndexToGlobalDataOffset(i));
|
||||
}
|
||||
void* globalSimdVarIndexToGlobalDatum(unsigned i) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return (void*)(globalData() + globalSimdVarIndexToGlobalDataOffset(i));
|
||||
}
|
||||
void* globalVarToGlobalDatum(const Global& g) const {
|
||||
unsigned index = g.varIndex();
|
||||
if (g.varInitKind() == Global::VarInitKind::InitConstant) {
|
||||
return g.varInitVal().isSimd()
|
||||
? globalSimdVarIndexToGlobalDatum(index)
|
||||
: globalScalarVarIndexToGlobalDatum(index);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(g.varInitKind() == Global::VarInitKind::InitImport);
|
||||
return IsSimdType(g.varInitImportType())
|
||||
? globalSimdVarIndexToGlobalDatum(index)
|
||||
: globalScalarVarIndexToGlobalDatum(index);
|
||||
}
|
||||
uint8_t** globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(globalDataOffset < globalDataBytes());
|
||||
return (uint8_t**)(globalData() + globalDataOffset);
|
||||
}
|
||||
unsigned exitIndexToGlobalDataOffset(unsigned exitIndex) const {
|
||||
MOZ_ASSERT(isFinishedWithModulePrologue());
|
||||
return exits_[exitIndex].globalDataOffset();
|
||||
}
|
||||
ExitDatum& exitIndexToGlobalDatum(unsigned exitIndex) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
return *(ExitDatum*)(globalData() + exitIndexToGlobalDataOffset(exitIndex));
|
||||
}
|
||||
bool exitIsOptimized(unsigned exitIndex) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
ExitDatum& exitDatum = exitIndexToGlobalDatum(exitIndex);
|
||||
return exitDatum.exit != interpExitTrampoline(exit(exitIndex));
|
||||
}
|
||||
void optimizeExit(unsigned exitIndex, jit::BaselineScript* baselineScript) const {
|
||||
MOZ_ASSERT(!exitIsOptimized(exitIndex));
|
||||
ExitDatum& exitDatum = exitIndexToGlobalDatum(exitIndex);
|
||||
exitDatum.exit = jitExitTrampoline(exit(exitIndex));
|
||||
exitDatum.baselineScript = baselineScript;
|
||||
}
|
||||
void detachJitCompilation(size_t exitIndex) const {
|
||||
MOZ_ASSERT(isFinished());
|
||||
ExitDatum& exitDatum = exitIndexToGlobalDatum(exitIndex);
|
||||
exitDatum.exit = interpExitTrampoline(exit(exitIndex));
|
||||
exitDatum.baselineScript = nullptr;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
// These functions are called after finish() but before staticallyLink():
|
||||
|
||||
bool addRelativeLink(RelativeLink link) {
|
||||
MOZ_ASSERT(isFinished() && !isStaticallyLinked());
|
||||
MOZ_ASSERT(isFinished());
|
||||
return staticLinkData_.relativeLinks.append(link);
|
||||
}
|
||||
|
||||
|
@ -1349,7 +1259,7 @@ class AsmJSModule
|
|||
|
||||
/*************************************************************************/
|
||||
|
||||
// After a module isFinished compiling or deserializing, it is "statically
|
||||
// After a module is finished compiling or deserializing, it is "statically
|
||||
// linked" which specializes the code to its current address (this allows
|
||||
// code to be relocated between serialization and deserialization).
|
||||
void staticallyLink(ExclusiveContext* cx);
|
||||
|
@ -1362,6 +1272,7 @@ class AsmJSModule
|
|||
// is kept in a list so that it can be updated if the linked buffer is
|
||||
// detached.
|
||||
void setIsDynamicallyLinked(JSRuntime* rt) {
|
||||
MOZ_ASSERT(isFinished());
|
||||
MOZ_ASSERT(!isDynamicallyLinked());
|
||||
dynamicallyLinked_ = true;
|
||||
nextLinked_ = rt->linkedAsmJSModules;
|
||||
|
|
|
@ -1022,7 +1022,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
union {
|
||||
struct {
|
||||
Type::Which type_;
|
||||
uint32_t index_;
|
||||
uint32_t globalDataOffset_;
|
||||
NumLit literalValue_;
|
||||
} varOrConst;
|
||||
uint32_t funcIndex_;
|
||||
|
@ -1058,9 +1058,9 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
MOZ_ASSERT(which_ == Variable || which_ == ConstantLiteral || which_ == ConstantImport);
|
||||
return u.varOrConst.type_;
|
||||
}
|
||||
uint32_t varOrConstIndex() const {
|
||||
uint32_t varOrConstGlobalDataOffset() const {
|
||||
MOZ_ASSERT(which_ == Variable || which_ == ConstantImport);
|
||||
return u.varOrConst.index_;
|
||||
return u.varOrConst.globalDataOffset_;
|
||||
}
|
||||
bool isConst() const {
|
||||
return which_ == ConstantLiteral || which_ == ConstantImport;
|
||||
|
@ -1258,8 +1258,6 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
NonAssertingLabel asyncInterruptLabel_;
|
||||
NonAssertingLabel onDetachedLabel_;
|
||||
|
||||
DebugOnly<bool> finishedFunctionBodies_;
|
||||
|
||||
public:
|
||||
ModuleValidator(ExclusiveContext* cx, AsmJSParser& parser)
|
||||
: cx_(cx),
|
||||
|
@ -1285,8 +1283,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
masm_(MacroAssembler::AsmJSToken()),
|
||||
usecBefore_(PRMJ_Now()),
|
||||
functionEntryOffsets_(cx),
|
||||
slowFunctions_(cx),
|
||||
finishedFunctionBodies_(false)
|
||||
slowFunctions_(cx)
|
||||
{
|
||||
MOZ_ASSERT(moduleFunctionNode_->pn_funbox == parser.pc->sc->asFunctionBox());
|
||||
}
|
||||
|
@ -1416,14 +1413,14 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
// The type of a const is the exact type of the literal (since its value
|
||||
// cannot change) which is more precise than the corresponding vartype.
|
||||
Type type = isConst ? Type::lit(lit) : Type::var(lit.type());
|
||||
uint32_t globalIndex;
|
||||
if (!module_->addGlobalVarInit(lit.value(), &globalIndex))
|
||||
uint32_t globalDataOffset;
|
||||
if (!module_->addGlobalVarInit(lit.value(), &globalDataOffset))
|
||||
return false;
|
||||
Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
|
||||
Global* global = moduleLifo_.new_<Global>(which);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.varOrConst.index_ = globalIndex;
|
||||
global->u.varOrConst.globalDataOffset_ = globalDataOffset;
|
||||
global->u.varOrConst.type_ = type.which();
|
||||
if (isConst)
|
||||
global->u.varOrConst.literalValue_ = lit;
|
||||
|
@ -1432,14 +1429,14 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
bool addGlobalVarImport(PropertyName* varName, PropertyName* fieldName, ValType importType,
|
||||
bool isConst)
|
||||
{
|
||||
uint32_t globalIndex;
|
||||
if (!module_->addGlobalVarImport(fieldName, importType, &globalIndex))
|
||||
uint32_t globalDataOffset;
|
||||
if (!module_->addGlobalVarImport(fieldName, importType, &globalDataOffset))
|
||||
return false;
|
||||
Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
|
||||
Global* global = moduleLifo_.new_<Global>(which);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.varOrConst.index_ = globalIndex;
|
||||
global->u.varOrConst.globalDataOffset_ = globalDataOffset;
|
||||
global->u.varOrConst.type_ = Type::var(importType).which();
|
||||
return globals_.putNew(varName, global);
|
||||
}
|
||||
|
@ -1830,34 +1827,38 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
}
|
||||
|
||||
bool finishGeneratingEntry(unsigned exportIndex, AsmJSOffsets offsets) {
|
||||
MOZ_ASSERT(finishedFunctionBodies_);
|
||||
module_->exportedFunction(exportIndex).initCodeOffset(offsets.begin);
|
||||
return module_->addCodeRange(AsmJSModule::CodeRange::Entry, offsets);
|
||||
}
|
||||
bool finishGeneratingInlineStub(AsmJSOffsets offsets) {
|
||||
MOZ_ASSERT(finishedFunctionBodies_);
|
||||
return module_->addCodeRange(AsmJSModule::CodeRange::Inline, offsets);
|
||||
}
|
||||
bool finishGeneratingInterpExit(unsigned exitIndex, AsmJSProfilingOffsets offsets) {
|
||||
MOZ_ASSERT(finishedFunctionBodies_);
|
||||
module_->exit(exitIndex).initInterpOffset(offsets.begin);
|
||||
return module_->addCodeRange(AsmJSModule::CodeRange::SlowFFI, offsets);
|
||||
}
|
||||
bool finishGeneratingJitExit(unsigned exitIndex, AsmJSProfilingOffsets offsets) {
|
||||
MOZ_ASSERT(finishedFunctionBodies_);
|
||||
module_->exit(exitIndex).initJitOffset(offsets.begin);
|
||||
return module_->addCodeRange(AsmJSModule::CodeRange::JitFFI, offsets);
|
||||
}
|
||||
bool finishGeneratingInterrupt(AsmJSProfilingOffsets offsets) {
|
||||
MOZ_ASSERT(finishedFunctionBodies_);
|
||||
return module_->addCodeRange(AsmJSModule::CodeRange::Interrupt, offsets);
|
||||
}
|
||||
bool finishGeneratingBuiltinThunk(AsmJSExit::BuiltinKind builtin, AsmJSProfilingOffsets offsets) {
|
||||
MOZ_ASSERT(finishedFunctionBodies_);
|
||||
return module_->addBuiltinThunkCodeRange(builtin, offsets);
|
||||
}
|
||||
|
||||
bool finish(ScopedJSDeletePtr<AsmJSModule>* module) {
|
||||
// Patch internal calls to their final positions
|
||||
for (auto& cs : masm().callSites()) {
|
||||
if (!cs.isInternal())
|
||||
continue;
|
||||
MOZ_ASSERT(cs.kind() == CallSiteDesc::Relative);
|
||||
uint32_t callerOffset = cs.returnAddressOffset();
|
||||
uint32_t calleeOffset = functionEntryOffset(cs.targetIndex());
|
||||
masm().patchCall(callerOffset, calleeOffset);
|
||||
}
|
||||
|
||||
masm().finish();
|
||||
if (masm().oom())
|
||||
return false;
|
||||
|
@ -1892,22 +1893,9 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
}
|
||||
module_->setViewsAreShared();
|
||||
}
|
||||
module_->startFunctionBodies();
|
||||
}
|
||||
bool finishFunctionBodies() {
|
||||
// Patch internal calls to their final positions
|
||||
for (auto& cs : masm().callSites()) {
|
||||
if (!cs.isInternal())
|
||||
continue;
|
||||
MOZ_ASSERT(cs.kind() == CallSiteDesc::Relative);
|
||||
uint32_t callerOffset = cs.returnAddressOffset();
|
||||
uint32_t calleeOffset = functionEntryOffset(cs.targetIndex());
|
||||
masm().patchCall(callerOffset, calleeOffset);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!finishedFunctionBodies_);
|
||||
module_->finishFunctionBodies(masm().currentOffset());
|
||||
finishedFunctionBodies_ = true;
|
||||
module_->setFunctionBytes(masm().currentOffset());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3245,12 +3233,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
|
|||
default: MOZ_CRASH("unexpected global type");
|
||||
}
|
||||
|
||||
uint32_t globalIndex = global->varOrConstIndex();
|
||||
// Write the global data offset
|
||||
if (global->varOrConstType().isSimd())
|
||||
f.writeU32(f.module().globalSimdVarIndexToGlobalDataOffset(globalIndex));
|
||||
else
|
||||
f.writeU32(f.module().globalScalarVarIndexToGlobalDataOffset(globalIndex));
|
||||
f.writeU32(global->varOrConstGlobalDataOffset());
|
||||
f.writeU8(uint8_t(global->isConst()));
|
||||
*type = global->varOrConstType();
|
||||
break;
|
||||
|
@ -3636,12 +3619,7 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
|
|||
default: MOZ_CRASH("unexpected global type");
|
||||
}
|
||||
|
||||
unsigned globalIndex = global->varOrConstIndex();
|
||||
// Global data offset
|
||||
if (global->varOrConstType().isSimd())
|
||||
f.patch32(indexAt, f.module().globalSimdVarIndexToGlobalDataOffset(globalIndex));
|
||||
else
|
||||
f.patch32(indexAt, f.module().globalScalarVarIndexToGlobalDataOffset(globalIndex));
|
||||
f.patch32(indexAt, global->varOrConstGlobalDataOffset());
|
||||
*type = rhsType;
|
||||
return true;
|
||||
}
|
||||
|
@ -4365,7 +4343,7 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, ExprT
|
|||
return false;
|
||||
|
||||
JS_STATIC_ASSERT(offsetof(AsmJSModule::ExitDatum, exit) == 0);
|
||||
f.patch32(offsetAt, f.module().exitIndexToGlobalDataOffset(exitIndex));
|
||||
f.patch32(offsetAt, f.module().exit(exitIndex).globalDataOffset());
|
||||
f.patchSig(sigAt, lifoSig);
|
||||
*type = Type::ret(ret);
|
||||
return true;
|
||||
|
@ -7725,7 +7703,7 @@ GenerateFFIIonExit(ModuleValidator& m, const LifoSig& sig, unsigned exitIndex, L
|
|||
Register scratch = ABIArgGenerator::NonArgReturnReg1; // repeatedly clobbered
|
||||
|
||||
// 2.1. Get ExitDatum
|
||||
unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
|
||||
unsigned globalDataOffset = m.module().exit(exitIndex).globalDataOffset();
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
m.masm().append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
|
||||
#elif defined(JS_CODEGEN_X86)
|
||||
|
|
|
@ -497,7 +497,7 @@ BaselineScript::clearDependentAsmJSModules()
|
|||
if (dependentAsmJSModules_) {
|
||||
for (size_t i = 0; i < dependentAsmJSModules_->length(); i++) {
|
||||
DependentAsmJSModuleExit exit = (*dependentAsmJSModules_)[i];
|
||||
exit.module->detachJitCompilation(exit.exitIndex);
|
||||
exit.module->exit(exit.exitIndex).deoptimize(*exit.module);
|
||||
}
|
||||
|
||||
dependentAsmJSModules_->clear();
|
||||
|
@ -509,12 +509,8 @@ BaselineScript::unlinkDependentAsmJSModules(FreeOp* fop)
|
|||
{
|
||||
// Remove any links from AsmJSModules that contain optimized FFI calls into
|
||||
// this BaselineScript.
|
||||
clearDependentAsmJSModules();
|
||||
if (dependentAsmJSModules_) {
|
||||
for (size_t i = 0; i < dependentAsmJSModules_->length(); i++) {
|
||||
DependentAsmJSModuleExit exit = (*dependentAsmJSModules_)[i];
|
||||
exit.module->detachJitCompilation(exit.exitIndex);
|
||||
}
|
||||
|
||||
fop->delete_(dependentAsmJSModules_);
|
||||
dependentAsmJSModules_ = nullptr;
|
||||
}
|
||||
|
|
|
@ -336,19 +336,4 @@ js::jit::writePerfSpewerAsmJSFunctionMap(uintptr_t base, uintptr_t size,
|
|||
unlockPerfMap();
|
||||
}
|
||||
|
||||
void
|
||||
js::jit::writePerfSpewerAsmJSEntriesAndExits(uintptr_t base, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
if (!lockPerfMap())
|
||||
return;
|
||||
|
||||
fprintf(PerfFilePtr, "%" PRIxPTR " %" PRIxSIZE " AsmJS Entries and Exits (0x%" PRIxPTR " 0x%" PRIxSIZE ")\n",
|
||||
base, size, base, size);
|
||||
|
||||
unlockPerfMap();
|
||||
}
|
||||
|
||||
#endif // defined (JS_ION_PERF)
|
||||
|
|
|
@ -87,8 +87,6 @@ class AsmJSPerfSpewer : public PerfSpewer
|
|||
void writePerfSpewerAsmJSFunctionMap(uintptr_t base, uintptr_t size, const char* filename,
|
||||
unsigned lineno, unsigned colIndex, const char* funcName);
|
||||
|
||||
void writePerfSpewerAsmJSEntriesAndExits(uintptr_t base, size_t size);
|
||||
|
||||
#endif // JS_ION_PERF
|
||||
|
||||
} // namespace jit
|
||||
|
|
Загрузка…
Ссылка в новой задаче