зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1239177 - Odin: make calls more like wasm (r=bbouvier)
--HG-- extra : commitid : 55SogGEwGDh extra : rebase_source : b37071da6504fe8418d9c1fcd8f34a17d0d453d7
This commit is contained in:
Родитель
dcfa1c7611
Коммит
0a5366fd58
|
@ -397,7 +397,7 @@ class js::AsmJSModule final : public Module
|
|||
AsmJSModule(UniqueModuleData base,
|
||||
UniqueStaticLinkData link,
|
||||
UniqueAsmJSModuleData module)
|
||||
: Module(Move(base), Module::IsAsmJS),
|
||||
: Module(Move(base), AsmJSBool::IsAsmJS),
|
||||
link_(Move(link)),
|
||||
module_(Move(module))
|
||||
{}
|
||||
|
@ -1354,7 +1354,6 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
public:
|
||||
class Func
|
||||
{
|
||||
const LifoSig& sig_;
|
||||
PropertyName* name_;
|
||||
uint32_t firstUse_;
|
||||
uint32_t index_;
|
||||
|
@ -1363,8 +1362,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
bool defined_;
|
||||
|
||||
public:
|
||||
Func(PropertyName* name, uint32_t firstUse, const LifoSig& sig, uint32_t index)
|
||||
: sig_(sig), name_(name), firstUse_(firstUse), index_(index),
|
||||
Func(PropertyName* name, uint32_t firstUse, uint32_t index)
|
||||
: name_(name), firstUse_(firstUse), index_(index),
|
||||
srcBegin_(0), srcEnd_(0), defined_(false)
|
||||
{}
|
||||
|
||||
|
@ -1382,7 +1381,6 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
|
||||
uint32_t srcBegin() const { MOZ_ASSERT(defined_); return srcBegin_; }
|
||||
uint32_t srcEnd() const { MOZ_ASSERT(defined_); return srcEnd_; }
|
||||
const LifoSig& sig() const { return sig_; }
|
||||
};
|
||||
|
||||
typedef Vector<const Func*> ConstFuncVector;
|
||||
|
@ -1390,7 +1388,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
|
||||
class FuncPtrTable
|
||||
{
|
||||
const LifoSig& sig_;
|
||||
uint32_t sigIndex_;
|
||||
PropertyName* name_;
|
||||
uint32_t firstUse_;
|
||||
uint32_t mask_;
|
||||
|
@ -1399,12 +1397,11 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
FuncPtrTable(FuncPtrTable&& rhs) = delete;
|
||||
|
||||
public:
|
||||
FuncPtrTable(ExclusiveContext* cx, PropertyName* name, uint32_t firstUse,
|
||||
const LifoSig& sig, uint32_t mask)
|
||||
: sig_(sig), name_(name), firstUse_(firstUse), mask_(mask), defined_(false)
|
||||
FuncPtrTable(uint32_t sigIndex, PropertyName* name, uint32_t firstUse, uint32_t mask)
|
||||
: sigIndex_(sigIndex), name_(name), firstUse_(firstUse), mask_(mask), defined_(false)
|
||||
{}
|
||||
|
||||
const LifoSig& sig() const { return sig_; }
|
||||
uint32_t sigIndex() const { return sigIndex_; }
|
||||
PropertyName* name() const { return name_; }
|
||||
uint32_t firstUse() const { return firstUse_; }
|
||||
unsigned mask() const { return mask_; }
|
||||
|
@ -1561,43 +1558,49 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
Scalar::Type type;
|
||||
};
|
||||
|
||||
class ImportDescriptor
|
||||
private:
|
||||
struct SigHashPolicy
|
||||
{
|
||||
typedef const Sig& Lookup;
|
||||
static HashNumber hash(Lookup sig) { return sig.hash(); }
|
||||
static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; }
|
||||
};
|
||||
typedef HashMap<const DeclaredSig*, uint32_t, SigHashPolicy> SigMap;
|
||||
class NamedSig
|
||||
{
|
||||
PropertyName* name_;
|
||||
const LifoSig* sig_;
|
||||
const DeclaredSig* sig_;
|
||||
|
||||
public:
|
||||
ImportDescriptor(PropertyName* name, const LifoSig& sig)
|
||||
NamedSig(PropertyName* name, const DeclaredSig& sig)
|
||||
: name_(name), sig_(&sig)
|
||||
{}
|
||||
|
||||
PropertyName* name() const {
|
||||
return name_;
|
||||
}
|
||||
const LifoSig& sig() const {
|
||||
const Sig& sig() const {
|
||||
return *sig_;
|
||||
}
|
||||
|
||||
struct Lookup { // implements HashPolicy
|
||||
PropertyName* name_;
|
||||
const MallocSig& sig_;
|
||||
Lookup(PropertyName* name, const MallocSig& sig) : name_(name), sig_(sig) {}
|
||||
// Implement HashPolicy:
|
||||
struct Lookup {
|
||||
PropertyName* name;
|
||||
const Sig& sig;
|
||||
Lookup(PropertyName* name, const Sig& sig) : name(name), sig(sig) {}
|
||||
};
|
||||
static HashNumber hash(const Lookup& l) {
|
||||
return HashGeneric(l.name_, l.sig_.hash());
|
||||
static HashNumber hash(Lookup l) {
|
||||
return HashGeneric(l.name, l.sig.hash());
|
||||
}
|
||||
static bool match(const ImportDescriptor& lhs, const Lookup& rhs) {
|
||||
return lhs.name_ == rhs.name_ && *lhs.sig_ == rhs.sig_;
|
||||
static bool match(NamedSig lhs, Lookup rhs) {
|
||||
return lhs.name_ == rhs.name && *lhs.sig_ == rhs.sig;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
typedef HashMap<NamedSig, uint32_t, NamedSig> ImportMap;
|
||||
typedef HashMap<PropertyName*, Global*> GlobalMap;
|
||||
typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
|
||||
typedef HashMap<PropertyName*, AsmJSAtomicsBuiltinFunction> AtomicsNameMap;
|
||||
typedef HashMap<PropertyName*, AsmJSSimdOperation> SimdOperationNameMap;
|
||||
typedef Vector<ArrayView> ArrayViewVector;
|
||||
typedef HashMap<ImportDescriptor, unsigned, ImportDescriptor> ImportMap;
|
||||
|
||||
ExclusiveContext* cx_;
|
||||
AsmJSParser& parser_;
|
||||
|
@ -1612,6 +1615,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
FuncVector functions_;
|
||||
FuncPtrTableVector funcPtrTables_;
|
||||
GlobalMap globalMap_;
|
||||
SigMap sigMap_;
|
||||
ImportMap importMap_;
|
||||
ArrayViewVector arrayViews_;
|
||||
bool atomicsPresent_;
|
||||
|
@ -1652,6 +1656,26 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
return false;
|
||||
return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
|
||||
}
|
||||
bool declareSig(Sig&& sig, uint32_t* sigIndex) {
|
||||
SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
|
||||
if (p) {
|
||||
*sigIndex = p->value();
|
||||
MOZ_ASSERT(mg_.sig(*sigIndex) == sig);
|
||||
return true;
|
||||
}
|
||||
|
||||
*sigIndex = sigMap_.count();
|
||||
if (*sigIndex >= MaxSigs)
|
||||
return failCurrentOffset("too many unique signatures");
|
||||
|
||||
mg_.initSig(*sigIndex, Move(sig));
|
||||
return sigMap_.add(p, &mg_.sig(*sigIndex), *sigIndex);
|
||||
}
|
||||
|
||||
// ModuleGeneratorData limits:
|
||||
static const unsigned MaxSigs = 4 * 1024;
|
||||
static const unsigned MaxFuncs = 512 * 1024;
|
||||
static const unsigned MaxImports = 4 * 1024;
|
||||
|
||||
public:
|
||||
ModuleValidator(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* moduleFunctionNode)
|
||||
|
@ -1666,6 +1690,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
functions_(cx),
|
||||
funcPtrTables_(cx),
|
||||
globalMap_(cx),
|
||||
sigMap_(cx),
|
||||
importMap_(cx),
|
||||
arrayViews_(cx),
|
||||
atomicsPresent_(false),
|
||||
|
@ -1697,7 +1722,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
module_->strict = parser_.pc->sc->strict() && !parser_.pc->sc->hasExplicitUseStrict();
|
||||
module_->scriptSource.reset(parser_.ss);
|
||||
|
||||
if (!globalMap_.init() || !importMap_.init())
|
||||
if (!globalMap_.init() || !sigMap_.init() || !importMap_.init())
|
||||
return false;
|
||||
|
||||
if (!standardLibraryMathNames_.init() ||
|
||||
|
@ -1756,7 +1781,16 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
}
|
||||
#undef ADDSTDLIBSIMDOPNAME
|
||||
|
||||
return mg_.init();
|
||||
UniqueModuleGeneratorData genData = MakeUnique<ModuleGeneratorData>();
|
||||
if (!genData ||
|
||||
!genData->sigs.resize(MaxSigs) ||
|
||||
!genData->funcSigs.resize(MaxFuncs) ||
|
||||
!genData->imports.resize(MaxImports))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mg_.init(Move(genData));
|
||||
}
|
||||
|
||||
ExclusiveContext* cx() const { return cx_; }
|
||||
|
@ -1970,11 +2004,8 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
|
||||
// Declare which function is exported which gives us an index into the
|
||||
// module ExportVector.
|
||||
MallocSig::ArgVector args;
|
||||
if (!args.appendAll(func.sig().args()))
|
||||
return false;
|
||||
uint32_t exportIndex;
|
||||
if (!mg_.declareExport(MallocSig(Move(args), func.sig().ret()), func.index(), &exportIndex))
|
||||
if (!mg_.declareExport(func.index(), &exportIndex))
|
||||
return false;
|
||||
|
||||
// Add a mapping from the given field to the Export's index.
|
||||
|
@ -1994,30 +2025,25 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
module_->exports.emplaceBack(func.srcBegin() - module_->srcStart,
|
||||
func.srcEnd() - module_->srcStart);
|
||||
}
|
||||
private:
|
||||
const LifoSig* getLifoSig(const LifoSig& sig) {
|
||||
return &sig;
|
||||
}
|
||||
const LifoSig* getLifoSig(const MallocSig& sig) {
|
||||
return mg_.newLifoSig(sig);
|
||||
}
|
||||
public:
|
||||
bool addFunction(PropertyName* name, uint32_t firstUse, const MallocSig& sig, Func** func) {
|
||||
bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
|
||||
uint32_t sigIndex;
|
||||
if (!declareSig(Move(sig), &sigIndex))
|
||||
return false;
|
||||
uint32_t funcIndex = numFunctions();
|
||||
if (funcIndex >= MaxFuncs)
|
||||
return failCurrentOffset("too many functions");
|
||||
if (!mg_.initFuncSig(funcIndex, sigIndex))
|
||||
return false;
|
||||
Global* global = validationLifo_.new_<Global>(Global::Function);
|
||||
if (!global)
|
||||
return false;
|
||||
global->u.funcIndex_ = funcIndex;
|
||||
if (!globalMap_.putNew(name, global))
|
||||
return false;
|
||||
const LifoSig* lifoSig = getLifoSig(sig);
|
||||
if (!lifoSig)
|
||||
return false;
|
||||
*func = validationLifo_.new_<Func>(name, firstUse, *lifoSig, funcIndex);
|
||||
*func = validationLifo_.new_<Func>(name, firstUse, funcIndex);
|
||||
return *func && functions_.append(*func);
|
||||
}
|
||||
template <class SigT>
|
||||
bool declareFuncPtrTable(PropertyName* name, uint32_t firstUse, SigT& sig, uint32_t mask,
|
||||
bool declareFuncPtrTable(Sig&& sig, PropertyName* name, uint32_t firstUse, uint32_t mask,
|
||||
uint32_t* index)
|
||||
{
|
||||
if (!mg_.declareFuncPtrTable(/* numElems = */ mask + 1, index))
|
||||
|
@ -2029,10 +2055,10 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
global->u.funcPtrTableIndex_ = *index;
|
||||
if (!globalMap_.putNew(name, global))
|
||||
return false;
|
||||
const LifoSig* lifoSig = getLifoSig(sig);
|
||||
if (!lifoSig)
|
||||
uint32_t sigIndex;
|
||||
if (!declareSig(Move(sig), &sigIndex))
|
||||
return false;
|
||||
FuncPtrTable* t = validationLifo_.new_<FuncPtrTable>(cx_, name, firstUse, *lifoSig, mask);
|
||||
FuncPtrTable* t = validationLifo_.new_<FuncPtrTable>(sigIndex, name, firstUse, mask);
|
||||
return t && funcPtrTables_.append(t);
|
||||
}
|
||||
bool defineFuncPtrTable(uint32_t funcPtrTableIndex, const Vector<uint32_t>& elems) {
|
||||
|
@ -2043,25 +2069,26 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
mg_.defineFuncPtrTable(funcPtrTableIndex, elems);
|
||||
return true;
|
||||
}
|
||||
bool addImport(PropertyName* name, MallocSig&& sig, unsigned ffiIndex, unsigned* importIndex,
|
||||
const LifoSig** lifoSig)
|
||||
{
|
||||
ImportDescriptor::Lookup lookup(name, sig);
|
||||
ImportMap::AddPtr p = importMap_.lookupForAdd(lookup);
|
||||
bool declareImport(PropertyName* name, Sig&& sig, unsigned ffiIndex, uint32_t* importIndex) {
|
||||
ImportMap::AddPtr p = importMap_.lookupForAdd(NamedSig::Lookup(name, sig));
|
||||
if (p) {
|
||||
*lifoSig = &p->key().sig();
|
||||
*importIndex = p->value();
|
||||
return true;
|
||||
}
|
||||
*lifoSig = getLifoSig(sig);
|
||||
if (!*lifoSig)
|
||||
*importIndex = module_->imports.length();
|
||||
if (*importIndex >= MaxImports)
|
||||
return failCurrentOffset("too many imports");
|
||||
if (!module_->imports.emplaceBack(ffiIndex))
|
||||
return false;
|
||||
if (!mg_.declareImport(Move(sig), importIndex))
|
||||
uint32_t sigIndex;
|
||||
if (!declareSig(Move(sig), &sigIndex))
|
||||
return false;
|
||||
if (!importMap_.add(p, ImportDescriptor(name, **lifoSig), *importIndex))
|
||||
uint32_t globalDataOffset;
|
||||
if (!mg_.allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
|
||||
return false;
|
||||
MOZ_ASSERT(module_->imports.length() == *importIndex);
|
||||
return module_->imports.emplaceBack(ffiIndex);
|
||||
if (!mg_.initImport(*importIndex, sigIndex, globalDataOffset))
|
||||
return false;
|
||||
return importMap_.add(p, NamedSig(name, mg_.sig(sigIndex)), *importIndex);
|
||||
}
|
||||
|
||||
bool tryConstantAccess(uint64_t start, uint64_t width) {
|
||||
|
@ -2089,6 +2116,10 @@ class MOZ_STACK_CLASS ModuleValidator
|
|||
return false;
|
||||
}
|
||||
|
||||
bool failCurrentOffset(const char* str) {
|
||||
return failOffset(tokenStream().currentToken().pos.begin, str);
|
||||
}
|
||||
|
||||
bool fail(ParseNode* pn, const char* str) {
|
||||
return failOffset(pn->pn_pos.begin, str);
|
||||
}
|
||||
|
@ -2588,8 +2619,8 @@ class MOZ_STACK_CLASS FunctionValidator
|
|||
labels_.init();
|
||||
}
|
||||
|
||||
bool finish(uint32_t funcIndex, const LifoSig& sig, unsigned generateTime) {
|
||||
return m_.mg().finishFunc(funcIndex, sig, encoder().finish(), generateTime, &fg_);
|
||||
bool finish(uint32_t funcIndex, unsigned generateTime) {
|
||||
return m_.mg().finishFunc(funcIndex, encoder().finish(), generateTime, &fg_);
|
||||
}
|
||||
|
||||
bool fail(ParseNode* pn, const char* str) {
|
||||
|
@ -2752,9 +2783,6 @@ class MOZ_STACK_CLASS FunctionValidator
|
|||
static_assert(sizeof(T) == sizeof(uint32_t), "patch32 is used for 4-bytes long ops");
|
||||
encoder().patch32(pos, val);
|
||||
}
|
||||
void patchSig(size_t pos, const LifoSig* ptr) {
|
||||
encoder().patchSig(pos, ptr);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool tempU8(size_t* offset) {
|
||||
|
@ -2774,17 +2802,6 @@ class MOZ_STACK_CLASS FunctionValidator
|
|||
}
|
||||
return true;
|
||||
}
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool tempPtr(size_t* offset) {
|
||||
if (!encoder().writeU8(uint8_t(Expr::Unreachable), offset))
|
||||
return false;
|
||||
for (size_t i = 1; i < sizeof(intptr_t); i++) {
|
||||
if (!encoder().writeU8(uint8_t(Expr::Unreachable)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/************************************************** End of build helpers */
|
||||
};
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
@ -3265,15 +3282,13 @@ CheckModuleProcessingDirectives(ModuleValidator& m)
|
|||
return true;
|
||||
|
||||
if (!IsIgnoredDirectiveName(m.cx(), ts.currentToken().atom()))
|
||||
return m.failOffset(ts.currentToken().pos.begin, "unsupported processing directive");
|
||||
return m.failCurrentOffset("unsupported processing directive");
|
||||
|
||||
TokenKind tt;
|
||||
if (!ts.getToken(&tt))
|
||||
return false;
|
||||
if (tt != TOK_SEMI) {
|
||||
return m.failOffset(ts.currentToken().pos.begin,
|
||||
"expected semicolon after string literal");
|
||||
}
|
||||
if (tt != TOK_SEMI)
|
||||
return m.failCurrentOffset("expected semicolon after string literal");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3341,7 +3356,7 @@ CheckProcessingDirectives(ModuleValidator& m, ParseNode** stmtIter)
|
|||
}
|
||||
|
||||
static bool
|
||||
CheckArguments(FunctionValidator& f, ParseNode** stmtIter, MallocSig::ArgVector* argTypes)
|
||||
CheckArguments(FunctionValidator& f, ParseNode** stmtIter, ValTypeVector* argTypes)
|
||||
{
|
||||
ParseNode* stmt = *stmtIter;
|
||||
|
||||
|
@ -4318,7 +4333,7 @@ typedef bool (*CheckArgType)(FunctionValidator& f, ParseNode* argNode, Type type
|
|||
|
||||
template <CheckArgType checkArg>
|
||||
static bool
|
||||
CheckCallArgs(FunctionValidator& f, ParseNode* callNode, MallocSig::ArgVector* args)
|
||||
CheckCallArgs(FunctionValidator& f, ParseNode* callNode, ValTypeVector* args)
|
||||
{
|
||||
ParseNode* argNode = CallArgList(callNode);
|
||||
for (unsigned i = 0; i < CallArgListLength(callNode); i++, argNode = NextNode(argNode)) {
|
||||
|
@ -4335,10 +4350,8 @@ CheckCallArgs(FunctionValidator& f, ParseNode* callNode, MallocSig::ArgVector* a
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class SigT>
|
||||
static bool
|
||||
CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, SigT& sig,
|
||||
const LifoSig& existing)
|
||||
CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, const Sig& sig, const Sig& existing)
|
||||
{
|
||||
if (sig.args().length() != existing.args().length()) {
|
||||
return m.failf(usepn, "incompatible number of arguments (%u here vs. %u before)",
|
||||
|
@ -4362,17 +4375,17 @@ CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, SigT& sig,
|
|||
}
|
||||
|
||||
static bool
|
||||
CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, const MallocSig& sig,
|
||||
PropertyName* name, ModuleValidator::Func** func)
|
||||
CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, PropertyName* name,
|
||||
ModuleValidator::Func** func)
|
||||
{
|
||||
ModuleValidator::Func* existing = m.lookupFunction(name);
|
||||
if (!existing) {
|
||||
if (!CheckModuleLevelName(m, usepn, name))
|
||||
return false;
|
||||
return m.addFunction(name, usepn->pn_pos.begin, sig, func);
|
||||
return m.addFunction(name, usepn->pn_pos.begin, Move(sig), func);
|
||||
}
|
||||
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, existing->sig()))
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().funcSig(existing->index())))
|
||||
return false;
|
||||
|
||||
*func = existing;
|
||||
|
@ -4396,34 +4409,28 @@ CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calle
|
|||
|
||||
// Function's index, to find out the function's entry
|
||||
size_t funcIndexAt;
|
||||
// Function's signature in lifo
|
||||
size_t sigAt;
|
||||
if (!f.temp32(&funcIndexAt) || !f.tempPtr(&sigAt))
|
||||
if (!f.temp32(&funcIndexAt))
|
||||
return false;
|
||||
|
||||
if (!f.noteLineCol(callNode))
|
||||
return false;
|
||||
|
||||
MallocSig::ArgVector args;
|
||||
ValTypeVector args;
|
||||
if (!CheckCallArgs<CheckIsVarType>(f, callNode, &args))
|
||||
return false;
|
||||
|
||||
MallocSig sig(Move(args), ret);
|
||||
|
||||
ModuleValidator::Func* callee;
|
||||
if (!CheckFunctionSignature(f.m(), callNode, sig, calleeName, &callee))
|
||||
if (!CheckFunctionSignature(f.m(), callNode, Sig(Move(args), ret), calleeName, &callee))
|
||||
return false;
|
||||
|
||||
f.patch32(funcIndexAt, callee->index());
|
||||
f.patchSig(sigAt, &callee->sig());
|
||||
*type = Type::ret(ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class SigT>
|
||||
static bool
|
||||
CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyName* name,
|
||||
SigT& sig, unsigned mask, uint32_t* funcPtrTableIndex)
|
||||
Sig&& sig, unsigned mask, uint32_t* funcPtrTableIndex)
|
||||
{
|
||||
if (const ModuleValidator::Global* existing = m.lookupGlobal(name)) {
|
||||
if (existing->which() != ModuleValidator::Global::FuncPtrTable)
|
||||
|
@ -4433,7 +4440,7 @@ CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyN
|
|||
if (mask != table.mask())
|
||||
return m.failf(usepn, "mask does not match previous value (%u)", table.mask());
|
||||
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, table.sig()))
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().sig(table.sigIndex())))
|
||||
return false;
|
||||
|
||||
*funcPtrTableIndex = existing->funcPtrTableIndex();
|
||||
|
@ -4443,7 +4450,7 @@ CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyN
|
|||
if (!CheckModuleLevelName(m, usepn, name))
|
||||
return false;
|
||||
|
||||
if (!m.declareFuncPtrTable(name, usepn->pn_pos.begin, sig, mask, funcPtrTableIndex))
|
||||
if (!m.declareFuncPtrTable(Move(sig), name, usepn->pn_pos.begin, mask, funcPtrTableIndex))
|
||||
return m.fail(usepn, "table too big");
|
||||
|
||||
return true;
|
||||
|
@ -4478,16 +4485,19 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, ExprType ret, Type*
|
|||
// Opcode
|
||||
if (!f.writeOp(Expr::CallIndirect))
|
||||
return false;
|
||||
|
||||
// Table's mask
|
||||
if (!f.writeU32(mask))
|
||||
return false;
|
||||
|
||||
// Global data offset
|
||||
size_t globalDataOffsetAt;
|
||||
if (!f.temp32(&globalDataOffsetAt))
|
||||
return false;
|
||||
// Signature
|
||||
size_t sigAt;
|
||||
if (!f.tempPtr(&sigAt))
|
||||
|
||||
// Call signature
|
||||
size_t sigIndexAt;
|
||||
if (!f.temp32(&sigIndexAt))
|
||||
return false;
|
||||
|
||||
if (!f.noteLineCol(callNode))
|
||||
|
@ -4500,18 +4510,18 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, ExprType ret, Type*
|
|||
if (!indexType.isIntish())
|
||||
return f.failf(indexNode, "%s is not a subtype of intish", indexType.toChars());
|
||||
|
||||
MallocSig::ArgVector args;
|
||||
ValTypeVector args;
|
||||
if (!CheckCallArgs<CheckIsVarType>(f, callNode, &args))
|
||||
return false;
|
||||
|
||||
MallocSig sig(Move(args), ret);
|
||||
Sig sig(Move(args), ret);
|
||||
|
||||
uint32_t funcPtrTableIndex;
|
||||
if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, sig, mask, &funcPtrTableIndex))
|
||||
uint32_t tableIndex;
|
||||
if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex))
|
||||
return false;
|
||||
|
||||
f.patch32(globalDataOffsetAt, f.m().mg().funcPtrTableGlobalDataOffset(funcPtrTableIndex));
|
||||
f.patchSig(sigAt, &f.m().funcPtrTable(funcPtrTableIndex).sig());
|
||||
f.patch32(globalDataOffsetAt, f.m().mg().funcPtrTableGlobalDataOffset(tableIndex));
|
||||
f.patch32(sigIndexAt, f.m().funcPtrTable(tableIndex).sigIndex());
|
||||
|
||||
*type = Type::ret(ret);
|
||||
return true;
|
||||
|
@ -4539,31 +4549,25 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, ExprT
|
|||
// Opcode
|
||||
if (!f.writeOp(Expr::CallImport))
|
||||
return false;
|
||||
// Global data offset
|
||||
size_t offsetAt;
|
||||
if (!f.temp32(&offsetAt))
|
||||
return false;
|
||||
// Pointer to the import's signature in the module's lifo
|
||||
size_t sigAt;
|
||||
if (!f.tempPtr(&sigAt))
|
||||
|
||||
// Import index
|
||||
size_t importIndexAt;
|
||||
if (!f.temp32(&importIndexAt))
|
||||
return false;
|
||||
|
||||
if (!f.noteLineCol(callNode))
|
||||
return false;
|
||||
|
||||
MallocSig::ArgVector args;
|
||||
ValTypeVector args;
|
||||
if (!CheckCallArgs<CheckIsExternType>(f, callNode, &args))
|
||||
return false;
|
||||
|
||||
MallocSig sig(Move(args), ret);
|
||||
|
||||
unsigned importIndex = 0;
|
||||
const LifoSig* lifoSig = nullptr;
|
||||
if (!f.m().addImport(calleeName, Move(sig), ffiIndex, &importIndex, &lifoSig))
|
||||
uint32_t importIndex;
|
||||
if (!f.m().declareImport(calleeName, Sig(Move(args), ret), ffiIndex, &importIndex))
|
||||
return false;
|
||||
|
||||
f.patch32(offsetAt, f.m().mg().importExitGlobalDataOffset(importIndex));
|
||||
f.patchSig(sigAt, lifoSig);
|
||||
f.patch32(importIndexAt, importIndex);
|
||||
|
||||
*type = Type::ret(ret);
|
||||
return true;
|
||||
}
|
||||
|
@ -6846,7 +6850,7 @@ CheckFunction(ModuleValidator& m)
|
|||
if (!CheckProcessingDirectives(m, &stmtIter))
|
||||
return false;
|
||||
|
||||
MallocSig::ArgVector args;
|
||||
ValTypeVector args;
|
||||
if (!CheckArguments(f, &stmtIter, &args))
|
||||
return false;
|
||||
|
||||
|
@ -6867,10 +6871,8 @@ CheckFunction(ModuleValidator& m)
|
|||
if (!CheckFinalReturn(f, lastNonEmptyStmt))
|
||||
return false;
|
||||
|
||||
MallocSig sig(Move(args), f.returnedType());
|
||||
|
||||
ModuleValidator::Func* func = nullptr;
|
||||
if (!CheckFunctionSignature(m, fn, sig, FunctionName(fn), &func))
|
||||
if (!CheckFunctionSignature(m, fn, Sig(Move(args), f.returnedType()), FunctionName(fn), &func))
|
||||
return false;
|
||||
|
||||
if (func->defined())
|
||||
|
@ -6878,7 +6880,7 @@ CheckFunction(ModuleValidator& m)
|
|||
|
||||
func->define(fn);
|
||||
|
||||
if (!f.finish(func->index(), func->sig(), (PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC))
|
||||
if (!f.finish(func->index(), (PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC))
|
||||
return m.fail(fn, "internal compiler failure (probably out of memory)");
|
||||
|
||||
// Release the parser's lifo memory only after the last use of a parse node.
|
||||
|
@ -6934,7 +6936,7 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
|
|||
unsigned mask = length - 1;
|
||||
|
||||
Vector<uint32_t> elemFuncIndices(m.cx());
|
||||
const LifoSig* sig = nullptr;
|
||||
const Sig* sig = nullptr;
|
||||
for (ParseNode* elem = ListHead(arrayLiteral); elem; elem = NextNode(elem)) {
|
||||
if (!elem->isKind(PNK_NAME))
|
||||
return m.fail(elem, "function-pointer table's elements must be names of functions");
|
||||
|
@ -6944,22 +6946,27 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
|
|||
if (!func)
|
||||
return m.fail(elem, "function-pointer table's elements must be names of functions");
|
||||
|
||||
const Sig& funcSig = m.mg().funcSig(func->index());
|
||||
if (sig) {
|
||||
if (*sig != func->sig())
|
||||
if (*sig != funcSig)
|
||||
return m.fail(elem, "all functions in table must have same signature");
|
||||
} else {
|
||||
sig = &func->sig();
|
||||
sig = &funcSig;
|
||||
}
|
||||
|
||||
if (!elemFuncIndices.append(func->index()))
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t funcPtrTableIndex;
|
||||
if (!CheckFuncPtrTableAgainstExisting(m, var, var->name(), *sig, mask, &funcPtrTableIndex))
|
||||
Sig copy;
|
||||
if (!copy.clone(*sig))
|
||||
return false;
|
||||
|
||||
if (!m.defineFuncPtrTable(funcPtrTableIndex, elemFuncIndices))
|
||||
uint32_t tableIndex;
|
||||
if (!CheckFuncPtrTableAgainstExisting(m, var, var->name(), Move(copy), mask, &tableIndex))
|
||||
return false;
|
||||
|
||||
if (!m.defineFuncPtrTable(tableIndex, elemFuncIndices))
|
||||
return m.fail(var, "duplicate function-pointer definition");
|
||||
|
||||
return true;
|
||||
|
@ -7039,10 +7046,9 @@ CheckModuleReturn(ModuleValidator& m)
|
|||
return false;
|
||||
TokenStream& ts = m.parser().tokenStream;
|
||||
if (tk != TOK_RETURN) {
|
||||
const char* msg = (tk == TOK_RC || tk == TOK_EOF)
|
||||
? "expecting return statement"
|
||||
: "invalid asm.js. statement";
|
||||
return m.failOffset(ts.currentToken().pos.begin, msg);
|
||||
return m.failCurrentOffset((tk == TOK_RC || tk == TOK_EOF)
|
||||
? "expecting return statement"
|
||||
: "invalid asm.js. statement");
|
||||
}
|
||||
ts.ungetToken();
|
||||
|
||||
|
@ -7077,10 +7083,8 @@ CheckModuleEnd(ModuleValidator &m)
|
|||
if (!GetToken(m.parser(), &tk))
|
||||
return false;
|
||||
|
||||
if (tk != TOK_EOF && tk != TOK_RC) {
|
||||
return m.failOffset(m.parser().tokenStream.currentToken().pos.begin,
|
||||
"top-level export (return) must be the last statement");
|
||||
}
|
||||
if (tk != TOK_EOF && tk != TOK_RC)
|
||||
return m.failCurrentOffset("top-level export (return) must be the last statement");
|
||||
|
||||
m.parser().tokenStream.ungetToken();
|
||||
return true;
|
||||
|
|
|
@ -309,7 +309,7 @@ typedef UniquePtr<Bytecode> UniqueBytecode;
|
|||
class Encoder
|
||||
{
|
||||
UniqueBytecode bytecode_;
|
||||
mozilla::DebugOnly<bool> done_;
|
||||
DebugOnly<bool> done_;
|
||||
|
||||
template<class T>
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
|
@ -327,7 +327,7 @@ class Encoder
|
|||
|
||||
bool init(UniqueBytecode bytecode = UniqueBytecode()) {
|
||||
if (bytecode) {
|
||||
bytecode_ = mozilla::Move(bytecode);
|
||||
bytecode_ = Move(bytecode);
|
||||
bytecode_->clear();
|
||||
return true;
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ class Encoder
|
|||
UniqueBytecode finish() {
|
||||
MOZ_ASSERT(!done_);
|
||||
done_ = true;
|
||||
return mozilla::Move(bytecode_);
|
||||
return Move(bytecode_);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool
|
||||
|
@ -410,11 +410,6 @@ class Encoder
|
|||
MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint32_t)));
|
||||
memcpy(&(*bytecode_)[pc], &i, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void patchSig(size_t pc, const LifoSig* ptr) {
|
||||
MOZ_ASSERT(pcIsPatchable(pc, sizeof(LifoSig*)));
|
||||
memcpy(&(*bytecode_)[pc], &ptr, sizeof(LifoSig*));
|
||||
}
|
||||
};
|
||||
|
||||
class Decoder
|
||||
|
@ -465,7 +460,6 @@ class Decoder
|
|||
MOZ_WARN_UNUSED_RESULT bool readF32(float* f) { return read(f); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readU32(uint32_t* u) { return read(u); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readF64(double* d) { return read(d); }
|
||||
MOZ_WARN_UNUSED_RESULT bool readSig(const LifoSig* sig) { return read(sig); }
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT bool readI32X4(jit::SimdConstant* c) {
|
||||
int32_t v[4] = { 0, 0, 0, 0 };
|
||||
|
@ -513,7 +507,6 @@ class Decoder
|
|||
float uncheckedReadF32() { return uncheckedRead<float>(); }
|
||||
uint32_t uncheckedReadU32() { return uncheckedRead<uint32_t>(); }
|
||||
double uncheckedReadF64() { return uncheckedRead<double>(); }
|
||||
const LifoSig* uncheckedReadSig() { return uncheckedRead<const LifoSig*>(); }
|
||||
|
||||
jit::SimdConstant uncheckedReadI32X4() {
|
||||
int32_t v[4] = { 0, 0, 0, 0 };
|
||||
|
@ -558,7 +551,6 @@ struct SourceCoords {
|
|||
};
|
||||
|
||||
typedef Vector<SourceCoords, 0, SystemAllocPolicy> SourceCoordsVector;
|
||||
typedef Vector<ValType, 0, SystemAllocPolicy> ValTypeVector;
|
||||
|
||||
// The FuncBytecode class contains the intermediate representation of a
|
||||
// parsed/decoded and validated asm.js/WebAssembly function. The FuncBytecode
|
||||
|
@ -574,7 +566,7 @@ class FuncBytecode
|
|||
SourceCoordsVector callSourceCoords_;
|
||||
|
||||
uint32_t index_;
|
||||
const LifoSig& sig_;
|
||||
const DeclaredSig& sig_;
|
||||
UniqueBytecode bytecode_;
|
||||
ValTypeVector localVars_;
|
||||
unsigned generateTime_;
|
||||
|
@ -585,22 +577,22 @@ class FuncBytecode
|
|||
unsigned column,
|
||||
SourceCoordsVector&& sourceCoords,
|
||||
uint32_t index,
|
||||
const LifoSig& sig,
|
||||
const DeclaredSig& sig,
|
||||
UniqueBytecode bytecode,
|
||||
ValTypeVector&& localVars,
|
||||
unsigned generateTime)
|
||||
: name_(name),
|
||||
line_(line),
|
||||
column_(column),
|
||||
callSourceCoords_(mozilla::Move(sourceCoords)),
|
||||
callSourceCoords_(Move(sourceCoords)),
|
||||
index_(index),
|
||||
sig_(sig),
|
||||
bytecode_(mozilla::Move(bytecode)),
|
||||
localVars_(mozilla::Move(localVars)),
|
||||
bytecode_(Move(bytecode)),
|
||||
localVars_(Move(localVars)),
|
||||
generateTime_(generateTime)
|
||||
{}
|
||||
|
||||
UniqueBytecode recycleBytecode() { return mozilla::Move(bytecode_); }
|
||||
UniqueBytecode recycleBytecode() { return Move(bytecode_); }
|
||||
|
||||
PropertyName* name() const { return name_; }
|
||||
unsigned line() const { return line_; }
|
||||
|
@ -608,7 +600,7 @@ class FuncBytecode
|
|||
const SourceCoords& sourceCoords(size_t i) const { return callSourceCoords_[i]; }
|
||||
|
||||
uint32_t index() const { return index_; }
|
||||
const LifoSig& sig() const { return sig_; }
|
||||
const DeclaredSig& sig() const { return sig_; }
|
||||
const Bytecode& bytecode() const { return *bytecode_; }
|
||||
|
||||
size_t numLocalVars() const { return localVars_.length(); }
|
||||
|
|
|
@ -35,14 +35,11 @@ static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|||
|
||||
ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
|
||||
: cx_(cx),
|
||||
jcx_(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread())),
|
||||
slowFuncs_(cx),
|
||||
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
|
||||
jcx_(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread())),
|
||||
alloc_(&lifo_),
|
||||
masm_(MacroAssembler::AsmJSToken(), alloc_),
|
||||
sigs_(cx),
|
||||
funcEntryOffsets_(cx),
|
||||
exportFuncIndices_(cx),
|
||||
funcIndexToExport_(cx),
|
||||
parallel_(false),
|
||||
outstanding_(0),
|
||||
|
@ -105,20 +102,26 @@ ParallelCompilationEnabled(ExclusiveContext* cx)
|
|||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::init()
|
||||
ModuleGenerator::init(UniqueModuleGeneratorData shared)
|
||||
{
|
||||
module_ = cx_->make_unique<ModuleData>();
|
||||
module_ = MakeUnique<ModuleData>();
|
||||
if (!module_)
|
||||
return false;
|
||||
|
||||
module_->globalBytes = InitialGlobalDataBytes;
|
||||
module_->compileArgs = CompileArgs(cx_);
|
||||
|
||||
link_ = cx_->make_unique<StaticLinkData>();
|
||||
link_ = MakeUnique<StaticLinkData>();
|
||||
if (!link_)
|
||||
return false;
|
||||
|
||||
if (!sigs_.init() || !funcIndexToExport_.init())
|
||||
shared_ = Move(shared);
|
||||
|
||||
threadView_ = MakeUnique<ModuleGeneratorThreadView>(*shared_);
|
||||
if (!threadView_)
|
||||
return false;
|
||||
|
||||
if (!funcIndexToExport_.init())
|
||||
return false;
|
||||
|
||||
uint32_t numTasks;
|
||||
|
@ -142,9 +145,9 @@ ModuleGenerator::init()
|
|||
|
||||
if (!tasks_.initCapacity(numTasks))
|
||||
return false;
|
||||
JSRuntime* runtime = cx_->compartment()->runtimeFromAnyThread();
|
||||
JSRuntime* rt = cx_->compartment()->runtimeFromAnyThread();
|
||||
for (size_t i = 0; i < numTasks; i++)
|
||||
tasks_.infallibleEmplaceBack(runtime, args(), COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
tasks_.infallibleEmplaceBack(rt, args(), *threadView_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
if (!freeTasks_.reserve(numTasks))
|
||||
return false;
|
||||
|
@ -154,23 +157,6 @@ ModuleGenerator::init()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
|
||||
{
|
||||
uint32_t globalBytes = module_->globalBytes;
|
||||
|
||||
uint32_t pad = ComputeByteAlignment(globalBytes, align);
|
||||
if (UINT32_MAX - globalBytes < pad + bytes)
|
||||
return false;
|
||||
|
||||
globalBytes += pad;
|
||||
*globalDataOffset = globalBytes;
|
||||
globalBytes += bytes;
|
||||
|
||||
module_->globalBytes = globalBytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishOutstandingTask()
|
||||
{
|
||||
|
@ -210,6 +196,7 @@ ModuleGenerator::finishTask(IonCompileTask* task)
|
|||
results.offsets().offsetBy(offsetInWhole);
|
||||
|
||||
// Record the non-profiling entry for whole-module linking later.
|
||||
// Cannot simply append because funcIndex order is nonlinear.
|
||||
if (func.index() >= funcEntryOffsets_.length()) {
|
||||
if (!funcEntryOffsets_.resize(func.index() + 1))
|
||||
return false;
|
||||
|
@ -243,18 +230,21 @@ ModuleGenerator::finishTask(IonCompileTask* task)
|
|||
return true;
|
||||
}
|
||||
|
||||
const LifoSig*
|
||||
ModuleGenerator::newLifoSig(const MallocSig& sig)
|
||||
bool
|
||||
ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
|
||||
{
|
||||
SigSet::AddPtr p = sigs_.lookupForAdd(sig);
|
||||
if (p)
|
||||
return *p;
|
||||
uint32_t globalBytes = module_->globalBytes;
|
||||
|
||||
LifoSig* lifoSig = LifoSig::new_(lifo_, sig);
|
||||
if (!lifoSig || !sigs_.add(p, lifoSig))
|
||||
return nullptr;
|
||||
uint32_t pad = ComputeByteAlignment(globalBytes, align);
|
||||
if (UINT32_MAX - globalBytes < pad + bytes)
|
||||
return false;
|
||||
|
||||
return lifoSig;
|
||||
globalBytes += pad;
|
||||
*globalDataOffset = globalBytes;
|
||||
globalBytes += bytes;
|
||||
|
||||
module_->globalBytes = globalBytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -279,17 +269,35 @@ ModuleGenerator::allocateGlobalVar(ValType type, uint32_t* globalDataOffset)
|
|||
return allocateGlobalBytes(width, width, globalDataOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::declareImport(MallocSig&& sig, unsigned* index)
|
||||
void
|
||||
ModuleGenerator::initSig(uint32_t sigIndex, Sig&& sig)
|
||||
{
|
||||
static_assert(Module::SizeOfImportExit % sizeof(void*) == 0, "word aligned");
|
||||
MOZ_ASSERT(shared_->sigs[sigIndex] == Sig());
|
||||
shared_->sigs[sigIndex] = Move(sig);
|
||||
}
|
||||
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
|
||||
const DeclaredSig&
|
||||
ModuleGenerator::sig(uint32_t index) const
|
||||
{
|
||||
return shared_->sigs[index];
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset)
|
||||
{
|
||||
MOZ_ASSERT(importIndex == module_->imports.length());
|
||||
|
||||
Sig copy;
|
||||
if (!copy.clone(sig(sigIndex)))
|
||||
return false;
|
||||
if (!module_->imports.emplaceBack(Move(copy), globalDataOffset))
|
||||
return false;
|
||||
|
||||
*index = unsigned(module_->imports.length());
|
||||
return module_->imports.emplaceBack(Move(sig), globalDataOffset);
|
||||
ModuleImportGeneratorData& import = shared_->imports[importIndex];
|
||||
MOZ_ASSERT(!import.sig);
|
||||
import.sig = &shared_->sigs[sigIndex];
|
||||
import.globalDataOffset = globalDataOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -298,16 +306,11 @@ ModuleGenerator::numImports() const
|
|||
return module_->imports.length();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ModuleGenerator::importExitGlobalDataOffset(uint32_t index) const
|
||||
const ModuleImportGeneratorData&
|
||||
ModuleGenerator::import(uint32_t index) const
|
||||
{
|
||||
return module_->imports[index].exitGlobalDataOffset();
|
||||
}
|
||||
|
||||
const MallocSig&
|
||||
ModuleGenerator::importSig(uint32_t index) const
|
||||
{
|
||||
return module_->imports[index].sig();
|
||||
MOZ_ASSERT(shared_->imports[index].sig);
|
||||
return shared_->imports[index];
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -321,7 +324,7 @@ ModuleGenerator::defineImport(uint32_t index, ProfilingOffsets interpExit, Profi
|
|||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* exportIndex)
|
||||
ModuleGenerator::declareExport(uint32_t funcIndex, uint32_t* exportIndex)
|
||||
{
|
||||
FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
|
||||
if (p) {
|
||||
|
@ -329,9 +332,13 @@ ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* ex
|
|||
return true;
|
||||
}
|
||||
|
||||
Sig copy;
|
||||
if (!copy.clone(funcSig(funcIndex)))
|
||||
return false;
|
||||
|
||||
*exportIndex = module_->exports.length();
|
||||
return funcIndexToExport_.add(p, funcIndex, *exportIndex) &&
|
||||
module_->exports.append(Move(sig)) &&
|
||||
module_->exports.append(Move(copy)) &&
|
||||
exportFuncIndices_.append(funcIndex);
|
||||
}
|
||||
|
||||
|
@ -341,7 +348,7 @@ ModuleGenerator::exportFuncIndex(uint32_t index) const
|
|||
return exportFuncIndices_[index];
|
||||
}
|
||||
|
||||
const MallocSig&
|
||||
const Sig&
|
||||
ModuleGenerator::exportSig(uint32_t index) const
|
||||
{
|
||||
return module_->exports[index].sig();
|
||||
|
@ -360,6 +367,21 @@ ModuleGenerator::defineExport(uint32_t index, Offsets offsets)
|
|||
return module_->codeRanges.emplaceBack(CodeRange::Entry, offsets);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::initFuncSig(uint32_t funcIndex, uint32_t sigIndex)
|
||||
{
|
||||
MOZ_ASSERT(!shared_->funcSigs[funcIndex]);
|
||||
shared_->funcSigs[funcIndex] = &shared_->sigs[sigIndex];
|
||||
return true;
|
||||
}
|
||||
|
||||
const DeclaredSig&
|
||||
ModuleGenerator::funcSig(uint32_t funcIndex) const
|
||||
{
|
||||
MOZ_ASSERT(shared_->funcSigs[funcIndex]);
|
||||
return *shared_->funcSigs[funcIndex];
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::startFunc(PropertyName* name, unsigned line, unsigned column,
|
||||
UniqueBytecode* recycled, FunctionGenerator* fg)
|
||||
|
@ -384,21 +406,21 @@ ModuleGenerator::startFunc(PropertyName* name, unsigned line, unsigned column,
|
|||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::finishFunc(uint32_t funcIndex, const LifoSig& sig, UniqueBytecode bytecode,
|
||||
unsigned generateTime, FunctionGenerator* fg)
|
||||
ModuleGenerator::finishFunc(uint32_t funcIndex, UniqueBytecode bytecode, unsigned generateTime,
|
||||
FunctionGenerator* fg)
|
||||
{
|
||||
MOZ_ASSERT(activeFunc_ == fg);
|
||||
|
||||
UniqueFuncBytecode func = cx_->make_unique<FuncBytecode>(fg->name_,
|
||||
fg->line_,
|
||||
fg->column_,
|
||||
Move(fg->callSourceCoords_),
|
||||
funcIndex,
|
||||
sig,
|
||||
Move(bytecode),
|
||||
Move(fg->localVars_),
|
||||
generateTime
|
||||
);
|
||||
UniqueFuncBytecode func =
|
||||
js::MakeUnique<FuncBytecode>(fg->name_,
|
||||
fg->line_,
|
||||
fg->column_,
|
||||
Move(fg->callSourceCoords_),
|
||||
funcIndex,
|
||||
funcSig(funcIndex),
|
||||
Move(bytecode),
|
||||
Move(fg->localVars_),
|
||||
generateTime);
|
||||
if (!func)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -28,9 +28,11 @@ namespace js {
|
|||
namespace wasm {
|
||||
|
||||
class FunctionGenerator;
|
||||
typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector;
|
||||
|
||||
// A slow function describes a function that took longer than msThreshold to
|
||||
// validate and compile.
|
||||
|
||||
struct SlowFunction
|
||||
{
|
||||
SlowFunction(PropertyName* name, unsigned ms, unsigned line, unsigned column)
|
||||
|
@ -46,53 +48,96 @@ struct SlowFunction
|
|||
};
|
||||
typedef Vector<SlowFunction> SlowFunctionVector;
|
||||
|
||||
// The ModuleGeneratorData holds all the state shared between the
|
||||
// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData is
|
||||
// encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
|
||||
// present a race-free interface to the code in each thread assuming any given
|
||||
// element is initialized by the ModuleGenerator thread before an index to that
|
||||
// element is written to Bytecode sent to a ModuleGeneratorThreadView thread.
|
||||
// Once created, the Vectors are never resized.
|
||||
|
||||
struct ModuleImportGeneratorData
|
||||
{
|
||||
DeclaredSig* sig;
|
||||
uint32_t globalDataOffset;
|
||||
};
|
||||
|
||||
typedef Vector<ModuleImportGeneratorData, 0, SystemAllocPolicy> ModuleImportGeneratorDataVector;
|
||||
|
||||
struct ModuleGeneratorData
|
||||
{
|
||||
DeclaredSigVector sigs;
|
||||
DeclaredSigPtrVector funcSigs;
|
||||
ModuleImportGeneratorDataVector imports;
|
||||
};
|
||||
|
||||
typedef UniquePtr<ModuleGeneratorData> UniqueModuleGeneratorData;
|
||||
|
||||
// The ModuleGeneratorThreadView class presents a restricted, read-only view of
|
||||
// the shared state needed by helper threads. There is only one
|
||||
// ModuleGeneratorThreadView object owned by ModuleGenerator and referenced by
|
||||
// all compile tasks.
|
||||
|
||||
class ModuleGeneratorThreadView
|
||||
{
|
||||
const ModuleGeneratorData& shared_;
|
||||
|
||||
public:
|
||||
explicit ModuleGeneratorThreadView(const ModuleGeneratorData& shared)
|
||||
: shared_(shared)
|
||||
{}
|
||||
const DeclaredSig& sig(uint32_t sigIndex) const {
|
||||
return shared_.sigs[sigIndex];
|
||||
}
|
||||
const DeclaredSig& funcSig(uint32_t funcIndex) const {
|
||||
MOZ_ASSERT(shared_.funcSigs[funcIndex]);
|
||||
return *shared_.funcSigs[funcIndex];
|
||||
}
|
||||
const ModuleImportGeneratorData& import(uint32_t importIndex) const {
|
||||
MOZ_ASSERT(shared_.imports[importIndex].sig);
|
||||
return shared_.imports[importIndex];
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
// functions, ModuleGenerator::finish() must be called to complete the
|
||||
// compilation and extract the resulting wasm module.
|
||||
|
||||
class MOZ_STACK_CLASS ModuleGenerator
|
||||
{
|
||||
typedef Vector<uint32_t> FuncOffsetVector;
|
||||
typedef Vector<uint32_t> FuncIndexVector;
|
||||
typedef UniquePtr<ModuleGeneratorThreadView> UniqueModuleGeneratorThreadView;
|
||||
typedef HashMap<uint32_t, uint32_t> FuncIndexMap;
|
||||
|
||||
struct SigHashPolicy
|
||||
{
|
||||
typedef const MallocSig& Lookup;
|
||||
static HashNumber hash(Lookup l) { return l.hash(); }
|
||||
static bool match(const LifoSig* lhs, Lookup rhs) { return *lhs == rhs; }
|
||||
};
|
||||
typedef HashSet<const LifoSig*, SigHashPolicy> SigSet;
|
||||
|
||||
ExclusiveContext* cx_;
|
||||
ExclusiveContext* cx_;
|
||||
jit::JitContext jcx_;
|
||||
|
||||
// Data handed back to the caller in finish()
|
||||
UniqueModuleData module_;
|
||||
UniqueStaticLinkData link_;
|
||||
SlowFunctionVector slowFuncs_;
|
||||
UniqueModuleData module_;
|
||||
UniqueStaticLinkData link_;
|
||||
SlowFunctionVector slowFuncs_;
|
||||
|
||||
// Data scoped to the ModuleGenerator's lifetime
|
||||
LifoAlloc lifo_;
|
||||
jit::JitContext jcx_;
|
||||
jit::TempAllocator alloc_;
|
||||
jit::MacroAssembler masm_;
|
||||
SigSet sigs_;
|
||||
FuncOffsetVector funcEntryOffsets_;
|
||||
FuncIndexVector exportFuncIndices_;
|
||||
FuncIndexMap funcIndexToExport_;
|
||||
UniqueModuleGeneratorData shared_;
|
||||
LifoAlloc lifo_;
|
||||
jit::TempAllocator alloc_;
|
||||
jit::MacroAssembler masm_;
|
||||
Uint32Vector funcEntryOffsets_;
|
||||
Uint32Vector exportFuncIndices_;
|
||||
FuncIndexMap funcIndexToExport_;
|
||||
|
||||
// Parallel compilation
|
||||
bool parallel_;
|
||||
uint32_t outstanding_;
|
||||
Vector<IonCompileTask> tasks_;
|
||||
Vector<IonCompileTask*> freeTasks_;
|
||||
bool parallel_;
|
||||
uint32_t outstanding_;
|
||||
UniqueModuleGeneratorThreadView threadView_;
|
||||
Vector<IonCompileTask> tasks_;
|
||||
Vector<IonCompileTask*> freeTasks_;
|
||||
|
||||
// Assertions
|
||||
DebugOnly<FunctionGenerator*> activeFunc_;
|
||||
DebugOnly<bool> finishedFuncs_;
|
||||
DebugOnly<FunctionGenerator*> activeFunc_;
|
||||
DebugOnly<bool> finishedFuncs_;
|
||||
|
||||
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
|
||||
bool finishOutstandingTask();
|
||||
bool finishTask(IonCompileTask* task);
|
||||
|
||||
|
@ -100,36 +145,40 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
explicit ModuleGenerator(ExclusiveContext* cx);
|
||||
~ModuleGenerator();
|
||||
|
||||
bool init();
|
||||
bool init(UniqueModuleGeneratorData shared);
|
||||
|
||||
CompileArgs args() const { return module_->compileArgs; }
|
||||
jit::MacroAssembler& masm() { return masm_; }
|
||||
const FuncOffsetVector& funcEntryOffsets() const { return funcEntryOffsets_; }
|
||||
|
||||
const LifoSig* newLifoSig(const MallocSig& sig);
|
||||
const Uint32Vector& funcEntryOffsets() const { return funcEntryOffsets_; }
|
||||
|
||||
// Global data:
|
||||
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
|
||||
bool allocateGlobalVar(ValType type, uint32_t* globalDataOffset);
|
||||
|
||||
// Signatures:
|
||||
void initSig(uint32_t sigIndex, Sig&& sig);
|
||||
const DeclaredSig& sig(uint32_t sigIndex) const;
|
||||
|
||||
// Imports:
|
||||
bool declareImport(MallocSig&& sig, uint32_t* index);
|
||||
bool initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset);
|
||||
uint32_t numImports() const;
|
||||
uint32_t importExitGlobalDataOffset(uint32_t index) const;
|
||||
const MallocSig& importSig(uint32_t index) const;
|
||||
const ModuleImportGeneratorData& import(uint32_t index) const;
|
||||
bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
|
||||
|
||||
// Exports:
|
||||
bool declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* exportIndex);
|
||||
bool declareExport(uint32_t funcIndex, uint32_t* exportIndex);
|
||||
uint32_t numExports() const;
|
||||
uint32_t exportFuncIndex(uint32_t index) const;
|
||||
const MallocSig& exportSig(uint32_t index) const;
|
||||
const Sig& exportSig(uint32_t index) const;
|
||||
bool defineExport(uint32_t index, Offsets offsets);
|
||||
|
||||
// Functions:
|
||||
bool initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
|
||||
const DeclaredSig& funcSig(uint32_t funcIndex) const;
|
||||
bool startFunc(PropertyName* name, unsigned line, unsigned column, UniqueBytecode* recycled,
|
||||
FunctionGenerator* fg);
|
||||
bool finishFunc(uint32_t funcIndex, const LifoSig& sig, UniqueBytecode bytecode,
|
||||
unsigned generateTime, FunctionGenerator* fg);
|
||||
bool finishFunc(uint32_t funcIndex, UniqueBytecode bytecode, unsigned generateTime,
|
||||
FunctionGenerator* fg);
|
||||
bool finishFuncs();
|
||||
|
||||
// Function-pointer tables:
|
||||
|
@ -160,6 +209,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
// anything else. After the body is complete, ModuleGenerator::finishFunc must
|
||||
// be called before the FunctionGenerator is destroyed and the next function is
|
||||
// started.
|
||||
|
||||
class MOZ_STACK_CLASS FunctionGenerator
|
||||
{
|
||||
friend class ModuleGenerator;
|
||||
|
|
|
@ -39,30 +39,33 @@ class FunctionCompiler
|
|||
typedef HashMap<size_t, BlockVector, DefaultHasher<uint32_t>, SystemAllocPolicy> UnlabeledBlockMap;
|
||||
typedef Vector<size_t, 4, SystemAllocPolicy> PositionStack;
|
||||
|
||||
const FuncBytecode& func_;
|
||||
Decoder decoder_;
|
||||
size_t nextId_;
|
||||
size_t lastReadCallSite_;
|
||||
ModuleGeneratorThreadView& mg_;
|
||||
const FuncBytecode& func_;
|
||||
Decoder decoder_;
|
||||
size_t nextId_;
|
||||
size_t lastReadCallSite_;
|
||||
|
||||
TempAllocator& alloc_;
|
||||
MIRGraph& graph_;
|
||||
const CompileInfo& info_;
|
||||
MIRGenerator& mirGen_;
|
||||
TempAllocator& alloc_;
|
||||
MIRGraph& graph_;
|
||||
const CompileInfo& info_;
|
||||
MIRGenerator& mirGen_;
|
||||
|
||||
MBasicBlock* curBlock_;
|
||||
MBasicBlock* curBlock_;
|
||||
|
||||
PositionStack loopStack_;
|
||||
PositionStack breakableStack_;
|
||||
UnlabeledBlockMap unlabeledBreaks_;
|
||||
UnlabeledBlockMap unlabeledContinues_;
|
||||
LabeledBlockMap labeledBreaks_;
|
||||
LabeledBlockMap labeledContinues_;
|
||||
PositionStack loopStack_;
|
||||
PositionStack breakableStack_;
|
||||
UnlabeledBlockMap unlabeledBreaks_;
|
||||
UnlabeledBlockMap unlabeledContinues_;
|
||||
LabeledBlockMap labeledBreaks_;
|
||||
LabeledBlockMap labeledContinues_;
|
||||
|
||||
FuncCompileResults& compileResults_;
|
||||
FuncCompileResults& compileResults_;
|
||||
|
||||
public:
|
||||
FunctionCompiler(const FuncBytecode& func, MIRGenerator& mirGen, FuncCompileResults& compileResults)
|
||||
: func_(func),
|
||||
FunctionCompiler(ModuleGeneratorThreadView& mg, const FuncBytecode& func, MIRGenerator& mirGen,
|
||||
FuncCompileResults& compileResults)
|
||||
: mg_(mg),
|
||||
func_(func),
|
||||
decoder_(func.bytecode()),
|
||||
nextId_(0),
|
||||
lastReadCallSite_(0),
|
||||
|
@ -74,9 +77,10 @@ class FunctionCompiler
|
|||
compileResults_(compileResults)
|
||||
{}
|
||||
|
||||
TempAllocator& alloc() const { return alloc_; }
|
||||
MacroAssembler& masm() const { return compileResults_.masm(); }
|
||||
const LifoSig& sig() const { return func_.sig(); }
|
||||
ModuleGeneratorThreadView& mg() const { return mg_; }
|
||||
TempAllocator& alloc() const { return alloc_; }
|
||||
MacroAssembler& masm() const { return compileResults_.masm(); }
|
||||
const Sig& sig() const { return func_.sig(); }
|
||||
|
||||
bool init()
|
||||
{
|
||||
|
@ -90,7 +94,7 @@ class FunctionCompiler
|
|||
|
||||
// Prepare the entry block for MIR generation:
|
||||
|
||||
const LifoSig::ArgVector& args = func_.sig().args();
|
||||
const ValTypeVector& args = func_.sig().args();
|
||||
unsigned firstVarSlot = args.length();
|
||||
|
||||
if (!mirGen_.ensureBallast())
|
||||
|
@ -98,7 +102,7 @@ class FunctionCompiler
|
|||
if (!newBlock(/* pred = */ nullptr, &curBlock_))
|
||||
return false;
|
||||
|
||||
for (ABIArgIter<LifoSig::ArgVector> i(args); !i.done(); i++) {
|
||||
for (ABIArgValTypeIter i(args); !i.done(); i++) {
|
||||
MAsmJSParameter* ins = MAsmJSParameter::New(alloc(), *i, i.mirType());
|
||||
curBlock_->add(ins);
|
||||
curBlock_->initSlot(info().localSlot(i.index()), ins);
|
||||
|
@ -729,12 +733,12 @@ class FunctionCompiler
|
|||
}
|
||||
|
||||
public:
|
||||
bool internalCall(const LifoSig& sig, uint32_t funcIndex, const Call& call, MDefinition** def)
|
||||
bool internalCall(const Sig& sig, uint32_t funcIndex, const Call& call, MDefinition** def)
|
||||
{
|
||||
return callPrivate(MAsmJSCall::Callee(AsmJSInternalCallee(funcIndex)), call, sig.ret(), def);
|
||||
}
|
||||
|
||||
bool funcPtrCall(const LifoSig& sig, uint32_t maskLit, uint32_t globalDataOffset, MDefinition* index,
|
||||
bool funcPtrCall(const Sig& sig, uint32_t maskLit, uint32_t globalDataOffset, MDefinition* index,
|
||||
const Call& call, MDefinition** def)
|
||||
{
|
||||
if (inDeadCode()) {
|
||||
|
@ -1174,7 +1178,6 @@ class FunctionCompiler
|
|||
int32_t readI32() { return decoder_.uncheckedReadI32(); }
|
||||
float readF32() { return decoder_.uncheckedReadF32(); }
|
||||
double readF64() { return decoder_.uncheckedReadF64(); }
|
||||
const LifoSig* readSig() { return decoder_.uncheckedReadSig(); }
|
||||
SimdConstant readI32X4() { return decoder_.uncheckedReadI32X4(); }
|
||||
SimdConstant readF32X4() { return decoder_.uncheckedReadF32X4(); }
|
||||
|
||||
|
@ -1548,7 +1551,7 @@ EmitAtomicsExchange(FunctionCompiler& f, MDefinition** def)
|
|||
}
|
||||
|
||||
static bool
|
||||
EmitCallArgs(FunctionCompiler& f, const LifoSig& sig, FunctionCompiler::Call* call)
|
||||
EmitCallArgs(FunctionCompiler& f, const Sig& sig, FunctionCompiler::Call* call)
|
||||
{
|
||||
f.startCallArgs(call);
|
||||
for (unsigned i = 0; i < sig.args().length(); i++) {
|
||||
|
@ -1573,7 +1576,8 @@ static bool
|
|||
EmitInternalCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
||||
{
|
||||
uint32_t funcIndex = f.readU32();
|
||||
const LifoSig& sig = *f.readSig();
|
||||
|
||||
const Sig& sig = f.mg().funcSig(funcIndex);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()), sig.ret() == ret);
|
||||
|
||||
uint32_t lineno, column;
|
||||
|
@ -1591,8 +1595,9 @@ EmitFuncPtrCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
|||
{
|
||||
uint32_t mask = f.readU32();
|
||||
uint32_t globalDataOffset = f.readU32();
|
||||
uint32_t sigIndex = f.readU32();
|
||||
|
||||
const LifoSig& sig = *f.readSig();
|
||||
const Sig& sig = f.mg().sig(sigIndex);
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()), sig.ret() == ret);
|
||||
|
||||
uint32_t lineno, column;
|
||||
|
@ -1612,19 +1617,20 @@ EmitFuncPtrCall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
|||
static bool
|
||||
EmitFFICall(FunctionCompiler& f, ExprType ret, MDefinition** def)
|
||||
{
|
||||
unsigned globalDataOffset = f.readI32();
|
||||
|
||||
const LifoSig& sig = *f.readSig();
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()), sig.ret() == ret);
|
||||
uint32_t importIndex = f.readU32();
|
||||
|
||||
uint32_t lineno, column;
|
||||
f.readCallLineCol(&lineno, &column);
|
||||
|
||||
const ModuleImportGeneratorData& import = f.mg().import(importIndex);
|
||||
const Sig& sig = *import.sig;
|
||||
MOZ_ASSERT_IF(!IsVoid(sig.ret()), sig.ret() == ret);
|
||||
|
||||
FunctionCompiler::Call call(f, lineno, column);
|
||||
if (!EmitCallArgs(f, sig, &call))
|
||||
return false;
|
||||
|
||||
return f.ffiCall(globalDataOffset, call, ret, def);
|
||||
return f.ffiCall(import.globalDataOffset, call, ret, def);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -2941,7 +2947,7 @@ wasm::IonCompileFunction(IonCompileTask* task)
|
|||
|
||||
// Build MIR graph
|
||||
{
|
||||
FunctionCompiler f(func, mir, results);
|
||||
FunctionCompiler f(task->mg(), func, mir, results);
|
||||
if (!f.init())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
class ModuleGeneratorThreadView;
|
||||
|
||||
typedef Vector<jit::MIRType, 8, SystemAllocPolicy> MIRTypeVector;
|
||||
typedef jit::ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
|
||||
typedef jit::ABIArgIter<ValTypeVector> ABIArgValTypeIter;
|
||||
|
||||
// The FuncCompileResults contains the results of compiling a single function
|
||||
// body, ready to be merged into the whole-module MacroAssembler.
|
||||
class FuncCompileResults
|
||||
|
@ -62,6 +68,7 @@ class IonCompileTask
|
|||
{
|
||||
JSRuntime* const runtime_;
|
||||
const CompileArgs args_;
|
||||
ModuleGeneratorThreadView& mg_;
|
||||
LifoAlloc lifo_;
|
||||
UniqueFuncBytecode func_;
|
||||
mozilla::Maybe<FuncCompileResults> results_;
|
||||
|
@ -70,9 +77,10 @@ class IonCompileTask
|
|||
IonCompileTask& operator=(const IonCompileTask&) = delete;
|
||||
|
||||
public:
|
||||
IonCompileTask(JSRuntime* runtime, CompileArgs args, size_t defaultChunkSize)
|
||||
: runtime_(runtime),
|
||||
IonCompileTask(JSRuntime* rt, CompileArgs args, ModuleGeneratorThreadView& mg, size_t defaultChunkSize)
|
||||
: runtime_(rt),
|
||||
args_(args),
|
||||
mg_(mg),
|
||||
lifo_(defaultChunkSize),
|
||||
func_(nullptr)
|
||||
{}
|
||||
|
@ -85,6 +93,9 @@ class IonCompileTask
|
|||
CompileArgs args() const {
|
||||
return args_;
|
||||
}
|
||||
ModuleGeneratorThreadView& mg() const {
|
||||
return mg_;
|
||||
}
|
||||
void init(UniqueFuncBytecode func) {
|
||||
MOZ_ASSERT(!func_);
|
||||
func_ = mozilla::Move(func);
|
||||
|
|
|
@ -243,14 +243,14 @@ StaticLinkData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
|||
}
|
||||
|
||||
static size_t
|
||||
SerializedSigSize(const MallocSig& sig)
|
||||
SerializedSigSize(const Sig& sig)
|
||||
{
|
||||
return sizeof(ExprType) +
|
||||
SerializedPodVectorSize(sig.args());
|
||||
}
|
||||
|
||||
static uint8_t*
|
||||
SerializeSig(uint8_t* cursor, const MallocSig& sig)
|
||||
SerializeSig(uint8_t* cursor, const Sig& sig)
|
||||
{
|
||||
cursor = WriteScalar<ExprType>(cursor, sig.ret());
|
||||
cursor = SerializePodVector(cursor, sig.args());
|
||||
|
@ -258,33 +258,22 @@ SerializeSig(uint8_t* cursor, const MallocSig& sig)
|
|||
}
|
||||
|
||||
static const uint8_t*
|
||||
DeserializeSig(ExclusiveContext* cx, const uint8_t* cursor, MallocSig* sig)
|
||||
DeserializeSig(ExclusiveContext* cx, const uint8_t* cursor, Sig* sig)
|
||||
{
|
||||
ExprType ret;
|
||||
cursor = ReadScalar<ExprType>(cursor, &ret);
|
||||
|
||||
MallocSig::ArgVector args;
|
||||
ValTypeVector args;
|
||||
cursor = DeserializePodVector(cx, cursor, &args);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
sig->init(Move(args), ret);
|
||||
*sig = Sig(Move(args), ret);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static bool
|
||||
CloneSig(JSContext* cx, const MallocSig& sig, MallocSig* out)
|
||||
{
|
||||
MallocSig::ArgVector args;
|
||||
if (!ClonePodVector(cx, sig.args(), &args))
|
||||
return false;
|
||||
|
||||
out->init(Move(args), sig.ret());
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t
|
||||
SizeOfSigExcludingThis(const MallocSig& sig, MallocSizeOf mallocSizeOf)
|
||||
SizeOfSigExcludingThis(const Sig& sig, MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
return sig.args().sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
@ -316,7 +305,7 @@ bool
|
|||
Export::clone(JSContext* cx, Export* out) const
|
||||
{
|
||||
out->pod = pod;
|
||||
return CloneSig(cx, sig_, &out->sig_);
|
||||
return out->sig_.clone(sig_);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -352,7 +341,7 @@ bool
|
|||
Import::clone(JSContext* cx, Import* out) const
|
||||
{
|
||||
out->pod = pod;
|
||||
return CloneSig(cx, sig_, &out->sig_);
|
||||
return out->sig_.clone(sig_);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
@ -103,14 +103,14 @@ typedef UniquePtr<StaticLinkData> UniqueStaticLinkData;
|
|||
|
||||
class Export
|
||||
{
|
||||
MallocSig sig_;
|
||||
Sig sig_;
|
||||
struct CacheablePod {
|
||||
uint32_t stubOffset_;
|
||||
} pod;
|
||||
|
||||
public:
|
||||
Export() = default;
|
||||
explicit Export(MallocSig&& sig)
|
||||
explicit Export(Sig&& sig)
|
||||
: sig_(Move(sig))
|
||||
{
|
||||
pod.stubOffset_ = UINT32_MAX;
|
||||
|
@ -128,7 +128,7 @@ class Export
|
|||
uint32_t stubOffset() const {
|
||||
return pod.stubOffset_;
|
||||
}
|
||||
const MallocSig& sig() const {
|
||||
const Sig& sig() const {
|
||||
return sig_;
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ typedef Vector<Export, 0, SystemAllocPolicy> ExportVector;
|
|||
|
||||
class Import
|
||||
{
|
||||
MallocSig sig_;
|
||||
Sig sig_;
|
||||
struct CacheablePod {
|
||||
uint32_t exitGlobalDataOffset_;
|
||||
uint32_t interpExitCodeOffset_;
|
||||
|
@ -153,7 +153,7 @@ class Import
|
|||
public:
|
||||
Import() {}
|
||||
Import(Import&& rhs) : sig_(Move(rhs.sig_)), pod(rhs.pod) {}
|
||||
Import(MallocSig&& sig, uint32_t exitGlobalDataOffset)
|
||||
Import(Sig&& sig, uint32_t exitGlobalDataOffset)
|
||||
: sig_(Move(sig))
|
||||
{
|
||||
pod.exitGlobalDataOffset_ = exitGlobalDataOffset;
|
||||
|
@ -170,7 +170,7 @@ class Import
|
|||
pod.jitExitCodeOffset_ = off;
|
||||
}
|
||||
|
||||
const MallocSig& sig() const {
|
||||
const Sig& sig() const {
|
||||
return sig_;
|
||||
}
|
||||
uint32_t exitGlobalDataOffset() const {
|
||||
|
|
|
@ -30,10 +30,6 @@ using namespace js::wasm;
|
|||
using mozilla::ArrayLength;
|
||||
using mozilla::MakeEnumeratedRange;
|
||||
|
||||
typedef Vector<MIRType, 8, SystemAllocPolicy> MIRTypeVector;
|
||||
typedef ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
|
||||
typedef ABIArgIter<MallocSig::ArgVector> ABIArgValTypeIter;
|
||||
|
||||
static void
|
||||
AssertStackAlignment(MacroAssembler& masm, uint32_t alignment, uint32_t addBeforeAssert = 0)
|
||||
{
|
||||
|
@ -102,7 +98,7 @@ static bool
|
|||
GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, bool usesHeap)
|
||||
{
|
||||
MacroAssembler& masm = mg.masm();
|
||||
const MallocSig& sig = mg.exportSig(exportIndex);
|
||||
const Sig& sig = mg.exportSig(exportIndex);
|
||||
|
||||
masm.haltingAlign(CodeAlignment);
|
||||
|
||||
|
@ -293,7 +289,7 @@ GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, bool usesHeap)
|
|||
}
|
||||
|
||||
static void
|
||||
FillArgumentArray(MacroAssembler& masm, const MallocSig::ArgVector& args, unsigned argOffset,
|
||||
FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argOffset,
|
||||
unsigned offsetToCallerStackArgs, Register scratch)
|
||||
{
|
||||
for (ABIArgValTypeIter i(args); !i.done(); i++) {
|
||||
|
@ -340,7 +336,7 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, Label* throwLa
|
|||
ProfilingOffsets* offsets)
|
||||
{
|
||||
MacroAssembler& masm = mg.masm();
|
||||
const MallocSig& sig = mg.importSig(importIndex);
|
||||
const Sig& sig = *mg.import(importIndex).sig;
|
||||
|
||||
masm.setFramePushed(0);
|
||||
|
||||
|
@ -445,7 +441,7 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, bool usesHeap,
|
|||
Label* throwLabel, ProfilingOffsets* offsets)
|
||||
{
|
||||
MacroAssembler& masm = mg.masm();
|
||||
const MallocSig& sig = mg.importSig(importIndex);
|
||||
const Sig& sig = *mg.import(importIndex).sig;
|
||||
|
||||
masm.setFramePushed(0);
|
||||
|
||||
|
@ -475,7 +471,7 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, bool usesHeap,
|
|||
Register scratch = ABIArgGenerator::NonArgReturnReg1; // repeatedly clobbered
|
||||
|
||||
// 2.1. Get ExitDatum
|
||||
unsigned globalDataOffset = mg.importExitGlobalDataOffset(importIndex);
|
||||
unsigned globalDataOffset = mg.import(importIndex).globalDataOffset;
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
|
||||
#elif defined(JS_CODEGEN_X86)
|
||||
|
|
|
@ -57,6 +57,8 @@ enum class ValType
|
|||
B32x4
|
||||
};
|
||||
|
||||
typedef Vector<ValType, 8, SystemAllocPolicy> ValTypeVector;
|
||||
|
||||
static inline bool
|
||||
IsSimdType(ValType vt)
|
||||
{
|
||||
|
@ -195,30 +197,32 @@ ToMIRType(ExprType et)
|
|||
// duration of module validation+compilation). Thus, long-lived objects like
|
||||
// WasmModule must use malloced allocation.
|
||||
|
||||
template <class AllocPolicy>
|
||||
class Sig
|
||||
{
|
||||
public:
|
||||
typedef Vector<ValType, 4, AllocPolicy> ArgVector;
|
||||
|
||||
private:
|
||||
ArgVector args_;
|
||||
ValTypeVector args_;
|
||||
ExprType ret_;
|
||||
|
||||
protected:
|
||||
explicit Sig(AllocPolicy alloc = AllocPolicy()) : args_(alloc) {}
|
||||
Sig(Sig&& rhs) : args_(Move(rhs.args_)), ret_(rhs.ret_) {}
|
||||
Sig(ArgVector&& args, ExprType ret) : args_(Move(args)), ret_(ret) {}
|
||||
Sig(const Sig&) = delete;
|
||||
Sig& operator=(const Sig&) = delete;
|
||||
|
||||
public:
|
||||
void init(ArgVector&& args, ExprType ret) {
|
||||
Sig() : args_(), ret_(ExprType::Void) {}
|
||||
Sig(Sig&& rhs) : args_(Move(rhs.args_)), ret_(rhs.ret_) {}
|
||||
Sig(ValTypeVector&& args, ExprType ret) : args_(Move(args)), ret_(ret) {}
|
||||
|
||||
bool clone(const Sig& rhs) {
|
||||
ret_ = rhs.ret_;
|
||||
MOZ_ASSERT(args_.empty());
|
||||
args_ = Move(args);
|
||||
ret_ = ret;
|
||||
return args_.appendAll(rhs.args_);
|
||||
}
|
||||
Sig& operator=(Sig&& rhs) {
|
||||
ret_ = rhs.ret_;
|
||||
args_ = Move(rhs.args_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValType arg(unsigned i) const { return args_[i]; }
|
||||
const ArgVector& args() const { return args_; }
|
||||
const ValTypeVector& args() const { return args_; }
|
||||
const ExprType& ret() const { return ret_; }
|
||||
|
||||
HashNumber hash() const {
|
||||
|
@ -227,9 +231,7 @@ class Sig
|
|||
hn = mozilla::AddToHash(hn, HashNumber(args_[i]));
|
||||
return hn;
|
||||
}
|
||||
|
||||
template <class AllocPolicy2>
|
||||
bool operator==(const Sig<AllocPolicy2>& rhs) const {
|
||||
bool operator==(const Sig& rhs) const {
|
||||
if (ret() != rhs.ret())
|
||||
return false;
|
||||
if (args().length() != rhs.args().length())
|
||||
|
@ -240,39 +242,27 @@ class Sig
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class AllocPolicy2>
|
||||
bool operator!=(const Sig<AllocPolicy2>& rhs) const {
|
||||
bool operator!=(const Sig& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
class MallocSig : public Sig<SystemAllocPolicy>
|
||||
{
|
||||
typedef Sig<SystemAllocPolicy> BaseSig;
|
||||
// A "declared" signature is a Sig object that is created and owned by the
|
||||
// ModuleGenerator. These signature objects are read-only and have the same
|
||||
// lifetime as the ModuleGenerator. This type is useful since some uses of Sig
|
||||
// need this extended lifetime and want to statically distinguish from the
|
||||
// common stack-allocated Sig objects that get passed around.
|
||||
|
||||
public:
|
||||
MallocSig() = default;
|
||||
MallocSig(MallocSig&& rhs) : BaseSig(Move(rhs)) {}
|
||||
MallocSig(ArgVector&& args, ExprType ret) : BaseSig(Move(args), ret) {}
|
||||
struct DeclaredSig : Sig
|
||||
{
|
||||
DeclaredSig() = default;
|
||||
DeclaredSig(DeclaredSig&& rhs) : Sig(Move(rhs)) {}
|
||||
explicit DeclaredSig(Sig&& sig) : Sig(Move(sig)) {}
|
||||
void operator=(Sig&& rhs) { Sig& base = *this; base = Move(rhs); }
|
||||
};
|
||||
|
||||
class LifoSig : public Sig<LifoAllocPolicy<Fallible>>
|
||||
{
|
||||
typedef Sig<LifoAllocPolicy<Fallible>> BaseSig;
|
||||
LifoSig(ArgVector&& args, ExprType ret) : BaseSig(Move(args), ret) {}
|
||||
|
||||
public:
|
||||
static LifoSig* new_(LifoAlloc& lifo, const MallocSig& src) {
|
||||
void* mem = lifo.alloc(sizeof(LifoSig));
|
||||
if (!mem)
|
||||
return nullptr;
|
||||
ArgVector args(lifo);
|
||||
if (!args.appendAll(src.args()))
|
||||
return nullptr;
|
||||
return new (mem) LifoSig(Move(args), src.ret());
|
||||
}
|
||||
};
|
||||
typedef Vector<DeclaredSig, 0, SystemAllocPolicy> DeclaredSigVector;
|
||||
typedef Vector<const DeclaredSig*, 0, SystemAllocPolicy> DeclaredSigPtrVector;
|
||||
|
||||
// The (,Profiling,Func)Offsets classes are used to record the offsets of
|
||||
// different key points in a CodeRange during compilation.
|
||||
|
|
Загрузка…
Ссылка в новой задаче