Bug 1239177 - Odin: make calls more like wasm (r=bbouvier)

--HG--
extra : commitid : 55SogGEwGDh
extra : rebase_source : b37071da6504fe8418d9c1fcd8f34a17d0d453d7
This commit is contained in:
Luke Wagner 2016-01-12 22:12:07 -06:00
Родитель dcfa1c7611
Коммит 0a5366fd58
10 изменённых файлов: 446 добавлений и 386 удалений

Просмотреть файл

@ -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.