зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1459900 - Struct types: read, write, validate. r=luke
We introduce a simple "struct" type definition for Wasm. A struct has fields of primitive types, including anyref, but no other information, notably no information about subtype relationships. The syntax is: (type $tname (struct (field $fname i32) ...)) where the $fnames are currently ignored. (In the future, the $fnames will denote the field numbers of their fields within the structure and will be used by the struct.get and struct.set instructions in the text format. If any $fname is bound in multiple structures the bindings must resolve to the same field number and field type.) To record the type information there is a new StructType type in WasmTypes.h. We generalize the SigWithId table in ModuleEnvironment to instead be a TypeDef table, where a TypeDef is a tagged union of SigWithId and StructType. Similarly, there is a new AstTypeDef base class for AstSig and AstStruct, and the sigs_ table in AstModule becomes a types_ table. When the ModuleEnvironment is about to be destroyed we move the StructType types into a dense structTypes_ table in the Module; a later patch will make use of these types. The structTypes_ get serialized and deserialized with the module. --HG-- extra : rebase_source : 62458ece9793c58fc1b813262e605916477c9954
This commit is contained in:
Родитель
3f9f7d8191
Коммит
50a17eeb52
|
@ -281,8 +281,8 @@ const v2vSigSection = sigSection([v2vSig]);
|
|||
const i2vSig = {args:[I32Code], ret:VoidCode};
|
||||
const v2vBody = funcBody({locals:[], body:[]});
|
||||
|
||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: U32MAX_LEB } ])), CompileError, /too many signatures/);
|
||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: [1, 0], } ])), CompileError, /expected function form/);
|
||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: U32MAX_LEB } ])), CompileError, /too many types/);
|
||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: [1, 0], } ])), CompileError, /expected type form/);
|
||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: [1, FuncCode, ...U32MAX_LEB], } ])), CompileError, /too many arguments in signature/);
|
||||
|
||||
assertThrowsInstanceOf(() => wasmEval(moduleWithSections([{name: typeId, body: [1]}])), CompileError);
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
if (!wasmGcEnabled()) {
|
||||
assertErrorMessage(() => wasmEvalText(`(module (type $s (struct)))`),
|
||||
WebAssembly.CompileError, /Structure types not enabled/);
|
||||
quit();
|
||||
}
|
||||
|
||||
var bin = wasmTextToBinary(
|
||||
`(module
|
||||
|
||||
(table 2 anyfunc)
|
||||
(elem (i32.const 0) $doit $doitagain)
|
||||
|
||||
;; Type array has a mix of types
|
||||
|
||||
(type $f1 (func (param i32) (result i32)))
|
||||
|
||||
(type $point (struct
|
||||
(field $point_x i32)
|
||||
(field $point_y i32)))
|
||||
|
||||
(type $f2 (func (param f64) (result f64)))
|
||||
|
||||
(type $int_node (struct
|
||||
(field $intbox_val (mut i32))
|
||||
(field $intbox_next (mut anyref))))
|
||||
|
||||
;; Test all the types.
|
||||
|
||||
(type $omni (struct
|
||||
(field $omni_i32 i32)
|
||||
(field $omni_i32m (mut i32))
|
||||
(field $omni_i64 i64)
|
||||
(field $omni_i64m (mut i64))
|
||||
(field $omni_f32 f32)
|
||||
(field $omni_f32m (mut f32))
|
||||
(field $omni_f64 f64)
|
||||
(field $omni_f64m (mut f64))
|
||||
(field $omni_anyref anyref)
|
||||
(field $omni_anyrefm (mut anyref))))
|
||||
|
||||
;; Various ways to reference a type in the middle of the
|
||||
;; type array, make sure we get the right one
|
||||
|
||||
(func $x1 (import "m" "x1") (type $f1))
|
||||
(func $x2 (import "m" "x2") (type $f2))
|
||||
|
||||
(func (export "hello") (param f64) (param i32) (result f64)
|
||||
(call_indirect $f2 (get_local 0) (get_local 1)))
|
||||
|
||||
(func $doit (param f64) (result f64)
|
||||
(f64.sqrt (get_local 0)))
|
||||
|
||||
(func $doitagain (param f64) (result f64)
|
||||
(f64.mul (get_local 0) (get_local 0)))
|
||||
|
||||
(func (export "x1") (param i32) (result i32)
|
||||
(call $x1 (get_local 0)))
|
||||
|
||||
(func (export "x2") (param f64) (result f64)
|
||||
(call $x2 (get_local 0)))
|
||||
)`)
|
||||
|
||||
var mod = new WebAssembly.Module(bin);
|
||||
var ins = new WebAssembly.Instance(mod, {m:{x1(x){ return x*3 }, x2(x){ return Math.PI }}}).exports;
|
||||
|
||||
assertEq(ins.hello(4.0, 0), 2.0)
|
||||
assertEq(ins.hello(4.0, 1), 16.0)
|
||||
|
||||
assertEq(ins.x1(12), 36)
|
||||
assertEq(ins.x2(8), Math.PI)
|
||||
|
||||
// Crude but at least checks that we have *something*.
|
||||
|
||||
var txt = wasmBinaryToText(bin);
|
||||
var re = /\(type\s+\$[a-z0-9]+\s+\(struct/gm;
|
||||
assertEq(Array.isArray(re.exec(txt)), true);
|
||||
assertEq(Array.isArray(re.exec(txt)), true);
|
||||
assertEq(Array.isArray(re.exec(txt)), true);
|
||||
assertEq(Array.isArray(re.exec(txt)), false);
|
||||
|
||||
// The field name is optional, so this should work.
|
||||
|
||||
wasmEvalText(`
|
||||
(module
|
||||
(type $s (struct (field i32))))
|
||||
`)
|
||||
|
||||
// Empty structs are OK.
|
||||
|
||||
wasmEvalText(`
|
||||
(module
|
||||
(type $s (struct)))
|
||||
`)
|
||||
|
||||
// Bogus type definition syntax.
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`
|
||||
(module
|
||||
(type $s))
|
||||
`),
|
||||
SyntaxError, /parsing wasm text/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`
|
||||
(module
|
||||
(type $s (field $x i32)))
|
||||
`),
|
||||
SyntaxError, /bad type definition/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`
|
||||
(module
|
||||
(type $s (struct (field $x i31))))
|
||||
`),
|
||||
SyntaxError, /parsing wasm text/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`
|
||||
(module
|
||||
(type $s (struct (fjeld $x i32))))
|
||||
`),
|
||||
SyntaxError, /parsing wasm text/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`
|
||||
(module
|
||||
(type $s (struct abracadabra)))
|
||||
`),
|
||||
SyntaxError, /parsing wasm text/);
|
||||
|
||||
// Function should not reference struct type: syntactic test
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`
|
||||
(module
|
||||
(type $s (struct))
|
||||
(type $f (func (param i32) (result i32)))
|
||||
(func (type 0) (param i32) (result i32) (unreachable)))
|
||||
`),
|
||||
WebAssembly.CompileError, /signature index references non-signature/);
|
||||
|
||||
// Function should not reference struct type: binary test
|
||||
|
||||
var bad = new Uint8Array([0x00, 0x61, 0x73, 0x6d,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
|
||||
0x01, // Type section
|
||||
0x03, // Section size
|
||||
0x01, // One type
|
||||
0x50, // Struct
|
||||
0x00, // Zero fields
|
||||
|
||||
0x03, // Function section
|
||||
0x02, // Section size
|
||||
0x01, // One function
|
||||
0x00, // Type of function
|
||||
|
||||
0x0a, // Code section
|
||||
0x05, // Section size
|
||||
0x01, // One body
|
||||
0x03, // Body size
|
||||
0x00, // Zero locals
|
||||
0x00, // UNREACHABLE
|
||||
0x0b]); // END
|
||||
|
||||
assertErrorMessage(() => new WebAssembly.Module(bad),
|
||||
WebAssembly.CompileError, /signature index references non-signature/);
|
|
@ -1638,17 +1638,17 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
|||
class HashableSig
|
||||
{
|
||||
uint32_t sigIndex_;
|
||||
const SigWithIdVector& sigs_;
|
||||
const TypeDefVector& types_;
|
||||
|
||||
public:
|
||||
HashableSig(uint32_t sigIndex, const SigWithIdVector& sigs)
|
||||
: sigIndex_(sigIndex), sigs_(sigs)
|
||||
HashableSig(uint32_t sigIndex, const TypeDefVector& types)
|
||||
: sigIndex_(sigIndex), types_(types)
|
||||
{}
|
||||
uint32_t sigIndex() const {
|
||||
return sigIndex_;
|
||||
}
|
||||
const Sig& sig() const {
|
||||
return sigs_[sigIndex_];
|
||||
return types_[sigIndex_].funcType();
|
||||
}
|
||||
|
||||
// Implement HashPolicy:
|
||||
|
@ -1666,8 +1666,8 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
|||
PropertyName* name_;
|
||||
|
||||
public:
|
||||
NamedSig(PropertyName* name, uint32_t sigIndex, const SigWithIdVector& sigs)
|
||||
: HashableSig(sigIndex, sigs), name_(name)
|
||||
NamedSig(PropertyName* name, uint32_t sigIndex, const TypeDefVector& types)
|
||||
: HashableSig(sigIndex, types), name_(name)
|
||||
{}
|
||||
PropertyName* name() const {
|
||||
return name_;
|
||||
|
@ -1755,22 +1755,22 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
|||
return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
|
||||
}
|
||||
bool newSig(Sig&& sig, uint32_t* sigIndex) {
|
||||
if (env_.sigs.length() >= MaxTypes)
|
||||
if (env_.types.length() >= MaxTypes)
|
||||
return failCurrentOffset("too many signatures");
|
||||
|
||||
*sigIndex = env_.sigs.length();
|
||||
return env_.sigs.append(std::move(sig));
|
||||
*sigIndex = env_.types.length();
|
||||
return env_.types.append(std::move(sig));
|
||||
}
|
||||
bool declareSig(Sig&& sig, uint32_t* sigIndex) {
|
||||
SigSet::AddPtr p = sigSet_.lookupForAdd(sig);
|
||||
if (p) {
|
||||
*sigIndex = p->sigIndex();
|
||||
MOZ_ASSERT(env_.sigs[*sigIndex] == sig);
|
||||
MOZ_ASSERT(env_.types[*sigIndex].funcType() == sig);
|
||||
return true;
|
||||
}
|
||||
|
||||
return newSig(std::move(sig), sigIndex) &&
|
||||
sigSet_.add(p, HashableSig(*sigIndex, env_.sigs));
|
||||
sigSet_.add(p, HashableSig(*sigIndex, env_.types));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -2308,7 +2308,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
|||
if (!declareSig(std::move(sig), &sigIndex))
|
||||
return false;
|
||||
|
||||
return funcImportMap_.add(p, NamedSig(name, sigIndex, env_.sigs), *importIndex);
|
||||
return funcImportMap_.add(p, NamedSig(name, sigIndex, env_.types), *importIndex);
|
||||
}
|
||||
|
||||
bool tryConstantAccess(uint64_t start, uint64_t width) {
|
||||
|
@ -2457,12 +2457,12 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
|||
for (FuncImportMap::Range r = funcImportMap_.all(); !r.empty(); r.popFront()) {
|
||||
uint32_t funcIndex = r.front().value();
|
||||
MOZ_ASSERT(!env_.funcSigs[funcIndex]);
|
||||
env_.funcSigs[funcIndex] = &env_.sigs[r.front().key().sigIndex()];
|
||||
env_.funcSigs[funcIndex] = &env_.types[r.front().key().sigIndex()].funcType();
|
||||
}
|
||||
for (const Func& func : funcDefs_) {
|
||||
uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
|
||||
MOZ_ASSERT(!env_.funcSigs[funcIndex]);
|
||||
env_.funcSigs[funcIndex] = &env_.sigs[func.sigIndex()];
|
||||
env_.funcSigs[funcIndex] = &env_.types[func.sigIndex()].funcType();
|
||||
}
|
||||
|
||||
if (!env_.funcImportGlobalDataOffsets.resize(funcImportMap_.count()))
|
||||
|
@ -4893,7 +4893,7 @@ CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, Property
|
|||
return m.addFuncDef(name, usepn->pn_pos.begin, std::move(sig), func);
|
||||
}
|
||||
|
||||
const SigWithId& existingSig = m.env().sigs[existing->sigIndex()];
|
||||
const SigWithId& existingSig = m.env().types[existing->sigIndex()].funcType();
|
||||
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, existingSig))
|
||||
return false;
|
||||
|
@ -4951,7 +4951,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, m.env().sigs[table.sigIndex()]))
|
||||
if (!CheckSignatureAgainstExisting(m, usepn, sig, m.env().types[table.sigIndex()].funcType()))
|
||||
return false;
|
||||
|
||||
*tableIndex = existing->tableIndex();
|
||||
|
@ -7376,7 +7376,7 @@ 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.env().sigs[func->sigIndex()];
|
||||
const Sig& funcSig = m.env().types[func->sigIndex()].funcType();
|
||||
if (sig) {
|
||||
if (*sig != funcSig)
|
||||
return m.fail(elem, "all functions in table must have same signature");
|
||||
|
|
|
@ -126,7 +126,29 @@ struct AstBase
|
|||
}
|
||||
};
|
||||
|
||||
class AstSig : public AstBase
|
||||
class AstSig;
|
||||
class AstStruct;
|
||||
|
||||
class AstTypeDef : public AstBase
|
||||
{
|
||||
protected:
|
||||
enum class Which { IsSig, IsStruct };
|
||||
|
||||
private:
|
||||
Which which_;
|
||||
|
||||
public:
|
||||
explicit AstTypeDef(Which which) : which_(which) {}
|
||||
|
||||
bool isSig() const { return which_ == Which::IsSig; }
|
||||
bool isStruct() const { return which_ == Which::IsStruct; }
|
||||
inline AstSig& asSig();
|
||||
inline AstStruct& asStruct();
|
||||
inline const AstSig& asSig() const;
|
||||
inline const AstStruct& asStruct() const;
|
||||
};
|
||||
|
||||
class AstSig : public AstTypeDef
|
||||
{
|
||||
AstName name_;
|
||||
AstValTypeVector args_;
|
||||
|
@ -134,15 +156,18 @@ class AstSig : public AstBase
|
|||
|
||||
public:
|
||||
explicit AstSig(LifoAlloc& lifo)
|
||||
: args_(lifo),
|
||||
: AstTypeDef(Which::IsSig),
|
||||
args_(lifo),
|
||||
ret_(ExprType::Void)
|
||||
{}
|
||||
AstSig(AstValTypeVector&& args, ExprType ret)
|
||||
: args_(std::move(args)),
|
||||
: AstTypeDef(Which::IsSig),
|
||||
args_(std::move(args)),
|
||||
ret_(ret)
|
||||
{}
|
||||
AstSig(AstName name, AstSig&& rhs)
|
||||
: name_(name),
|
||||
: AstTypeDef(Which::IsSig),
|
||||
name_(name),
|
||||
args_(std::move(rhs.args_)),
|
||||
ret_(rhs.ret_)
|
||||
{}
|
||||
|
@ -171,6 +196,68 @@ class AstSig : public AstBase
|
|||
}
|
||||
};
|
||||
|
||||
class AstStruct : public AstTypeDef
|
||||
{
|
||||
AstName name_;
|
||||
AstNameVector fieldNames_;
|
||||
AstValTypeVector fieldTypes_;
|
||||
|
||||
public:
|
||||
explicit AstStruct(LifoAlloc& lifo)
|
||||
: AstTypeDef(Which::IsStruct),
|
||||
fieldNames_(lifo),
|
||||
fieldTypes_(lifo)
|
||||
{}
|
||||
AstStruct(AstNameVector&& names, AstValTypeVector&& types)
|
||||
: AstTypeDef(Which::IsStruct),
|
||||
fieldNames_(std::move(names)),
|
||||
fieldTypes_(std::move(types))
|
||||
{}
|
||||
AstStruct(AstName name, AstStruct&& rhs)
|
||||
: AstTypeDef(Which::IsStruct),
|
||||
name_(name),
|
||||
fieldNames_(std::move(rhs.fieldNames_)),
|
||||
fieldTypes_(std::move(rhs.fieldTypes_))
|
||||
{}
|
||||
AstName name() const {
|
||||
return name_;
|
||||
}
|
||||
const AstNameVector& fieldNames() const {
|
||||
return fieldNames_;
|
||||
}
|
||||
const AstValTypeVector& fieldTypes() const {
|
||||
return fieldTypes_;
|
||||
}
|
||||
};
|
||||
|
||||
inline AstSig&
|
||||
AstTypeDef::asSig()
|
||||
{
|
||||
MOZ_ASSERT(isSig());
|
||||
return *static_cast<AstSig*>(this);
|
||||
}
|
||||
|
||||
inline AstStruct&
|
||||
AstTypeDef::asStruct()
|
||||
{
|
||||
MOZ_ASSERT(isStruct());
|
||||
return *static_cast<AstStruct*>(this);
|
||||
}
|
||||
|
||||
inline const AstSig&
|
||||
AstTypeDef::asSig() const
|
||||
{
|
||||
MOZ_ASSERT(isSig());
|
||||
return *static_cast<const AstSig*>(this);
|
||||
}
|
||||
|
||||
inline const AstStruct&
|
||||
AstTypeDef::asStruct() const
|
||||
{
|
||||
MOZ_ASSERT(isStruct());
|
||||
return *static_cast<const AstStruct*>(this);
|
||||
}
|
||||
|
||||
const uint32_t AstNodeUnknownOffset = 0;
|
||||
|
||||
class AstNode : public AstBase
|
||||
|
@ -948,7 +1035,7 @@ class AstModule : public AstNode
|
|||
typedef AstVector<AstFunc*> FuncVector;
|
||||
typedef AstVector<AstImport*> ImportVector;
|
||||
typedef AstVector<AstExport*> ExportVector;
|
||||
typedef AstVector<AstSig*> SigVector;
|
||||
typedef AstVector<AstTypeDef*> TypeDefVector;
|
||||
typedef AstVector<AstName> NameVector;
|
||||
typedef AstVector<AstResizable> AstResizableVector;
|
||||
|
||||
|
@ -956,7 +1043,7 @@ class AstModule : public AstNode
|
|||
typedef AstHashMap<AstSig*, uint32_t, AstSig> SigMap;
|
||||
|
||||
LifoAlloc& lifo_;
|
||||
SigVector sigs_;
|
||||
TypeDefVector types_;
|
||||
SigMap sigMap_;
|
||||
ImportVector imports_;
|
||||
NameVector funcImportNames_;
|
||||
|
@ -974,7 +1061,7 @@ class AstModule : public AstNode
|
|||
public:
|
||||
explicit AstModule(LifoAlloc& lifo)
|
||||
: lifo_(lifo),
|
||||
sigs_(lifo),
|
||||
types_(lifo),
|
||||
sigMap_(lifo),
|
||||
imports_(lifo),
|
||||
funcImportNames_(lifo),
|
||||
|
@ -1038,21 +1125,21 @@ class AstModule : public AstNode
|
|||
*sigIndex = p->value();
|
||||
return true;
|
||||
}
|
||||
*sigIndex = sigs_.length();
|
||||
*sigIndex = types_.length();
|
||||
auto* lifoSig = new (lifo_) AstSig(AstName(), std::move(sig));
|
||||
return lifoSig &&
|
||||
sigs_.append(lifoSig) &&
|
||||
sigMap_.add(p, sigs_.back(), *sigIndex);
|
||||
types_.append(lifoSig) &&
|
||||
sigMap_.add(p, static_cast<AstSig*>(types_.back()), *sigIndex);
|
||||
}
|
||||
bool append(AstSig* sig) {
|
||||
uint32_t sigIndex = sigs_.length();
|
||||
if (!sigs_.append(sig))
|
||||
uint32_t sigIndex = types_.length();
|
||||
if (!types_.append(sig))
|
||||
return false;
|
||||
SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
|
||||
return p || sigMap_.add(p, sig, sigIndex);
|
||||
}
|
||||
const SigVector& sigs() const {
|
||||
return sigs_;
|
||||
const TypeDefVector& types() const {
|
||||
return types_;
|
||||
}
|
||||
bool append(AstFunc* func) {
|
||||
return funcs_.append(func);
|
||||
|
@ -1060,6 +1147,9 @@ class AstModule : public AstNode
|
|||
const FuncVector& funcs() const {
|
||||
return funcs_;
|
||||
}
|
||||
bool append(AstStruct* str) {
|
||||
return types_.append(str);
|
||||
}
|
||||
bool append(AstImport* imp) {
|
||||
switch (imp->kind()) {
|
||||
case DefinitionKind::Function:
|
||||
|
|
|
@ -3762,7 +3762,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
|||
|
||||
void callIndirect(uint32_t sigIndex, const Stk& indexVal, const FunctionCall& call)
|
||||
{
|
||||
const SigWithId& sig = env_.sigs[sigIndex];
|
||||
const SigWithId& sig = env_.types[sigIndex].funcType();
|
||||
MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None);
|
||||
|
||||
MOZ_ASSERT(env_.tables.length() == 1);
|
||||
|
@ -7861,7 +7861,7 @@ BaseCompiler::emitCallIndirect()
|
|||
|
||||
sync();
|
||||
|
||||
const SigWithId& sig = env_.sigs[sigIndex];
|
||||
const SigWithId& sig = env_.types[sigIndex].funcType();
|
||||
|
||||
// Stack: ... arg1 .. argn callee
|
||||
|
||||
|
@ -8830,6 +8830,9 @@ BaseCompiler::emitInstanceCall(uint32_t lineOrBytecode, const MIRTypeVector& sig
|
|||
|
||||
popValueStackBy(numArgs);
|
||||
|
||||
// Note, a number of clients of emitInstanceCall currently assume that the
|
||||
// following operation does not destroy ReturnReg.
|
||||
|
||||
pushReturnedIfNonVoid(baselineCall, retType);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ enum class TypeCode
|
|||
// Type constructor for function types
|
||||
Func = 0x60, // SLEB128(-0x20)
|
||||
|
||||
// Type constructor for structure types - unofficial
|
||||
Struct = 0x50, // SLEB128(-0x30)
|
||||
|
||||
// Special code representing the block signature ()->()
|
||||
BlockVoid = 0x40, // SLEB128(-0x40)
|
||||
|
||||
|
@ -603,6 +606,7 @@ static const unsigned MaxElemSegments = 10000000;
|
|||
static const unsigned MaxTableMaximumLength = 10000000;
|
||||
static const unsigned MaxLocals = 50000;
|
||||
static const unsigned MaxParams = 1000;
|
||||
static const unsigned MaxStructFields = 1000;
|
||||
static const unsigned MaxMemoryMaximumPages = 65536;
|
||||
static const unsigned MaxStringBytes = 100000;
|
||||
static const unsigned MaxModuleBytes = 1024 * 1024 * 1024;
|
||||
|
|
|
@ -97,12 +97,12 @@ class AstDecodeContext
|
|||
|
||||
public:
|
||||
AstDecodeContext(JSContext* cx, LifoAlloc& lifo, Decoder& d, AstModule& module,
|
||||
bool generateNames)
|
||||
bool generateNames, HasGcTypes hasGcTypes)
|
||||
: cx(cx),
|
||||
lifo(lifo),
|
||||
d(d),
|
||||
generateNames(generateNames),
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
|
||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, hasGcTypes,
|
||||
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()
|
||||
? Shareable::True
|
||||
: Shareable::False),
|
||||
|
@ -351,7 +351,7 @@ AstDecodeCallIndirect(AstDecodeContext& c)
|
|||
if (!GenerateRef(c, AstName(u"type"), sigIndex, &sigRef))
|
||||
return false;
|
||||
|
||||
const SigWithId& sig = c.env().sigs[sigIndex];
|
||||
const SigWithId& sig = c.env().types[sigIndex].funcType();
|
||||
AstExprVector args(c.lifo);
|
||||
if (!AstDecodeCallArgs(c, sig, &args))
|
||||
return false;
|
||||
|
@ -1958,26 +1958,59 @@ AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
|
|||
// wasm decoding and generation
|
||||
|
||||
static bool
|
||||
AstCreateSignatures(AstDecodeContext& c)
|
||||
AstCreateTypes(AstDecodeContext& c)
|
||||
{
|
||||
SigWithIdVector& sigs = c.env().sigs;
|
||||
uint32_t typeIndexForNames = 0;
|
||||
for (const TypeDef& td : c.env().types) {
|
||||
if (td.isFuncType()) {
|
||||
const Sig& sig = td.funcType();
|
||||
|
||||
for (size_t sigIndex = 0; sigIndex < sigs.length(); sigIndex++) {
|
||||
const Sig& sig = sigs[sigIndex];
|
||||
AstValTypeVector args(c.lifo);
|
||||
if (!args.appendAll(sig.args()))
|
||||
return false;
|
||||
|
||||
AstValTypeVector args(c.lifo);
|
||||
if (!args.appendAll(sig.args()))
|
||||
return false;
|
||||
AstSig sigNoName(std::move(args), sig.ret());
|
||||
|
||||
AstSig sigNoName(std::move(args), sig.ret());
|
||||
AstName sigName;
|
||||
if (!GenerateName(c, AstName(u"type"), typeIndexForNames, &sigName))
|
||||
return false;
|
||||
|
||||
AstName sigName;
|
||||
if (!GenerateName(c, AstName(u"type"), sigIndex, &sigName))
|
||||
return false;
|
||||
AstSig* astSig = new(c.lifo) AstSig(sigName, std::move(sigNoName));
|
||||
if (!astSig || !c.module().append(astSig))
|
||||
return false;
|
||||
} else if (td.isStructType()) {
|
||||
const StructType& str = td.structType();
|
||||
|
||||
AstSig* astSig = new(c.lifo) AstSig(sigName, std::move(sigNoName));
|
||||
if (!astSig || !c.module().append(astSig))
|
||||
return false;
|
||||
AstValTypeVector fieldTypes(c.lifo);
|
||||
if (!fieldTypes.appendAll(str.fields_))
|
||||
return false;
|
||||
|
||||
AstNameVector fieldNames(c.lifo);
|
||||
if (!fieldNames.resize(fieldTypes.length()))
|
||||
return false;
|
||||
|
||||
// The multiplication ensures that generated field names are unique
|
||||
// within the module, though the resulting namespace is very sparse.
|
||||
|
||||
for (size_t fieldIndex = 0; fieldIndex < fieldTypes.length(); fieldIndex++) {
|
||||
size_t idx = (typeIndexForNames * MaxStructFields) + fieldIndex;
|
||||
if (!GenerateName(c, AstName(u"f"), idx, &fieldNames[fieldIndex]))
|
||||
return false;
|
||||
}
|
||||
|
||||
AstStruct structNoName(std::move(fieldNames), std::move(fieldTypes));
|
||||
|
||||
AstName structName;
|
||||
if (!GenerateName(c, AstName(u"type"), typeIndexForNames, &structName))
|
||||
return false;
|
||||
|
||||
AstStruct* astStruct = new(c.lifo) AstStruct(structName, std::move(structNoName));
|
||||
if (!astStruct || !c.module().append(astStruct))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
typeIndexForNames++;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -2230,7 +2263,7 @@ AstDecodeEnvironment(AstDecodeContext& c)
|
|||
if (!DecodeModuleEnvironment(c.d, &c.env()))
|
||||
return false;
|
||||
|
||||
if (!AstCreateSignatures(c))
|
||||
if (!AstCreateTypes(c))
|
||||
return false;
|
||||
|
||||
if (!AstCreateImports(c))
|
||||
|
@ -2333,7 +2366,7 @@ wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAllo
|
|||
|
||||
UniqueChars error;
|
||||
Decoder d(bytes, bytes + length, 0, &error, nullptr, /* resilient */ true);
|
||||
AstDecodeContext c(cx, lifo, d, *result, true);
|
||||
AstDecodeContext c(cx, lifo, d, *result, /* generateNames */ true, HasGcTypes::True);
|
||||
|
||||
if (!AstDecodeEnvironment(c) ||
|
||||
!AstDecodeCodeSection(c) ||
|
||||
|
|
|
@ -191,6 +191,7 @@ RenderExprType(WasmRenderContext& c, ExprType type)
|
|||
case ExprType::I64: return c.buffer.append("i64");
|
||||
case ExprType::F32: return c.buffer.append("f32");
|
||||
case ExprType::F64: return c.buffer.append("f64");
|
||||
case ExprType::AnyRef: return c.buffer.append("anyref");
|
||||
default:;
|
||||
}
|
||||
|
||||
|
@ -209,6 +210,12 @@ RenderName(WasmRenderContext& c, const AstName& name)
|
|||
return c.buffer.append(name.begin(), name.end());
|
||||
}
|
||||
|
||||
static bool
|
||||
RenderNonemptyName(WasmRenderContext& c, const AstName& name)
|
||||
{
|
||||
return name.empty() || (RenderName(c, name) && c.buffer.append(' '));
|
||||
}
|
||||
|
||||
static bool
|
||||
RenderRef(WasmRenderContext& c, const AstRef& ref)
|
||||
{
|
||||
|
@ -1481,12 +1488,8 @@ RenderSignature(WasmRenderContext& c, const AstSig& sig, const AstNameVector* ma
|
|||
if (!c.buffer.append(" (param "))
|
||||
return false;
|
||||
const AstName& name = (*maybeLocals)[i];
|
||||
if (!name.empty()) {
|
||||
if (!RenderName(c, name))
|
||||
return false;
|
||||
if (!c.buffer.append(" "))
|
||||
return false;
|
||||
}
|
||||
if (!RenderNonemptyName(c, name))
|
||||
return false;
|
||||
ValType arg = sig.args()[i];
|
||||
if (!RenderValType(c, arg))
|
||||
return false;
|
||||
|
@ -1518,34 +1521,76 @@ RenderSignature(WasmRenderContext& c, const AstSig& sig, const AstNameVector* ma
|
|||
}
|
||||
|
||||
static bool
|
||||
RenderTypeSection(WasmRenderContext& c, const AstModule::SigVector& sigs)
|
||||
RenderFields(WasmRenderContext& c, const AstStruct& str)
|
||||
{
|
||||
uint32_t numSigs = sigs.length();
|
||||
if (!numSigs)
|
||||
return true;
|
||||
const AstNameVector& fieldNames = str.fieldNames();
|
||||
const AstValTypeVector& fieldTypes = str.fieldTypes();
|
||||
|
||||
for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
|
||||
const AstSig* sig = sigs[sigIndex];
|
||||
for (uint32_t fieldIndex = 0; fieldIndex < fieldTypes.length(); fieldIndex++) {
|
||||
if (!c.buffer.append("\n"))
|
||||
return false;
|
||||
if (!RenderIndent(c))
|
||||
return false;
|
||||
if (!c.buffer.append("(type"))
|
||||
if (!c.buffer.append("(field "))
|
||||
return false;
|
||||
if (!sig->name().empty()) {
|
||||
if (!c.buffer.append(" "))
|
||||
return false;
|
||||
if (!RenderName(c, sig->name()))
|
||||
return false;
|
||||
}
|
||||
if (!c.buffer.append(" (func"))
|
||||
if (!RenderNonemptyName(c, fieldNames[fieldIndex]))
|
||||
return false;
|
||||
if (!RenderSignature(c, *sig))
|
||||
if (!RenderValType(c, fieldTypes[fieldIndex]))
|
||||
return false;
|
||||
if (!c.buffer.append("))\n"))
|
||||
if (!c.buffer.append(')'))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<size_t ArrayLength>
|
||||
static bool
|
||||
RenderTypeStart(WasmRenderContext& c, const AstName& name, const char (&keyword)[ArrayLength])
|
||||
{
|
||||
if (!RenderIndent(c))
|
||||
return false;
|
||||
if (!c.buffer.append("(type "))
|
||||
return false;
|
||||
if (!RenderNonemptyName(c, name))
|
||||
return false;
|
||||
if (!c.buffer.append("("))
|
||||
return false;
|
||||
return c.buffer.append(keyword);
|
||||
}
|
||||
|
||||
static bool
|
||||
RenderTypeEnd(WasmRenderContext& c)
|
||||
{
|
||||
return c.buffer.append("))\n");
|
||||
}
|
||||
|
||||
static bool
|
||||
RenderTypeSection(WasmRenderContext& c, const AstModule::TypeDefVector& types)
|
||||
{
|
||||
for (uint32_t typeIndex = 0; typeIndex < types.length(); typeIndex++) {
|
||||
const AstTypeDef* type = types[typeIndex];
|
||||
if (type->isSig()) {
|
||||
const AstSig* sig = &type->asSig();
|
||||
if (!RenderTypeStart(c, sig->name(), "func"))
|
||||
return false;
|
||||
if (!RenderSignature(c, *sig))
|
||||
return false;
|
||||
} else {
|
||||
const AstStruct* strukt = &type->asStruct();
|
||||
if (!RenderTypeStart(c, strukt->name(), "struct"))
|
||||
return false;
|
||||
c.indent++;
|
||||
if (!RenderFields(c, *strukt))
|
||||
return false;
|
||||
c.indent--;
|
||||
}
|
||||
if (!RenderTypeEnd(c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
RenderLimits(WasmRenderContext& c, const Limits& limits)
|
||||
{
|
||||
|
@ -1755,7 +1800,7 @@ RenderImport(WasmRenderContext& c, AstImport& import, const AstModule& module)
|
|||
case DefinitionKind::Function: {
|
||||
if (!c.buffer.append("(func"))
|
||||
return false;
|
||||
const AstSig* sig = module.sigs()[import.funcSig().index()];
|
||||
const AstSig* sig = &module.types()[import.funcSig().index()]->asSig();
|
||||
if (!RenderSignature(c, *sig))
|
||||
return false;
|
||||
if (!c.buffer.append(")"))
|
||||
|
@ -1858,9 +1903,9 @@ RenderExportSection(WasmRenderContext& c, const AstModule::ExportVector& exports
|
|||
}
|
||||
|
||||
static bool
|
||||
RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::SigVector& sigs)
|
||||
RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::TypeDefVector& types)
|
||||
{
|
||||
const AstSig* sig = sigs[func.sig().index()];
|
||||
const AstSig* sig = &types[func.sig().index()]->asSig();
|
||||
|
||||
uint32_t argsNum = sig->args().length();
|
||||
uint32_t localsNum = func.vars().length();
|
||||
|
@ -1904,13 +1949,13 @@ RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::SigVect
|
|||
|
||||
static bool
|
||||
RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
|
||||
const AstModule::SigVector& sigs)
|
||||
const AstModule::TypeDefVector& types)
|
||||
{
|
||||
uint32_t numFuncBodies = funcs.length();
|
||||
for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
|
||||
AstFunc* func = funcs[funcIndex];
|
||||
uint32_t sigIndex = func->sig().index();
|
||||
AstSig* sig = sigs[sigIndex];
|
||||
AstSig* sig = &types[sigIndex]->asSig();
|
||||
|
||||
if (!RenderIndent(c))
|
||||
return false;
|
||||
|
@ -1929,7 +1974,7 @@ RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
|
|||
c.currentFuncIndex = funcIndex;
|
||||
|
||||
c.indent++;
|
||||
if (!RenderFunctionBody(c, *func, sigs))
|
||||
if (!RenderFunctionBody(c, *func, types))
|
||||
return false;
|
||||
c.indent--;
|
||||
if (!RenderIndent(c))
|
||||
|
@ -2026,7 +2071,7 @@ RenderModule(WasmRenderContext& c, AstModule& module)
|
|||
|
||||
c.indent++;
|
||||
|
||||
if (!RenderTypeSection(c, module.sigs()))
|
||||
if (!RenderTypeSection(c, module.types()))
|
||||
return false;
|
||||
|
||||
if (!RenderImportSection(c, module))
|
||||
|
@ -2050,7 +2095,7 @@ RenderModule(WasmRenderContext& c, AstModule& module)
|
|||
if (!RenderElemSection(c, module))
|
||||
return false;
|
||||
|
||||
if (!RenderCodeSection(c, module.funcs(), module.sigs()))
|
||||
if (!RenderCodeSection(c, module.funcs(), module.types()))
|
||||
return false;
|
||||
|
||||
if (!RenderDataSection(c, module))
|
||||
|
|
|
@ -243,7 +243,11 @@ ModuleGenerator::init(Metadata* maybeAsmJSMetadata)
|
|||
}
|
||||
|
||||
if (!isAsmJS()) {
|
||||
for (SigWithId& sig : env_->sigs) {
|
||||
for (TypeDef& td : env_->types) {
|
||||
if (!td.isFuncType())
|
||||
continue;
|
||||
|
||||
SigWithId& sig = td.funcType();
|
||||
if (SigIdDesc::isGlobal(sig)) {
|
||||
uint32_t globalDataOffset;
|
||||
if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset))
|
||||
|
@ -979,6 +983,12 @@ ModuleGenerator::finishModule(const ShareableBytes& bytecode)
|
|||
if (!code || !code->initialize(bytecode, *linkDataTier_))
|
||||
return nullptr;
|
||||
|
||||
StructTypeVector structTypes;
|
||||
for (TypeDef& td : env_->types) {
|
||||
if (td.isStructType() && !structTypes.append(std::move(td.structType())))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SharedModule module(js_new<Module>(std::move(assumptions_),
|
||||
*code,
|
||||
std::move(maybeDebuggingBytes),
|
||||
|
@ -987,6 +997,7 @@ ModuleGenerator::finishModule(const ShareableBytes& bytecode)
|
|||
std::move(env_->exports),
|
||||
std::move(env_->dataSegments),
|
||||
std::move(env_->elemSegments),
|
||||
std::move(structTypes),
|
||||
bytecode));
|
||||
if (!module)
|
||||
return nullptr;
|
||||
|
|
|
@ -1212,7 +1212,7 @@ class FunctionCompiler
|
|||
return true;
|
||||
}
|
||||
|
||||
const SigWithId& sig = env_.sigs[sigIndex];
|
||||
const SigWithId& sig = env_.types[sigIndex].funcType();
|
||||
|
||||
CalleeDesc callee;
|
||||
if (env_.isAsmJS()) {
|
||||
|
@ -2235,7 +2235,7 @@ EmitCallIndirect(FunctionCompiler& f, bool oldStyle)
|
|||
if (f.inDeadCode())
|
||||
return true;
|
||||
|
||||
const Sig& sig = f.env().sigs[sigIndex];
|
||||
const Sig& sig = f.env().types[sigIndex].funcType();
|
||||
|
||||
CallCompileState call(f, lineOrBytecode);
|
||||
if (!EmitCallArgs(f, sig, args, &call))
|
||||
|
|
|
@ -398,6 +398,7 @@ Module::compiledSerializedSize() const
|
|||
SerializedVectorSize(exports_) +
|
||||
SerializedPodVectorSize(dataSegments_) +
|
||||
SerializedVectorSize(elemSegments_) +
|
||||
SerializedVectorSize(structTypes_) +
|
||||
code_->serializedSize();
|
||||
}
|
||||
|
||||
|
@ -423,6 +424,7 @@ Module::compiledSerialize(uint8_t* compiledBegin, size_t compiledSize) const
|
|||
cursor = SerializeVector(cursor, exports_);
|
||||
cursor = SerializePodVector(cursor, dataSegments_);
|
||||
cursor = SerializeVector(cursor, elemSegments_);
|
||||
cursor = SerializeVector(cursor, structTypes_);
|
||||
cursor = code_->serialize(cursor, linkData_);
|
||||
MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
|
||||
}
|
||||
|
@ -486,6 +488,11 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
|
|||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
StructTypeVector structTypes;
|
||||
cursor = DeserializeVector(cursor, &structTypes);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
SharedCode code;
|
||||
cursor = Code::deserialize(cursor, *bytecode, linkData, *metadata, &code);
|
||||
if (!cursor)
|
||||
|
@ -502,6 +509,7 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
|
|||
std::move(exports),
|
||||
std::move(dataSegments),
|
||||
std::move(elemSegments),
|
||||
std::move(structTypes),
|
||||
*bytecode);
|
||||
}
|
||||
|
||||
|
@ -627,6 +635,7 @@ Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
|||
SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
|
||||
dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
|
||||
SizeOfVectorExcludingThis(structTypes_, mallocSizeOf) +
|
||||
bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
||||
if (unlinkedCodeForDebugging_)
|
||||
*data += unlinkedCodeForDebugging_->sizeOfExcludingThis(mallocSizeOf);
|
||||
|
|
|
@ -135,6 +135,7 @@ class Module : public JS::WasmModule
|
|||
const ExportVector exports_;
|
||||
const DataSegmentVector dataSegments_;
|
||||
const ElemSegmentVector elemSegments_;
|
||||
const StructTypeVector structTypes_;
|
||||
const SharedBytes bytecode_;
|
||||
ExclusiveTiering tiering_;
|
||||
|
||||
|
@ -170,6 +171,7 @@ class Module : public JS::WasmModule
|
|||
ExportVector&& exports,
|
||||
DataSegmentVector&& dataSegments,
|
||||
ElemSegmentVector&& elemSegments,
|
||||
StructTypeVector&& structTypes,
|
||||
const ShareableBytes& bytecode)
|
||||
: assumptions_(std::move(assumptions)),
|
||||
code_(&code),
|
||||
|
@ -179,6 +181,7 @@ class Module : public JS::WasmModule
|
|||
exports_(std::move(exports)),
|
||||
dataSegments_(std::move(dataSegments)),
|
||||
elemSegments_(std::move(elemSegments)),
|
||||
structTypes_(std::move(structTypes)),
|
||||
bytecode_(&bytecode),
|
||||
tiering_(mutexid::WasmModuleTieringLock),
|
||||
codeIsBusy_(false)
|
||||
|
|
|
@ -1732,7 +1732,7 @@ OpIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector*
|
|||
if (!readVarU32(sigIndex))
|
||||
return fail("unable to read call_indirect signature index");
|
||||
|
||||
if (*sigIndex >= env_.numSigs())
|
||||
if (*sigIndex >= env_.numTypes())
|
||||
return fail("signature index out of range");
|
||||
|
||||
uint8_t flags;
|
||||
|
@ -1745,7 +1745,10 @@ OpIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector*
|
|||
if (!popWithType(ValType::I32, callee))
|
||||
return false;
|
||||
|
||||
const Sig& sig = env_.sigs[*sigIndex];
|
||||
if (!env_.types[*sigIndex].isFuncType())
|
||||
return fail("expected signature type");
|
||||
|
||||
const Sig& sig = env_.types[*sigIndex].funcType();
|
||||
|
||||
if (!popCallArgs(sig.args(), argValues))
|
||||
return false;
|
||||
|
@ -1789,10 +1792,13 @@ OpIter<Policy>::readOldCallIndirect(uint32_t* sigIndex, Value* callee, ValueVect
|
|||
if (!readVarU32(sigIndex))
|
||||
return fail("unable to read call_indirect signature index");
|
||||
|
||||
if (*sigIndex >= env_.numSigs())
|
||||
if (*sigIndex >= env_.numTypes())
|
||||
return fail("signature index out of range");
|
||||
|
||||
const Sig& sig = env_.sigs[*sigIndex];
|
||||
if (!env_.types[*sigIndex].isFuncType())
|
||||
return fail("expected signature type");
|
||||
|
||||
const Sig& sig = env_.types[*sigIndex].funcType();
|
||||
|
||||
if (!popCallArgs(sig.args(), argValues))
|
||||
return false;
|
||||
|
|
|
@ -94,6 +94,7 @@ class WasmToken
|
|||
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
|
||||
ExtraConversionOpcode,
|
||||
#endif
|
||||
Field,
|
||||
Float,
|
||||
Func,
|
||||
GetGlobal,
|
||||
|
@ -127,6 +128,7 @@ class WasmToken
|
|||
Shared,
|
||||
SignedInteger,
|
||||
Start,
|
||||
Struct,
|
||||
Store,
|
||||
Table,
|
||||
TeeLocal,
|
||||
|
@ -364,6 +366,7 @@ class WasmToken
|
|||
case End:
|
||||
case Error:
|
||||
case Export:
|
||||
case Field:
|
||||
case Float:
|
||||
case Func:
|
||||
case Global:
|
||||
|
@ -382,6 +385,7 @@ class WasmToken
|
|||
case Shared:
|
||||
case SignedInteger:
|
||||
case Start:
|
||||
case Struct:
|
||||
case Table:
|
||||
case Text:
|
||||
case Then:
|
||||
|
@ -951,6 +955,9 @@ WasmTokenStream::next()
|
|||
break;
|
||||
|
||||
case 'f':
|
||||
if (consume(u"field"))
|
||||
return WasmToken(WasmToken::Field, begin, cur_);
|
||||
|
||||
if (consume(u"func"))
|
||||
return WasmToken(WasmToken::Func, begin, cur_);
|
||||
|
||||
|
@ -1708,6 +1715,8 @@ WasmTokenStream::next()
|
|||
#endif
|
||||
if (consume(u"start"))
|
||||
return WasmToken(WasmToken::Start, begin, cur_);
|
||||
if (consume(u"struct"))
|
||||
return WasmToken(WasmToken::Struct, begin, cur_);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
|
@ -3331,24 +3340,71 @@ ParseFunc(WasmParseContext& c, AstModule* module)
|
|||
return func && module->append(func);
|
||||
}
|
||||
|
||||
static AstSig*
|
||||
static bool
|
||||
ParseGlobalType(WasmParseContext& c, WasmToken* typeToken, bool* isMutable);
|
||||
|
||||
static bool
|
||||
ParseStructFields(WasmParseContext& c, AstStruct* str)
|
||||
{
|
||||
AstNameVector names(c.lifo);
|
||||
AstValTypeVector types(c.lifo);
|
||||
|
||||
while (true) {
|
||||
if (!c.ts.getIf(WasmToken::OpenParen))
|
||||
break;
|
||||
|
||||
if (!c.ts.match(WasmToken::Field, c.error))
|
||||
return false;
|
||||
|
||||
AstName name = c.ts.getIfName();
|
||||
|
||||
WasmToken typeToken;
|
||||
bool isMutable;
|
||||
if (!ParseGlobalType(c, &typeToken, &isMutable))
|
||||
return false;
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
return false;
|
||||
|
||||
if (!names.append(name))
|
||||
return false;
|
||||
if (!types.append(typeToken.valueType()))
|
||||
return false;
|
||||
}
|
||||
|
||||
*str = AstStruct(std::move(names), std::move(types));
|
||||
return true;
|
||||
}
|
||||
|
||||
static AstTypeDef*
|
||||
ParseTypeDef(WasmParseContext& c)
|
||||
{
|
||||
AstName name = c.ts.getIfName();
|
||||
|
||||
if (!c.ts.match(WasmToken::OpenParen, c.error))
|
||||
return nullptr;
|
||||
if (!c.ts.match(WasmToken::Func, c.error))
|
||||
return nullptr;
|
||||
|
||||
AstSig sig(c.lifo);
|
||||
if (!ParseFuncSig(c, &sig))
|
||||
AstTypeDef* type = nullptr;
|
||||
if (c.ts.getIf(WasmToken::Func)) {
|
||||
AstSig sig(c.lifo);
|
||||
if (!ParseFuncSig(c, &sig))
|
||||
return nullptr;
|
||||
|
||||
type = new(c.lifo) AstSig(name, std::move(sig));
|
||||
} else if (c.ts.getIf(WasmToken::Struct)) {
|
||||
AstStruct str(c.lifo);
|
||||
if (!ParseStructFields(c, &str))
|
||||
return nullptr;
|
||||
|
||||
type = new(c.lifo) AstStruct(name, std::move(str));
|
||||
} else {
|
||||
c.ts.generateError(c.ts.peek(), "bad type definition", c.error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
return nullptr;
|
||||
|
||||
return new(c.lifo) AstSig(name, std::move(sig));
|
||||
return type;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -3922,8 +3978,10 @@ ParseModule(const char16_t* text, uintptr_t stackLimit, LifoAlloc& lifo, UniqueC
|
|||
|
||||
switch (section.kind()) {
|
||||
case WasmToken::Type: {
|
||||
AstSig* sig = ParseTypeDef(c);
|
||||
if (!sig || !module->append(sig))
|
||||
AstTypeDef* typeDef = ParseTypeDef(c);
|
||||
if (!typeDef)
|
||||
return nullptr;
|
||||
if (!module->append(static_cast<AstSig*>(typeDef)))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
|
@ -4008,6 +4066,7 @@ class Resolver
|
|||
AstNameMap importMap_;
|
||||
AstNameMap tableMap_;
|
||||
AstNameMap memoryMap_;
|
||||
AstNameMap typeMap_;
|
||||
AstNameVector targetStack_;
|
||||
|
||||
bool registerName(AstNameMap& map, AstName name, size_t index) {
|
||||
|
@ -4045,6 +4104,7 @@ class Resolver
|
|||
importMap_(lifo),
|
||||
tableMap_(lifo),
|
||||
memoryMap_(lifo),
|
||||
typeMap_(lifo),
|
||||
targetStack_(lifo)
|
||||
{}
|
||||
bool init() {
|
||||
|
@ -4053,6 +4113,7 @@ class Resolver
|
|||
importMap_.init() &&
|
||||
tableMap_.init() &&
|
||||
memoryMap_.init() &&
|
||||
typeMap_.init() &&
|
||||
varMap_.init() &&
|
||||
globalMap_.init();
|
||||
}
|
||||
|
@ -4072,6 +4133,7 @@ class Resolver
|
|||
REGISTER(Global, globalMap_)
|
||||
REGISTER(Table, tableMap_)
|
||||
REGISTER(Memory, memoryMap_)
|
||||
REGISTER(Type, typeMap_)
|
||||
|
||||
#undef REGISTER
|
||||
|
||||
|
@ -4097,6 +4159,7 @@ class Resolver
|
|||
RESOLVE(globalMap_, Global)
|
||||
RESOLVE(tableMap_, Table)
|
||||
RESOLVE(memoryMap_, Memory)
|
||||
RESOLVE(typeMap_, Type)
|
||||
|
||||
#undef RESOLVE
|
||||
|
||||
|
@ -4538,11 +4601,18 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
|
|||
if (!r.init())
|
||||
return false;
|
||||
|
||||
size_t numSigs = module->sigs().length();
|
||||
for (size_t i = 0; i < numSigs; i++) {
|
||||
AstSig* sig = module->sigs()[i];
|
||||
if (!r.registerSigName(sig->name(), i))
|
||||
return r.fail("duplicate signature");
|
||||
size_t numTypes = module->types().length();
|
||||
for (size_t i = 0; i < numTypes; i++) {
|
||||
AstTypeDef* ty = module->types()[i];
|
||||
if (ty->isSig()) {
|
||||
AstSig* sig = static_cast<AstSig*>(ty);
|
||||
if (!r.registerSigName(sig->name(), i))
|
||||
return r.fail("duplicate signature");
|
||||
} else if (ty->isStruct()) {
|
||||
AstStruct* str = static_cast<AstStruct*>(ty);
|
||||
if (!r.registerTypeName(str->name(), i))
|
||||
return r.fail("duplicate struct");
|
||||
}
|
||||
}
|
||||
|
||||
size_t lastFuncIndex = 0;
|
||||
|
@ -5169,34 +5239,51 @@ EncodeExpr(Encoder& e, AstExpr& expr)
|
|||
static bool
|
||||
EncodeTypeSection(Encoder& e, AstModule& module)
|
||||
{
|
||||
if (module.sigs().empty())
|
||||
if (module.types().empty())
|
||||
return true;
|
||||
|
||||
size_t offset;
|
||||
if (!e.startSection(SectionId::Type, &offset))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(module.sigs().length()))
|
||||
if (!e.writeVarU32(module.types().length()))
|
||||
return false;
|
||||
|
||||
for (AstSig* sig : module.sigs()) {
|
||||
if (!e.writeVarU32(uint32_t(TypeCode::Func)))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(sig->args().length()))
|
||||
return false;
|
||||
|
||||
for (ValType t : sig->args()) {
|
||||
if (!e.writeValType(t))
|
||||
for (AstTypeDef* ty : module.types()) {
|
||||
if (ty->isSig()) {
|
||||
AstSig* sig = static_cast<AstSig*>(ty);
|
||||
if (!e.writeVarU32(uint32_t(TypeCode::Func)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e.writeVarU32(!IsVoid(sig->ret())))
|
||||
return false;
|
||||
|
||||
if (!IsVoid(sig->ret())) {
|
||||
if (!e.writeValType(NonVoidToValType(sig->ret())))
|
||||
if (!e.writeVarU32(sig->args().length()))
|
||||
return false;
|
||||
|
||||
for (ValType t : sig->args()) {
|
||||
if (!e.writeValType(t))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e.writeVarU32(!IsVoid(sig->ret())))
|
||||
return false;
|
||||
|
||||
if (!IsVoid(sig->ret())) {
|
||||
if (!e.writeValType(NonVoidToValType(sig->ret())))
|
||||
return false;
|
||||
}
|
||||
} else if (ty->isStruct()) {
|
||||
AstStruct* str = static_cast<AstStruct*>(ty);
|
||||
if (!e.writeVarU32(uint32_t(TypeCode::Struct)))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(str->fieldTypes().length()))
|
||||
return false;
|
||||
|
||||
for (ValType t : str->fieldTypes()) {
|
||||
if (!e.writeValType(t))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -327,6 +327,36 @@ SigWithId::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
|||
return Sig::sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
size_t
|
||||
StructType::serializedSize() const
|
||||
{
|
||||
return SerializedPodVectorSize(fields_) +
|
||||
SerializedPodVectorSize(fieldOffsets_);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
StructType::serialize(uint8_t* cursor) const
|
||||
{
|
||||
cursor = SerializePodVector(cursor, fields_);
|
||||
cursor = SerializePodVector(cursor, fieldOffsets_);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
StructType::deserialize(const uint8_t* cursor)
|
||||
{
|
||||
(cursor = DeserializePodVector(cursor, &fields_));
|
||||
(cursor = DeserializePodVector(cursor, &fieldOffsets_));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
size_t
|
||||
StructType::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
return fields_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
fieldOffsets_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
size_t
|
||||
Import::serializedSize() const
|
||||
{
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
|
@ -753,6 +752,31 @@ struct SigHashPolicy
|
|||
static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; }
|
||||
};
|
||||
|
||||
// Structure type.
|
||||
//
|
||||
// The Module owns a dense array of Struct values that represent the structure
|
||||
// types that the module knows about. It is created from the sparse array of
|
||||
// types in the ModuleEnvironment when the Module is created.
|
||||
|
||||
class StructType
|
||||
{
|
||||
public:
|
||||
ValTypeVector fields_; // Scalar types of fields
|
||||
Uint32Vector fieldOffsets_; // Byte offsets into an object for corresponding field
|
||||
|
||||
public:
|
||||
StructType() : fields_(), fieldOffsets_() {}
|
||||
|
||||
StructType(ValTypeVector&& fields, Uint32Vector&& fieldOffsets)
|
||||
: fields_(std::move(fields)),
|
||||
fieldOffsets_(std::move(fieldOffsets))
|
||||
{}
|
||||
|
||||
WASM_DECLARE_SERIALIZABLE(StructType)
|
||||
};
|
||||
|
||||
typedef Vector<StructType, 0, SystemAllocPolicy> StructTypeVector;
|
||||
|
||||
// An InitExpr describes a deferred initializer expression, used to initialize
|
||||
// a global or a table element offset. Such expressions are created during
|
||||
// decoding and actually executed on module instantiation.
|
||||
|
@ -1113,6 +1137,97 @@ struct SigWithId : Sig
|
|||
typedef Vector<SigWithId, 0, SystemAllocPolicy> SigWithIdVector;
|
||||
typedef Vector<const SigWithId*, 0, SystemAllocPolicy> SigWithIdPtrVector;
|
||||
|
||||
// A tagged container for the various types that can be present in a wasm
|
||||
// module's type section.
|
||||
|
||||
class TypeDef
|
||||
{
|
||||
enum { IsFuncType, IsStructType, IsNone } tag_;
|
||||
union {
|
||||
SigWithId funcType_;
|
||||
StructType structType_;
|
||||
};
|
||||
|
||||
public:
|
||||
TypeDef() : tag_(IsNone), structType_(StructType()) {}
|
||||
|
||||
explicit TypeDef(Sig&& sig) : tag_(IsFuncType), funcType_(SigWithId(std::move(sig))) {}
|
||||
|
||||
explicit TypeDef(StructType&& structType) : tag_(IsStructType), structType_(std::move(structType)) {}
|
||||
|
||||
TypeDef(TypeDef&& td) : tag_(td.tag_), structType_(StructType()) {
|
||||
switch (tag_) {
|
||||
case IsFuncType: funcType_ = std::move(td.funcType_); break;
|
||||
case IsStructType: structType_ = std::move(td.structType_); break;
|
||||
case IsNone: break;
|
||||
}
|
||||
}
|
||||
|
||||
~TypeDef() {
|
||||
switch (tag_) {
|
||||
case IsFuncType: funcType_.~SigWithId(); break;
|
||||
case IsStructType: structType_.~StructType(); break;
|
||||
case IsNone: break;
|
||||
}
|
||||
}
|
||||
|
||||
TypeDef& operator=(TypeDef&& that) {
|
||||
tag_ = that.tag_;
|
||||
switch (tag_) {
|
||||
case IsFuncType: funcType_ = std::move(that.funcType_); break;
|
||||
case IsStructType: structType_ = std::move(that.structType_); break;
|
||||
case IsNone: break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isFuncType() const {
|
||||
return tag_ == IsFuncType;
|
||||
}
|
||||
|
||||
bool isStructType() const {
|
||||
return tag_ == IsStructType;
|
||||
}
|
||||
|
||||
const SigWithId& funcType() const {
|
||||
MOZ_ASSERT(isFuncType());
|
||||
return funcType_;
|
||||
}
|
||||
|
||||
SigWithId& funcType() {
|
||||
MOZ_ASSERT(isFuncType());
|
||||
return funcType_;
|
||||
}
|
||||
|
||||
// p has to point to the sig_ embedded within a TypeDef for this to be
|
||||
// valid.
|
||||
static const TypeDef* fromSigWithIdPtr(const SigWithId* p) {
|
||||
const TypeDef* q = (const TypeDef*)((char*)p - offsetof(TypeDef, funcType_));
|
||||
MOZ_ASSERT(q->tag_ == IsFuncType);
|
||||
return q;
|
||||
}
|
||||
|
||||
const StructType& structType() const {
|
||||
MOZ_ASSERT(isStructType());
|
||||
return structType_;
|
||||
}
|
||||
|
||||
StructType& structType() {
|
||||
MOZ_ASSERT(isStructType());
|
||||
return structType_;
|
||||
}
|
||||
|
||||
// p has to point to the struct_ embedded within a TypeDef for this to be
|
||||
// valid.
|
||||
static const TypeDef* fromStructPtr(const StructType* p) {
|
||||
const TypeDef* q = (const TypeDef*)((char*)p - offsetof(TypeDef, structType_));
|
||||
MOZ_ASSERT(q->tag_ == IsStructType);
|
||||
return q;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Vector<TypeDef, 0, SystemAllocPolicy> TypeDefVector;
|
||||
|
||||
// A wasm::Trap represents a wasm-defined trap that can occur during execution
|
||||
// which triggers a WebAssembly.RuntimeError. Generated code may jump to a Trap
|
||||
// symbolically, passing the bytecode offset to report as the trap offset. The
|
||||
|
|
|
@ -1063,6 +1063,78 @@ DecodePreamble(Decoder& d)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeFuncType(Decoder& d, ModuleEnvironment* env, uint32_t typeIndex)
|
||||
{
|
||||
uint32_t numArgs;
|
||||
if (!d.readVarU32(&numArgs))
|
||||
return d.fail("bad number of function args");
|
||||
|
||||
if (numArgs > MaxParams)
|
||||
return d.fail("too many arguments in signature");
|
||||
|
||||
ValTypeVector args;
|
||||
if (!args.resize(numArgs))
|
||||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < numArgs; i++) {
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &args[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t numRets;
|
||||
if (!d.readVarU32(&numRets))
|
||||
return d.fail("bad number of function returns");
|
||||
|
||||
if (numRets > 1)
|
||||
return d.fail("too many returns in signature");
|
||||
|
||||
ExprType result = ExprType::Void;
|
||||
|
||||
if (numRets == 1) {
|
||||
ValType type;
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &type))
|
||||
return false;
|
||||
|
||||
result = ToExprType(type);
|
||||
}
|
||||
|
||||
env->types[typeIndex] = TypeDef(Sig(std::move(args), result));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeStructType(Decoder& d, ModuleEnvironment* env, uint32_t typeIndex)
|
||||
{
|
||||
if (env->gcTypesEnabled == HasGcTypes::False)
|
||||
return d.fail("Structure types not enabled");
|
||||
|
||||
uint32_t numFields;
|
||||
if (!d.readVarU32(&numFields))
|
||||
return d.fail("Bad number of fields");
|
||||
|
||||
if (numFields > MaxStructFields)
|
||||
return d.fail("too many fields in structure");
|
||||
|
||||
ValTypeVector fields;
|
||||
if (!fields.resize(numFields))
|
||||
return false;
|
||||
|
||||
Uint32Vector fieldOffsets;
|
||||
if (!fieldOffsets.resize(numFields))
|
||||
return false;
|
||||
|
||||
// TODO (subsequent patch): lay out the fields.
|
||||
|
||||
for (uint32_t i = 0; i < numFields; i++) {
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &fields[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
env->types[typeIndex] = TypeDef(StructType(std::move(fields), std::move(fieldOffsets)));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
||||
{
|
||||
|
@ -1072,55 +1144,33 @@ DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
|||
if (!range)
|
||||
return true;
|
||||
|
||||
uint32_t numSigs;
|
||||
if (!d.readVarU32(&numSigs))
|
||||
return d.fail("expected number of signatures");
|
||||
uint32_t numTypes;
|
||||
if (!d.readVarU32(&numTypes))
|
||||
return d.fail("expected number of types");
|
||||
|
||||
if (numSigs > MaxTypes)
|
||||
return d.fail("too many signatures");
|
||||
if (numTypes > MaxTypes)
|
||||
return d.fail("too many types");
|
||||
|
||||
if (!env->sigs.resize(numSigs))
|
||||
if (!env->types.resize(numTypes))
|
||||
return false;
|
||||
|
||||
for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
|
||||
for (uint32_t typeIndex = 0; typeIndex < numTypes; typeIndex++) {
|
||||
uint8_t form;
|
||||
if (!d.readFixedU8(&form) || form != uint8_t(TypeCode::Func))
|
||||
return d.fail("expected function form");
|
||||
if (!d.readFixedU8(&form))
|
||||
return d.fail("expected type form");
|
||||
|
||||
uint32_t numArgs;
|
||||
if (!d.readVarU32(&numArgs))
|
||||
return d.fail("bad number of function args");
|
||||
|
||||
if (numArgs > MaxParams)
|
||||
return d.fail("too many arguments in signature");
|
||||
|
||||
ValTypeVector args;
|
||||
if (!args.resize(numArgs))
|
||||
return false;
|
||||
|
||||
for (uint32_t i = 0; i < numArgs; i++) {
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &args[i]))
|
||||
switch (form) {
|
||||
case uint8_t(TypeCode::Func):
|
||||
if (!DecodeFuncType(d, env, typeIndex))
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t numRets;
|
||||
if (!d.readVarU32(&numRets))
|
||||
return d.fail("bad number of function returns");
|
||||
|
||||
if (numRets > 1)
|
||||
return d.fail("too many returns in signature");
|
||||
|
||||
ExprType result = ExprType::Void;
|
||||
|
||||
if (numRets == 1) {
|
||||
ValType type;
|
||||
if (!DecodeValType(d, ModuleKind::Wasm, env->gcTypesEnabled, &type))
|
||||
break;
|
||||
case uint8_t(TypeCode::Struct):
|
||||
if (!DecodeStructType(d, env, typeIndex))
|
||||
return false;
|
||||
|
||||
result = ToExprType(type);
|
||||
break;
|
||||
default:
|
||||
return d.fail("expected type form");
|
||||
}
|
||||
|
||||
env->sigs[sigIndex] = Sig(std::move(args), result);
|
||||
}
|
||||
|
||||
return d.finishSection(*range, "type");
|
||||
|
@ -1154,14 +1204,17 @@ DecodeName(Decoder& d)
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeSignatureIndex(Decoder& d, const SigWithIdVector& sigs, uint32_t* sigIndex)
|
||||
DecodeSignatureIndex(Decoder& d, const TypeDefVector& types, uint32_t* sigIndex)
|
||||
{
|
||||
if (!d.readVarU32(sigIndex))
|
||||
return d.fail("expected signature index");
|
||||
|
||||
if (*sigIndex >= sigs.length())
|
||||
if (*sigIndex >= types.length())
|
||||
return d.fail("signature index out of range");
|
||||
|
||||
if (!types[*sigIndex].isFuncType())
|
||||
return d.fail("signature index references non-signature");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1335,9 +1388,9 @@ DecodeImport(Decoder& d, ModuleEnvironment* env)
|
|||
switch (importKind) {
|
||||
case DefinitionKind::Function: {
|
||||
uint32_t sigIndex;
|
||||
if (!DecodeSignatureIndex(d, env->sigs, &sigIndex))
|
||||
if (!DecodeSignatureIndex(d, env->types, &sigIndex))
|
||||
return false;
|
||||
if (!env->funcSigs.append(&env->sigs[sigIndex]))
|
||||
if (!env->funcSigs.append(&env->types[sigIndex].funcType()))
|
||||
return false;
|
||||
if (env->funcSigs.length() > MaxFuncs)
|
||||
return d.fail("too many functions");
|
||||
|
@ -1428,9 +1481,9 @@ DecodeFunctionSection(Decoder& d, ModuleEnvironment* env)
|
|||
|
||||
for (uint32_t i = 0; i < numDefs; i++) {
|
||||
uint32_t sigIndex;
|
||||
if (!DecodeSignatureIndex(d, env->sigs, &sigIndex))
|
||||
if (!DecodeSignatureIndex(d, env->types, &sigIndex))
|
||||
return false;
|
||||
env->funcSigs.infallibleAppend(&env->sigs[sigIndex]);
|
||||
env->funcSigs.infallibleAppend(&env->types[sigIndex].funcType());
|
||||
}
|
||||
|
||||
return d.finishSection(*range, "function");
|
||||
|
|
|
@ -68,7 +68,7 @@ struct ModuleEnvironment
|
|||
MemoryUsage memoryUsage;
|
||||
uint32_t minMemoryLength;
|
||||
Maybe<uint32_t> maxMemoryLength;
|
||||
SigWithIdVector sigs;
|
||||
TypeDefVector types;
|
||||
SigWithIdPtrVector funcSigs;
|
||||
Uint32Vector funcImportGlobalDataOffsets;
|
||||
GlobalDescVector globals;
|
||||
|
@ -105,8 +105,8 @@ struct ModuleEnvironment
|
|||
size_t numTables() const {
|
||||
return tables.length();
|
||||
}
|
||||
size_t numSigs() const {
|
||||
return sigs.length();
|
||||
size_t numTypes() const {
|
||||
return types.length();
|
||||
}
|
||||
size_t numFuncs() const {
|
||||
return funcSigs.length();
|
||||
|
@ -133,7 +133,7 @@ struct ModuleEnvironment
|
|||
return funcIndex < funcImportGlobalDataOffsets.length();
|
||||
}
|
||||
uint32_t funcIndexToSigIndex(uint32_t funcIndex) const {
|
||||
return funcSigs[funcIndex] - sigs.begin();
|
||||
return TypeDef::fromSigWithIdPtr(funcSigs[funcIndex]) - types.begin();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче