зеркало из 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 i2vSig = {args:[I32Code], ret:VoidCode};
|
||||||
const v2vBody = funcBody({locals:[], body:[]});
|
const v2vBody = funcBody({locals:[], body:[]});
|
||||||
|
|
||||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: U32MAX_LEB } ])), CompileError, /too many signatures/);
|
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: U32MAX_LEB } ])), CompileError, /too many types/);
|
||||||
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: [1, 0], } ])), CompileError, /expected function form/);
|
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/);
|
assertErrorMessage(() => wasmEval(moduleWithSections([ {name: typeId, body: [1, FuncCode, ...U32MAX_LEB], } ])), CompileError, /too many arguments in signature/);
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => wasmEval(moduleWithSections([{name: typeId, body: [1]}])), CompileError);
|
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
|
class HashableSig
|
||||||
{
|
{
|
||||||
uint32_t sigIndex_;
|
uint32_t sigIndex_;
|
||||||
const SigWithIdVector& sigs_;
|
const TypeDefVector& types_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashableSig(uint32_t sigIndex, const SigWithIdVector& sigs)
|
HashableSig(uint32_t sigIndex, const TypeDefVector& types)
|
||||||
: sigIndex_(sigIndex), sigs_(sigs)
|
: sigIndex_(sigIndex), types_(types)
|
||||||
{}
|
{}
|
||||||
uint32_t sigIndex() const {
|
uint32_t sigIndex() const {
|
||||||
return sigIndex_;
|
return sigIndex_;
|
||||||
}
|
}
|
||||||
const Sig& sig() const {
|
const Sig& sig() const {
|
||||||
return sigs_[sigIndex_];
|
return types_[sigIndex_].funcType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement HashPolicy:
|
// Implement HashPolicy:
|
||||||
|
@ -1666,8 +1666,8 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
||||||
PropertyName* name_;
|
PropertyName* name_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NamedSig(PropertyName* name, uint32_t sigIndex, const SigWithIdVector& sigs)
|
NamedSig(PropertyName* name, uint32_t sigIndex, const TypeDefVector& types)
|
||||||
: HashableSig(sigIndex, sigs), name_(name)
|
: HashableSig(sigIndex, types), name_(name)
|
||||||
{}
|
{}
|
||||||
PropertyName* name() const {
|
PropertyName* name() const {
|
||||||
return name_;
|
return name_;
|
||||||
|
@ -1755,22 +1755,22 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
||||||
return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
|
return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
|
||||||
}
|
}
|
||||||
bool newSig(Sig&& sig, uint32_t* sigIndex) {
|
bool newSig(Sig&& sig, uint32_t* sigIndex) {
|
||||||
if (env_.sigs.length() >= MaxTypes)
|
if (env_.types.length() >= MaxTypes)
|
||||||
return failCurrentOffset("too many signatures");
|
return failCurrentOffset("too many signatures");
|
||||||
|
|
||||||
*sigIndex = env_.sigs.length();
|
*sigIndex = env_.types.length();
|
||||||
return env_.sigs.append(std::move(sig));
|
return env_.types.append(std::move(sig));
|
||||||
}
|
}
|
||||||
bool declareSig(Sig&& sig, uint32_t* sigIndex) {
|
bool declareSig(Sig&& sig, uint32_t* sigIndex) {
|
||||||
SigSet::AddPtr p = sigSet_.lookupForAdd(sig);
|
SigSet::AddPtr p = sigSet_.lookupForAdd(sig);
|
||||||
if (p) {
|
if (p) {
|
||||||
*sigIndex = p->sigIndex();
|
*sigIndex = p->sigIndex();
|
||||||
MOZ_ASSERT(env_.sigs[*sigIndex] == sig);
|
MOZ_ASSERT(env_.types[*sigIndex].funcType() == sig);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return newSig(std::move(sig), sigIndex) &&
|
return newSig(std::move(sig), sigIndex) &&
|
||||||
sigSet_.add(p, HashableSig(*sigIndex, env_.sigs));
|
sigSet_.add(p, HashableSig(*sigIndex, env_.types));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -2308,7 +2308,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
|
||||||
if (!declareSig(std::move(sig), &sigIndex))
|
if (!declareSig(std::move(sig), &sigIndex))
|
||||||
return false;
|
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) {
|
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()) {
|
for (FuncImportMap::Range r = funcImportMap_.all(); !r.empty(); r.popFront()) {
|
||||||
uint32_t funcIndex = r.front().value();
|
uint32_t funcIndex = r.front().value();
|
||||||
MOZ_ASSERT(!env_.funcSigs[funcIndex]);
|
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_) {
|
for (const Func& func : funcDefs_) {
|
||||||
uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
|
uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
|
||||||
MOZ_ASSERT(!env_.funcSigs[funcIndex]);
|
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()))
|
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);
|
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))
|
if (!CheckSignatureAgainstExisting(m, usepn, sig, existingSig))
|
||||||
return false;
|
return false;
|
||||||
|
@ -4951,7 +4951,7 @@ CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyN
|
||||||
if (mask != table.mask())
|
if (mask != table.mask())
|
||||||
return m.failf(usepn, "mask does not match previous value (%u)", 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;
|
return false;
|
||||||
|
|
||||||
*tableIndex = existing->tableIndex();
|
*tableIndex = existing->tableIndex();
|
||||||
|
@ -7376,7 +7376,7 @@ CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
|
||||||
if (!func)
|
if (!func)
|
||||||
return m.fail(elem, "function-pointer table's elements must be names of functions");
|
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) {
|
||||||
if (*sig != funcSig)
|
if (*sig != funcSig)
|
||||||
return m.fail(elem, "all functions in table must have same signature");
|
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_;
|
AstName name_;
|
||||||
AstValTypeVector args_;
|
AstValTypeVector args_;
|
||||||
|
@ -134,15 +156,18 @@ class AstSig : public AstBase
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AstSig(LifoAlloc& lifo)
|
explicit AstSig(LifoAlloc& lifo)
|
||||||
: args_(lifo),
|
: AstTypeDef(Which::IsSig),
|
||||||
|
args_(lifo),
|
||||||
ret_(ExprType::Void)
|
ret_(ExprType::Void)
|
||||||
{}
|
{}
|
||||||
AstSig(AstValTypeVector&& args, ExprType ret)
|
AstSig(AstValTypeVector&& args, ExprType ret)
|
||||||
: args_(std::move(args)),
|
: AstTypeDef(Which::IsSig),
|
||||||
|
args_(std::move(args)),
|
||||||
ret_(ret)
|
ret_(ret)
|
||||||
{}
|
{}
|
||||||
AstSig(AstName name, AstSig&& rhs)
|
AstSig(AstName name, AstSig&& rhs)
|
||||||
: name_(name),
|
: AstTypeDef(Which::IsSig),
|
||||||
|
name_(name),
|
||||||
args_(std::move(rhs.args_)),
|
args_(std::move(rhs.args_)),
|
||||||
ret_(rhs.ret_)
|
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;
|
const uint32_t AstNodeUnknownOffset = 0;
|
||||||
|
|
||||||
class AstNode : public AstBase
|
class AstNode : public AstBase
|
||||||
|
@ -948,7 +1035,7 @@ class AstModule : public AstNode
|
||||||
typedef AstVector<AstFunc*> FuncVector;
|
typedef AstVector<AstFunc*> FuncVector;
|
||||||
typedef AstVector<AstImport*> ImportVector;
|
typedef AstVector<AstImport*> ImportVector;
|
||||||
typedef AstVector<AstExport*> ExportVector;
|
typedef AstVector<AstExport*> ExportVector;
|
||||||
typedef AstVector<AstSig*> SigVector;
|
typedef AstVector<AstTypeDef*> TypeDefVector;
|
||||||
typedef AstVector<AstName> NameVector;
|
typedef AstVector<AstName> NameVector;
|
||||||
typedef AstVector<AstResizable> AstResizableVector;
|
typedef AstVector<AstResizable> AstResizableVector;
|
||||||
|
|
||||||
|
@ -956,7 +1043,7 @@ class AstModule : public AstNode
|
||||||
typedef AstHashMap<AstSig*, uint32_t, AstSig> SigMap;
|
typedef AstHashMap<AstSig*, uint32_t, AstSig> SigMap;
|
||||||
|
|
||||||
LifoAlloc& lifo_;
|
LifoAlloc& lifo_;
|
||||||
SigVector sigs_;
|
TypeDefVector types_;
|
||||||
SigMap sigMap_;
|
SigMap sigMap_;
|
||||||
ImportVector imports_;
|
ImportVector imports_;
|
||||||
NameVector funcImportNames_;
|
NameVector funcImportNames_;
|
||||||
|
@ -974,7 +1061,7 @@ class AstModule : public AstNode
|
||||||
public:
|
public:
|
||||||
explicit AstModule(LifoAlloc& lifo)
|
explicit AstModule(LifoAlloc& lifo)
|
||||||
: lifo_(lifo),
|
: lifo_(lifo),
|
||||||
sigs_(lifo),
|
types_(lifo),
|
||||||
sigMap_(lifo),
|
sigMap_(lifo),
|
||||||
imports_(lifo),
|
imports_(lifo),
|
||||||
funcImportNames_(lifo),
|
funcImportNames_(lifo),
|
||||||
|
@ -1038,21 +1125,21 @@ class AstModule : public AstNode
|
||||||
*sigIndex = p->value();
|
*sigIndex = p->value();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*sigIndex = sigs_.length();
|
*sigIndex = types_.length();
|
||||||
auto* lifoSig = new (lifo_) AstSig(AstName(), std::move(sig));
|
auto* lifoSig = new (lifo_) AstSig(AstName(), std::move(sig));
|
||||||
return lifoSig &&
|
return lifoSig &&
|
||||||
sigs_.append(lifoSig) &&
|
types_.append(lifoSig) &&
|
||||||
sigMap_.add(p, sigs_.back(), *sigIndex);
|
sigMap_.add(p, static_cast<AstSig*>(types_.back()), *sigIndex);
|
||||||
}
|
}
|
||||||
bool append(AstSig* sig) {
|
bool append(AstSig* sig) {
|
||||||
uint32_t sigIndex = sigs_.length();
|
uint32_t sigIndex = types_.length();
|
||||||
if (!sigs_.append(sig))
|
if (!types_.append(sig))
|
||||||
return false;
|
return false;
|
||||||
SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
|
SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
|
||||||
return p || sigMap_.add(p, sig, sigIndex);
|
return p || sigMap_.add(p, sig, sigIndex);
|
||||||
}
|
}
|
||||||
const SigVector& sigs() const {
|
const TypeDefVector& types() const {
|
||||||
return sigs_;
|
return types_;
|
||||||
}
|
}
|
||||||
bool append(AstFunc* func) {
|
bool append(AstFunc* func) {
|
||||||
return funcs_.append(func);
|
return funcs_.append(func);
|
||||||
|
@ -1060,6 +1147,9 @@ class AstModule : public AstNode
|
||||||
const FuncVector& funcs() const {
|
const FuncVector& funcs() const {
|
||||||
return funcs_;
|
return funcs_;
|
||||||
}
|
}
|
||||||
|
bool append(AstStruct* str) {
|
||||||
|
return types_.append(str);
|
||||||
|
}
|
||||||
bool append(AstImport* imp) {
|
bool append(AstImport* imp) {
|
||||||
switch (imp->kind()) {
|
switch (imp->kind()) {
|
||||||
case DefinitionKind::Function:
|
case DefinitionKind::Function:
|
||||||
|
|
|
@ -3762,7 +3762,7 @@ class BaseCompiler final : public BaseCompilerInterface
|
||||||
|
|
||||||
void callIndirect(uint32_t sigIndex, const Stk& indexVal, const FunctionCall& call)
|
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(sig.id.kind() != SigIdDesc::Kind::None);
|
||||||
|
|
||||||
MOZ_ASSERT(env_.tables.length() == 1);
|
MOZ_ASSERT(env_.tables.length() == 1);
|
||||||
|
@ -7861,7 +7861,7 @@ BaseCompiler::emitCallIndirect()
|
||||||
|
|
||||||
sync();
|
sync();
|
||||||
|
|
||||||
const SigWithId& sig = env_.sigs[sigIndex];
|
const SigWithId& sig = env_.types[sigIndex].funcType();
|
||||||
|
|
||||||
// Stack: ... arg1 .. argn callee
|
// Stack: ... arg1 .. argn callee
|
||||||
|
|
||||||
|
@ -8830,6 +8830,9 @@ BaseCompiler::emitInstanceCall(uint32_t lineOrBytecode, const MIRTypeVector& sig
|
||||||
|
|
||||||
popValueStackBy(numArgs);
|
popValueStackBy(numArgs);
|
||||||
|
|
||||||
|
// Note, a number of clients of emitInstanceCall currently assume that the
|
||||||
|
// following operation does not destroy ReturnReg.
|
||||||
|
|
||||||
pushReturnedIfNonVoid(baselineCall, retType);
|
pushReturnedIfNonVoid(baselineCall, retType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,9 @@ enum class TypeCode
|
||||||
// Type constructor for function types
|
// Type constructor for function types
|
||||||
Func = 0x60, // SLEB128(-0x20)
|
Func = 0x60, // SLEB128(-0x20)
|
||||||
|
|
||||||
|
// Type constructor for structure types - unofficial
|
||||||
|
Struct = 0x50, // SLEB128(-0x30)
|
||||||
|
|
||||||
// Special code representing the block signature ()->()
|
// Special code representing the block signature ()->()
|
||||||
BlockVoid = 0x40, // SLEB128(-0x40)
|
BlockVoid = 0x40, // SLEB128(-0x40)
|
||||||
|
|
||||||
|
@ -603,6 +606,7 @@ static const unsigned MaxElemSegments = 10000000;
|
||||||
static const unsigned MaxTableMaximumLength = 10000000;
|
static const unsigned MaxTableMaximumLength = 10000000;
|
||||||
static const unsigned MaxLocals = 50000;
|
static const unsigned MaxLocals = 50000;
|
||||||
static const unsigned MaxParams = 1000;
|
static const unsigned MaxParams = 1000;
|
||||||
|
static const unsigned MaxStructFields = 1000;
|
||||||
static const unsigned MaxMemoryMaximumPages = 65536;
|
static const unsigned MaxMemoryMaximumPages = 65536;
|
||||||
static const unsigned MaxStringBytes = 100000;
|
static const unsigned MaxStringBytes = 100000;
|
||||||
static const unsigned MaxModuleBytes = 1024 * 1024 * 1024;
|
static const unsigned MaxModuleBytes = 1024 * 1024 * 1024;
|
||||||
|
|
|
@ -97,12 +97,12 @@ class AstDecodeContext
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstDecodeContext(JSContext* cx, LifoAlloc& lifo, Decoder& d, AstModule& module,
|
AstDecodeContext(JSContext* cx, LifoAlloc& lifo, Decoder& d, AstModule& module,
|
||||||
bool generateNames)
|
bool generateNames, HasGcTypes hasGcTypes)
|
||||||
: cx(cx),
|
: cx(cx),
|
||||||
lifo(lifo),
|
lifo(lifo),
|
||||||
d(d),
|
d(d),
|
||||||
generateNames(generateNames),
|
generateNames(generateNames),
|
||||||
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, HasGcTypes::False,
|
env_(CompileMode::Once, Tier::Ion, DebugEnabled::False, hasGcTypes,
|
||||||
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()
|
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()
|
||||||
? Shareable::True
|
? Shareable::True
|
||||||
: Shareable::False),
|
: Shareable::False),
|
||||||
|
@ -351,7 +351,7 @@ AstDecodeCallIndirect(AstDecodeContext& c)
|
||||||
if (!GenerateRef(c, AstName(u"type"), sigIndex, &sigRef))
|
if (!GenerateRef(c, AstName(u"type"), sigIndex, &sigRef))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const SigWithId& sig = c.env().sigs[sigIndex];
|
const SigWithId& sig = c.env().types[sigIndex].funcType();
|
||||||
AstExprVector args(c.lifo);
|
AstExprVector args(c.lifo);
|
||||||
if (!AstDecodeCallArgs(c, sig, &args))
|
if (!AstDecodeCallArgs(c, sig, &args))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1958,26 +1958,59 @@ AstDecodeFunctionBody(AstDecodeContext &c, uint32_t funcIndex, AstFunc** func)
|
||||||
// wasm decoding and generation
|
// wasm decoding and generation
|
||||||
|
|
||||||
static bool
|
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++) {
|
AstValTypeVector args(c.lifo);
|
||||||
const Sig& sig = sigs[sigIndex];
|
if (!args.appendAll(sig.args()))
|
||||||
|
return false;
|
||||||
|
|
||||||
AstValTypeVector args(c.lifo);
|
AstSig sigNoName(std::move(args), sig.ret());
|
||||||
if (!args.appendAll(sig.args()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
AstSig sigNoName(std::move(args), sig.ret());
|
AstName sigName;
|
||||||
|
if (!GenerateName(c, AstName(u"type"), typeIndexForNames, &sigName))
|
||||||
|
return false;
|
||||||
|
|
||||||
AstName sigName;
|
AstSig* astSig = new(c.lifo) AstSig(sigName, std::move(sigNoName));
|
||||||
if (!GenerateName(c, AstName(u"type"), sigIndex, &sigName))
|
if (!astSig || !c.module().append(astSig))
|
||||||
return false;
|
return false;
|
||||||
|
} else if (td.isStructType()) {
|
||||||
|
const StructType& str = td.structType();
|
||||||
|
|
||||||
AstSig* astSig = new(c.lifo) AstSig(sigName, std::move(sigNoName));
|
AstValTypeVector fieldTypes(c.lifo);
|
||||||
if (!astSig || !c.module().append(astSig))
|
if (!fieldTypes.appendAll(str.fields_))
|
||||||
return false;
|
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;
|
return true;
|
||||||
|
@ -2230,7 +2263,7 @@ AstDecodeEnvironment(AstDecodeContext& c)
|
||||||
if (!DecodeModuleEnvironment(c.d, &c.env()))
|
if (!DecodeModuleEnvironment(c.d, &c.env()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!AstCreateSignatures(c))
|
if (!AstCreateTypes(c))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!AstCreateImports(c))
|
if (!AstCreateImports(c))
|
||||||
|
@ -2333,7 +2366,7 @@ wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAllo
|
||||||
|
|
||||||
UniqueChars error;
|
UniqueChars error;
|
||||||
Decoder d(bytes, bytes + length, 0, &error, nullptr, /* resilient */ true);
|
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) ||
|
if (!AstDecodeEnvironment(c) ||
|
||||||
!AstDecodeCodeSection(c) ||
|
!AstDecodeCodeSection(c) ||
|
||||||
|
|
|
@ -191,6 +191,7 @@ RenderExprType(WasmRenderContext& c, ExprType type)
|
||||||
case ExprType::I64: return c.buffer.append("i64");
|
case ExprType::I64: return c.buffer.append("i64");
|
||||||
case ExprType::F32: return c.buffer.append("f32");
|
case ExprType::F32: return c.buffer.append("f32");
|
||||||
case ExprType::F64: return c.buffer.append("f64");
|
case ExprType::F64: return c.buffer.append("f64");
|
||||||
|
case ExprType::AnyRef: return c.buffer.append("anyref");
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +210,12 @@ RenderName(WasmRenderContext& c, const AstName& name)
|
||||||
return c.buffer.append(name.begin(), name.end());
|
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
|
static bool
|
||||||
RenderRef(WasmRenderContext& c, const AstRef& ref)
|
RenderRef(WasmRenderContext& c, const AstRef& ref)
|
||||||
{
|
{
|
||||||
|
@ -1481,12 +1488,8 @@ RenderSignature(WasmRenderContext& c, const AstSig& sig, const AstNameVector* ma
|
||||||
if (!c.buffer.append(" (param "))
|
if (!c.buffer.append(" (param "))
|
||||||
return false;
|
return false;
|
||||||
const AstName& name = (*maybeLocals)[i];
|
const AstName& name = (*maybeLocals)[i];
|
||||||
if (!name.empty()) {
|
if (!RenderNonemptyName(c, name))
|
||||||
if (!RenderName(c, name))
|
return false;
|
||||||
return false;
|
|
||||||
if (!c.buffer.append(" "))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ValType arg = sig.args()[i];
|
ValType arg = sig.args()[i];
|
||||||
if (!RenderValType(c, arg))
|
if (!RenderValType(c, arg))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1518,34 +1521,76 @@ RenderSignature(WasmRenderContext& c, const AstSig& sig, const AstNameVector* ma
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
RenderTypeSection(WasmRenderContext& c, const AstModule::SigVector& sigs)
|
RenderFields(WasmRenderContext& c, const AstStruct& str)
|
||||||
{
|
{
|
||||||
uint32_t numSigs = sigs.length();
|
const AstNameVector& fieldNames = str.fieldNames();
|
||||||
if (!numSigs)
|
const AstValTypeVector& fieldTypes = str.fieldTypes();
|
||||||
return true;
|
|
||||||
|
|
||||||
for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
|
for (uint32_t fieldIndex = 0; fieldIndex < fieldTypes.length(); fieldIndex++) {
|
||||||
const AstSig* sig = sigs[sigIndex];
|
if (!c.buffer.append("\n"))
|
||||||
|
return false;
|
||||||
if (!RenderIndent(c))
|
if (!RenderIndent(c))
|
||||||
return false;
|
return false;
|
||||||
if (!c.buffer.append("(type"))
|
if (!c.buffer.append("(field "))
|
||||||
return false;
|
return false;
|
||||||
if (!sig->name().empty()) {
|
if (!RenderNonemptyName(c, fieldNames[fieldIndex]))
|
||||||
if (!c.buffer.append(" "))
|
|
||||||
return false;
|
|
||||||
if (!RenderName(c, sig->name()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!c.buffer.append(" (func"))
|
|
||||||
return false;
|
return false;
|
||||||
if (!RenderSignature(c, *sig))
|
if (!RenderValType(c, fieldTypes[fieldIndex]))
|
||||||
return false;
|
return false;
|
||||||
if (!c.buffer.append("))\n"))
|
if (!c.buffer.append(')'))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
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
|
static bool
|
||||||
RenderLimits(WasmRenderContext& c, const Limits& limits)
|
RenderLimits(WasmRenderContext& c, const Limits& limits)
|
||||||
{
|
{
|
||||||
|
@ -1755,7 +1800,7 @@ RenderImport(WasmRenderContext& c, AstImport& import, const AstModule& module)
|
||||||
case DefinitionKind::Function: {
|
case DefinitionKind::Function: {
|
||||||
if (!c.buffer.append("(func"))
|
if (!c.buffer.append("(func"))
|
||||||
return false;
|
return false;
|
||||||
const AstSig* sig = module.sigs()[import.funcSig().index()];
|
const AstSig* sig = &module.types()[import.funcSig().index()]->asSig();
|
||||||
if (!RenderSignature(c, *sig))
|
if (!RenderSignature(c, *sig))
|
||||||
return false;
|
return false;
|
||||||
if (!c.buffer.append(")"))
|
if (!c.buffer.append(")"))
|
||||||
|
@ -1858,9 +1903,9 @@ RenderExportSection(WasmRenderContext& c, const AstModule::ExportVector& exports
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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 argsNum = sig->args().length();
|
||||||
uint32_t localsNum = func.vars().length();
|
uint32_t localsNum = func.vars().length();
|
||||||
|
@ -1904,13 +1949,13 @@ RenderFunctionBody(WasmRenderContext& c, AstFunc& func, const AstModule::SigVect
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
|
RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
|
||||||
const AstModule::SigVector& sigs)
|
const AstModule::TypeDefVector& types)
|
||||||
{
|
{
|
||||||
uint32_t numFuncBodies = funcs.length();
|
uint32_t numFuncBodies = funcs.length();
|
||||||
for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
|
for (uint32_t funcIndex = 0; funcIndex < numFuncBodies; funcIndex++) {
|
||||||
AstFunc* func = funcs[funcIndex];
|
AstFunc* func = funcs[funcIndex];
|
||||||
uint32_t sigIndex = func->sig().index();
|
uint32_t sigIndex = func->sig().index();
|
||||||
AstSig* sig = sigs[sigIndex];
|
AstSig* sig = &types[sigIndex]->asSig();
|
||||||
|
|
||||||
if (!RenderIndent(c))
|
if (!RenderIndent(c))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1929,7 +1974,7 @@ RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs,
|
||||||
c.currentFuncIndex = funcIndex;
|
c.currentFuncIndex = funcIndex;
|
||||||
|
|
||||||
c.indent++;
|
c.indent++;
|
||||||
if (!RenderFunctionBody(c, *func, sigs))
|
if (!RenderFunctionBody(c, *func, types))
|
||||||
return false;
|
return false;
|
||||||
c.indent--;
|
c.indent--;
|
||||||
if (!RenderIndent(c))
|
if (!RenderIndent(c))
|
||||||
|
@ -2026,7 +2071,7 @@ RenderModule(WasmRenderContext& c, AstModule& module)
|
||||||
|
|
||||||
c.indent++;
|
c.indent++;
|
||||||
|
|
||||||
if (!RenderTypeSection(c, module.sigs()))
|
if (!RenderTypeSection(c, module.types()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!RenderImportSection(c, module))
|
if (!RenderImportSection(c, module))
|
||||||
|
@ -2050,7 +2095,7 @@ RenderModule(WasmRenderContext& c, AstModule& module)
|
||||||
if (!RenderElemSection(c, module))
|
if (!RenderElemSection(c, module))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!RenderCodeSection(c, module.funcs(), module.sigs()))
|
if (!RenderCodeSection(c, module.funcs(), module.types()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!RenderDataSection(c, module))
|
if (!RenderDataSection(c, module))
|
||||||
|
|
|
@ -243,7 +243,11 @@ ModuleGenerator::init(Metadata* maybeAsmJSMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAsmJS()) {
|
if (!isAsmJS()) {
|
||||||
for (SigWithId& sig : env_->sigs) {
|
for (TypeDef& td : env_->types) {
|
||||||
|
if (!td.isFuncType())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigWithId& sig = td.funcType();
|
||||||
if (SigIdDesc::isGlobal(sig)) {
|
if (SigIdDesc::isGlobal(sig)) {
|
||||||
uint32_t globalDataOffset;
|
uint32_t globalDataOffset;
|
||||||
if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset))
|
if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset))
|
||||||
|
@ -979,6 +983,12 @@ ModuleGenerator::finishModule(const ShareableBytes& bytecode)
|
||||||
if (!code || !code->initialize(bytecode, *linkDataTier_))
|
if (!code || !code->initialize(bytecode, *linkDataTier_))
|
||||||
return nullptr;
|
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_),
|
SharedModule module(js_new<Module>(std::move(assumptions_),
|
||||||
*code,
|
*code,
|
||||||
std::move(maybeDebuggingBytes),
|
std::move(maybeDebuggingBytes),
|
||||||
|
@ -987,6 +997,7 @@ ModuleGenerator::finishModule(const ShareableBytes& bytecode)
|
||||||
std::move(env_->exports),
|
std::move(env_->exports),
|
||||||
std::move(env_->dataSegments),
|
std::move(env_->dataSegments),
|
||||||
std::move(env_->elemSegments),
|
std::move(env_->elemSegments),
|
||||||
|
std::move(structTypes),
|
||||||
bytecode));
|
bytecode));
|
||||||
if (!module)
|
if (!module)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -1212,7 +1212,7 @@ class FunctionCompiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SigWithId& sig = env_.sigs[sigIndex];
|
const SigWithId& sig = env_.types[sigIndex].funcType();
|
||||||
|
|
||||||
CalleeDesc callee;
|
CalleeDesc callee;
|
||||||
if (env_.isAsmJS()) {
|
if (env_.isAsmJS()) {
|
||||||
|
@ -2235,7 +2235,7 @@ EmitCallIndirect(FunctionCompiler& f, bool oldStyle)
|
||||||
if (f.inDeadCode())
|
if (f.inDeadCode())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const Sig& sig = f.env().sigs[sigIndex];
|
const Sig& sig = f.env().types[sigIndex].funcType();
|
||||||
|
|
||||||
CallCompileState call(f, lineOrBytecode);
|
CallCompileState call(f, lineOrBytecode);
|
||||||
if (!EmitCallArgs(f, sig, args, &call))
|
if (!EmitCallArgs(f, sig, args, &call))
|
||||||
|
|
|
@ -398,6 +398,7 @@ Module::compiledSerializedSize() const
|
||||||
SerializedVectorSize(exports_) +
|
SerializedVectorSize(exports_) +
|
||||||
SerializedPodVectorSize(dataSegments_) +
|
SerializedPodVectorSize(dataSegments_) +
|
||||||
SerializedVectorSize(elemSegments_) +
|
SerializedVectorSize(elemSegments_) +
|
||||||
|
SerializedVectorSize(structTypes_) +
|
||||||
code_->serializedSize();
|
code_->serializedSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,6 +424,7 @@ Module::compiledSerialize(uint8_t* compiledBegin, size_t compiledSize) const
|
||||||
cursor = SerializeVector(cursor, exports_);
|
cursor = SerializeVector(cursor, exports_);
|
||||||
cursor = SerializePodVector(cursor, dataSegments_);
|
cursor = SerializePodVector(cursor, dataSegments_);
|
||||||
cursor = SerializeVector(cursor, elemSegments_);
|
cursor = SerializeVector(cursor, elemSegments_);
|
||||||
|
cursor = SerializeVector(cursor, structTypes_);
|
||||||
cursor = code_->serialize(cursor, linkData_);
|
cursor = code_->serialize(cursor, linkData_);
|
||||||
MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
|
MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
|
||||||
}
|
}
|
||||||
|
@ -486,6 +488,11 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
StructTypeVector structTypes;
|
||||||
|
cursor = DeserializeVector(cursor, &structTypes);
|
||||||
|
if (!cursor)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
SharedCode code;
|
SharedCode code;
|
||||||
cursor = Code::deserialize(cursor, *bytecode, linkData, *metadata, &code);
|
cursor = Code::deserialize(cursor, *bytecode, linkData, *metadata, &code);
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
|
@ -502,6 +509,7 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
|
||||||
std::move(exports),
|
std::move(exports),
|
||||||
std::move(dataSegments),
|
std::move(dataSegments),
|
||||||
std::move(elemSegments),
|
std::move(elemSegments),
|
||||||
|
std::move(structTypes),
|
||||||
*bytecode);
|
*bytecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,6 +635,7 @@ Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
||||||
SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
|
SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
|
||||||
dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
|
dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
|
||||||
SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
|
SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
|
||||||
|
SizeOfVectorExcludingThis(structTypes_, mallocSizeOf) +
|
||||||
bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
||||||
if (unlinkedCodeForDebugging_)
|
if (unlinkedCodeForDebugging_)
|
||||||
*data += unlinkedCodeForDebugging_->sizeOfExcludingThis(mallocSizeOf);
|
*data += unlinkedCodeForDebugging_->sizeOfExcludingThis(mallocSizeOf);
|
||||||
|
|
|
@ -135,6 +135,7 @@ class Module : public JS::WasmModule
|
||||||
const ExportVector exports_;
|
const ExportVector exports_;
|
||||||
const DataSegmentVector dataSegments_;
|
const DataSegmentVector dataSegments_;
|
||||||
const ElemSegmentVector elemSegments_;
|
const ElemSegmentVector elemSegments_;
|
||||||
|
const StructTypeVector structTypes_;
|
||||||
const SharedBytes bytecode_;
|
const SharedBytes bytecode_;
|
||||||
ExclusiveTiering tiering_;
|
ExclusiveTiering tiering_;
|
||||||
|
|
||||||
|
@ -170,6 +171,7 @@ class Module : public JS::WasmModule
|
||||||
ExportVector&& exports,
|
ExportVector&& exports,
|
||||||
DataSegmentVector&& dataSegments,
|
DataSegmentVector&& dataSegments,
|
||||||
ElemSegmentVector&& elemSegments,
|
ElemSegmentVector&& elemSegments,
|
||||||
|
StructTypeVector&& structTypes,
|
||||||
const ShareableBytes& bytecode)
|
const ShareableBytes& bytecode)
|
||||||
: assumptions_(std::move(assumptions)),
|
: assumptions_(std::move(assumptions)),
|
||||||
code_(&code),
|
code_(&code),
|
||||||
|
@ -179,6 +181,7 @@ class Module : public JS::WasmModule
|
||||||
exports_(std::move(exports)),
|
exports_(std::move(exports)),
|
||||||
dataSegments_(std::move(dataSegments)),
|
dataSegments_(std::move(dataSegments)),
|
||||||
elemSegments_(std::move(elemSegments)),
|
elemSegments_(std::move(elemSegments)),
|
||||||
|
structTypes_(std::move(structTypes)),
|
||||||
bytecode_(&bytecode),
|
bytecode_(&bytecode),
|
||||||
tiering_(mutexid::WasmModuleTieringLock),
|
tiering_(mutexid::WasmModuleTieringLock),
|
||||||
codeIsBusy_(false)
|
codeIsBusy_(false)
|
||||||
|
|
|
@ -1732,7 +1732,7 @@ OpIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector*
|
||||||
if (!readVarU32(sigIndex))
|
if (!readVarU32(sigIndex))
|
||||||
return fail("unable to read call_indirect signature index");
|
return fail("unable to read call_indirect signature index");
|
||||||
|
|
||||||
if (*sigIndex >= env_.numSigs())
|
if (*sigIndex >= env_.numTypes())
|
||||||
return fail("signature index out of range");
|
return fail("signature index out of range");
|
||||||
|
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
|
@ -1745,7 +1745,10 @@ OpIter<Policy>::readCallIndirect(uint32_t* sigIndex, Value* callee, ValueVector*
|
||||||
if (!popWithType(ValType::I32, callee))
|
if (!popWithType(ValType::I32, callee))
|
||||||
return false;
|
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))
|
if (!popCallArgs(sig.args(), argValues))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1789,10 +1792,13 @@ OpIter<Policy>::readOldCallIndirect(uint32_t* sigIndex, Value* callee, ValueVect
|
||||||
if (!readVarU32(sigIndex))
|
if (!readVarU32(sigIndex))
|
||||||
return fail("unable to read call_indirect signature index");
|
return fail("unable to read call_indirect signature index");
|
||||||
|
|
||||||
if (*sigIndex >= env_.numSigs())
|
if (*sigIndex >= env_.numTypes())
|
||||||
return fail("signature index out of range");
|
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))
|
if (!popCallArgs(sig.args(), argValues))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -94,6 +94,7 @@ class WasmToken
|
||||||
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
|
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
|
||||||
ExtraConversionOpcode,
|
ExtraConversionOpcode,
|
||||||
#endif
|
#endif
|
||||||
|
Field,
|
||||||
Float,
|
Float,
|
||||||
Func,
|
Func,
|
||||||
GetGlobal,
|
GetGlobal,
|
||||||
|
@ -127,6 +128,7 @@ class WasmToken
|
||||||
Shared,
|
Shared,
|
||||||
SignedInteger,
|
SignedInteger,
|
||||||
Start,
|
Start,
|
||||||
|
Struct,
|
||||||
Store,
|
Store,
|
||||||
Table,
|
Table,
|
||||||
TeeLocal,
|
TeeLocal,
|
||||||
|
@ -364,6 +366,7 @@ class WasmToken
|
||||||
case End:
|
case End:
|
||||||
case Error:
|
case Error:
|
||||||
case Export:
|
case Export:
|
||||||
|
case Field:
|
||||||
case Float:
|
case Float:
|
||||||
case Func:
|
case Func:
|
||||||
case Global:
|
case Global:
|
||||||
|
@ -382,6 +385,7 @@ class WasmToken
|
||||||
case Shared:
|
case Shared:
|
||||||
case SignedInteger:
|
case SignedInteger:
|
||||||
case Start:
|
case Start:
|
||||||
|
case Struct:
|
||||||
case Table:
|
case Table:
|
||||||
case Text:
|
case Text:
|
||||||
case Then:
|
case Then:
|
||||||
|
@ -951,6 +955,9 @@ WasmTokenStream::next()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
if (consume(u"field"))
|
||||||
|
return WasmToken(WasmToken::Field, begin, cur_);
|
||||||
|
|
||||||
if (consume(u"func"))
|
if (consume(u"func"))
|
||||||
return WasmToken(WasmToken::Func, begin, cur_);
|
return WasmToken(WasmToken::Func, begin, cur_);
|
||||||
|
|
||||||
|
@ -1708,6 +1715,8 @@ WasmTokenStream::next()
|
||||||
#endif
|
#endif
|
||||||
if (consume(u"start"))
|
if (consume(u"start"))
|
||||||
return WasmToken(WasmToken::Start, begin, cur_);
|
return WasmToken(WasmToken::Start, begin, cur_);
|
||||||
|
if (consume(u"struct"))
|
||||||
|
return WasmToken(WasmToken::Struct, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
|
@ -3331,24 +3340,71 @@ ParseFunc(WasmParseContext& c, AstModule* module)
|
||||||
return func && module->append(func);
|
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)
|
ParseTypeDef(WasmParseContext& c)
|
||||||
{
|
{
|
||||||
AstName name = c.ts.getIfName();
|
AstName name = c.ts.getIfName();
|
||||||
|
|
||||||
if (!c.ts.match(WasmToken::OpenParen, c.error))
|
if (!c.ts.match(WasmToken::OpenParen, c.error))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!c.ts.match(WasmToken::Func, c.error))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
AstSig sig(c.lifo);
|
AstTypeDef* type = nullptr;
|
||||||
if (!ParseFuncSig(c, &sig))
|
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;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return new(c.lifo) AstSig(name, std::move(sig));
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -3922,8 +3978,10 @@ ParseModule(const char16_t* text, uintptr_t stackLimit, LifoAlloc& lifo, UniqueC
|
||||||
|
|
||||||
switch (section.kind()) {
|
switch (section.kind()) {
|
||||||
case WasmToken::Type: {
|
case WasmToken::Type: {
|
||||||
AstSig* sig = ParseTypeDef(c);
|
AstTypeDef* typeDef = ParseTypeDef(c);
|
||||||
if (!sig || !module->append(sig))
|
if (!typeDef)
|
||||||
|
return nullptr;
|
||||||
|
if (!module->append(static_cast<AstSig*>(typeDef)))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4008,6 +4066,7 @@ class Resolver
|
||||||
AstNameMap importMap_;
|
AstNameMap importMap_;
|
||||||
AstNameMap tableMap_;
|
AstNameMap tableMap_;
|
||||||
AstNameMap memoryMap_;
|
AstNameMap memoryMap_;
|
||||||
|
AstNameMap typeMap_;
|
||||||
AstNameVector targetStack_;
|
AstNameVector targetStack_;
|
||||||
|
|
||||||
bool registerName(AstNameMap& map, AstName name, size_t index) {
|
bool registerName(AstNameMap& map, AstName name, size_t index) {
|
||||||
|
@ -4045,6 +4104,7 @@ class Resolver
|
||||||
importMap_(lifo),
|
importMap_(lifo),
|
||||||
tableMap_(lifo),
|
tableMap_(lifo),
|
||||||
memoryMap_(lifo),
|
memoryMap_(lifo),
|
||||||
|
typeMap_(lifo),
|
||||||
targetStack_(lifo)
|
targetStack_(lifo)
|
||||||
{}
|
{}
|
||||||
bool init() {
|
bool init() {
|
||||||
|
@ -4053,6 +4113,7 @@ class Resolver
|
||||||
importMap_.init() &&
|
importMap_.init() &&
|
||||||
tableMap_.init() &&
|
tableMap_.init() &&
|
||||||
memoryMap_.init() &&
|
memoryMap_.init() &&
|
||||||
|
typeMap_.init() &&
|
||||||
varMap_.init() &&
|
varMap_.init() &&
|
||||||
globalMap_.init();
|
globalMap_.init();
|
||||||
}
|
}
|
||||||
|
@ -4072,6 +4133,7 @@ class Resolver
|
||||||
REGISTER(Global, globalMap_)
|
REGISTER(Global, globalMap_)
|
||||||
REGISTER(Table, tableMap_)
|
REGISTER(Table, tableMap_)
|
||||||
REGISTER(Memory, memoryMap_)
|
REGISTER(Memory, memoryMap_)
|
||||||
|
REGISTER(Type, typeMap_)
|
||||||
|
|
||||||
#undef REGISTER
|
#undef REGISTER
|
||||||
|
|
||||||
|
@ -4097,6 +4159,7 @@ class Resolver
|
||||||
RESOLVE(globalMap_, Global)
|
RESOLVE(globalMap_, Global)
|
||||||
RESOLVE(tableMap_, Table)
|
RESOLVE(tableMap_, Table)
|
||||||
RESOLVE(memoryMap_, Memory)
|
RESOLVE(memoryMap_, Memory)
|
||||||
|
RESOLVE(typeMap_, Type)
|
||||||
|
|
||||||
#undef RESOLVE
|
#undef RESOLVE
|
||||||
|
|
||||||
|
@ -4538,11 +4601,18 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
|
||||||
if (!r.init())
|
if (!r.init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size_t numSigs = module->sigs().length();
|
size_t numTypes = module->types().length();
|
||||||
for (size_t i = 0; i < numSigs; i++) {
|
for (size_t i = 0; i < numTypes; i++) {
|
||||||
AstSig* sig = module->sigs()[i];
|
AstTypeDef* ty = module->types()[i];
|
||||||
if (!r.registerSigName(sig->name(), i))
|
if (ty->isSig()) {
|
||||||
return r.fail("duplicate signature");
|
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;
|
size_t lastFuncIndex = 0;
|
||||||
|
@ -5169,34 +5239,51 @@ EncodeExpr(Encoder& e, AstExpr& expr)
|
||||||
static bool
|
static bool
|
||||||
EncodeTypeSection(Encoder& e, AstModule& module)
|
EncodeTypeSection(Encoder& e, AstModule& module)
|
||||||
{
|
{
|
||||||
if (module.sigs().empty())
|
if (module.types().empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
if (!e.startSection(SectionId::Type, &offset))
|
if (!e.startSection(SectionId::Type, &offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!e.writeVarU32(module.sigs().length()))
|
if (!e.writeVarU32(module.types().length()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (AstSig* sig : module.sigs()) {
|
for (AstTypeDef* ty : module.types()) {
|
||||||
if (!e.writeVarU32(uint32_t(TypeCode::Func)))
|
if (ty->isSig()) {
|
||||||
return false;
|
AstSig* sig = static_cast<AstSig*>(ty);
|
||||||
|
if (!e.writeVarU32(uint32_t(TypeCode::Func)))
|
||||||
if (!e.writeVarU32(sig->args().length()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (ValType t : sig->args()) {
|
|
||||||
if (!e.writeValType(t))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!e.writeVarU32(!IsVoid(sig->ret())))
|
if (!e.writeVarU32(sig->args().length()))
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!IsVoid(sig->ret())) {
|
|
||||||
if (!e.writeValType(NonVoidToValType(sig->ret())))
|
|
||||||
return false;
|
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);
|
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
|
size_t
|
||||||
Import::serializedSize() const
|
Import::serializedSize() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "mozilla/EnumeratedArray.h"
|
#include "mozilla/EnumeratedArray.h"
|
||||||
#include "mozilla/HashFunctions.h"
|
#include "mozilla/HashFunctions.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/Move.h"
|
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
|
@ -753,6 +752,31 @@ struct SigHashPolicy
|
||||||
static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; }
|
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
|
// An InitExpr describes a deferred initializer expression, used to initialize
|
||||||
// a global or a table element offset. Such expressions are created during
|
// a global or a table element offset. Such expressions are created during
|
||||||
// decoding and actually executed on module instantiation.
|
// decoding and actually executed on module instantiation.
|
||||||
|
@ -1113,6 +1137,97 @@ struct SigWithId : Sig
|
||||||
typedef Vector<SigWithId, 0, SystemAllocPolicy> SigWithIdVector;
|
typedef Vector<SigWithId, 0, SystemAllocPolicy> SigWithIdVector;
|
||||||
typedef Vector<const SigWithId*, 0, SystemAllocPolicy> SigWithIdPtrVector;
|
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
|
// 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
|
// which triggers a WebAssembly.RuntimeError. Generated code may jump to a Trap
|
||||||
// symbolically, passing the bytecode offset to report as the trap offset. The
|
// symbolically, passing the bytecode offset to report as the trap offset. The
|
||||||
|
|
|
@ -1063,6 +1063,78 @@ DecodePreamble(Decoder& d)
|
||||||
return true;
|
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
|
static bool
|
||||||
DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
||||||
{
|
{
|
||||||
|
@ -1072,55 +1144,33 @@ DecodeTypeSection(Decoder& d, ModuleEnvironment* env)
|
||||||
if (!range)
|
if (!range)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
uint32_t numSigs;
|
uint32_t numTypes;
|
||||||
if (!d.readVarU32(&numSigs))
|
if (!d.readVarU32(&numTypes))
|
||||||
return d.fail("expected number of signatures");
|
return d.fail("expected number of types");
|
||||||
|
|
||||||
if (numSigs > MaxTypes)
|
if (numTypes > MaxTypes)
|
||||||
return d.fail("too many signatures");
|
return d.fail("too many types");
|
||||||
|
|
||||||
if (!env->sigs.resize(numSigs))
|
if (!env->types.resize(numTypes))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint32_t sigIndex = 0; sigIndex < numSigs; sigIndex++) {
|
for (uint32_t typeIndex = 0; typeIndex < numTypes; typeIndex++) {
|
||||||
uint8_t form;
|
uint8_t form;
|
||||||
if (!d.readFixedU8(&form) || form != uint8_t(TypeCode::Func))
|
if (!d.readFixedU8(&form))
|
||||||
return d.fail("expected function form");
|
return d.fail("expected type form");
|
||||||
|
|
||||||
uint32_t numArgs;
|
switch (form) {
|
||||||
if (!d.readVarU32(&numArgs))
|
case uint8_t(TypeCode::Func):
|
||||||
return d.fail("bad number of function args");
|
if (!DecodeFuncType(d, env, typeIndex))
|
||||||
|
|
||||||
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;
|
return false;
|
||||||
}
|
break;
|
||||||
|
case uint8_t(TypeCode::Struct):
|
||||||
uint32_t numRets;
|
if (!DecodeStructType(d, env, typeIndex))
|
||||||
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;
|
return false;
|
||||||
|
break;
|
||||||
result = ToExprType(type);
|
default:
|
||||||
|
return d.fail("expected type form");
|
||||||
}
|
}
|
||||||
|
|
||||||
env->sigs[sigIndex] = Sig(std::move(args), result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.finishSection(*range, "type");
|
return d.finishSection(*range, "type");
|
||||||
|
@ -1154,14 +1204,17 @@ DecodeName(Decoder& d)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DecodeSignatureIndex(Decoder& d, const SigWithIdVector& sigs, uint32_t* sigIndex)
|
DecodeSignatureIndex(Decoder& d, const TypeDefVector& types, uint32_t* sigIndex)
|
||||||
{
|
{
|
||||||
if (!d.readVarU32(sigIndex))
|
if (!d.readVarU32(sigIndex))
|
||||||
return d.fail("expected signature index");
|
return d.fail("expected signature index");
|
||||||
|
|
||||||
if (*sigIndex >= sigs.length())
|
if (*sigIndex >= types.length())
|
||||||
return d.fail("signature index out of range");
|
return d.fail("signature index out of range");
|
||||||
|
|
||||||
|
if (!types[*sigIndex].isFuncType())
|
||||||
|
return d.fail("signature index references non-signature");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1335,9 +1388,9 @@ DecodeImport(Decoder& d, ModuleEnvironment* env)
|
||||||
switch (importKind) {
|
switch (importKind) {
|
||||||
case DefinitionKind::Function: {
|
case DefinitionKind::Function: {
|
||||||
uint32_t sigIndex;
|
uint32_t sigIndex;
|
||||||
if (!DecodeSignatureIndex(d, env->sigs, &sigIndex))
|
if (!DecodeSignatureIndex(d, env->types, &sigIndex))
|
||||||
return false;
|
return false;
|
||||||
if (!env->funcSigs.append(&env->sigs[sigIndex]))
|
if (!env->funcSigs.append(&env->types[sigIndex].funcType()))
|
||||||
return false;
|
return false;
|
||||||
if (env->funcSigs.length() > MaxFuncs)
|
if (env->funcSigs.length() > MaxFuncs)
|
||||||
return d.fail("too many functions");
|
return d.fail("too many functions");
|
||||||
|
@ -1428,9 +1481,9 @@ DecodeFunctionSection(Decoder& d, ModuleEnvironment* env)
|
||||||
|
|
||||||
for (uint32_t i = 0; i < numDefs; i++) {
|
for (uint32_t i = 0; i < numDefs; i++) {
|
||||||
uint32_t sigIndex;
|
uint32_t sigIndex;
|
||||||
if (!DecodeSignatureIndex(d, env->sigs, &sigIndex))
|
if (!DecodeSignatureIndex(d, env->types, &sigIndex))
|
||||||
return false;
|
return false;
|
||||||
env->funcSigs.infallibleAppend(&env->sigs[sigIndex]);
|
env->funcSigs.infallibleAppend(&env->types[sigIndex].funcType());
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.finishSection(*range, "function");
|
return d.finishSection(*range, "function");
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct ModuleEnvironment
|
||||||
MemoryUsage memoryUsage;
|
MemoryUsage memoryUsage;
|
||||||
uint32_t minMemoryLength;
|
uint32_t minMemoryLength;
|
||||||
Maybe<uint32_t> maxMemoryLength;
|
Maybe<uint32_t> maxMemoryLength;
|
||||||
SigWithIdVector sigs;
|
TypeDefVector types;
|
||||||
SigWithIdPtrVector funcSigs;
|
SigWithIdPtrVector funcSigs;
|
||||||
Uint32Vector funcImportGlobalDataOffsets;
|
Uint32Vector funcImportGlobalDataOffsets;
|
||||||
GlobalDescVector globals;
|
GlobalDescVector globals;
|
||||||
|
@ -105,8 +105,8 @@ struct ModuleEnvironment
|
||||||
size_t numTables() const {
|
size_t numTables() const {
|
||||||
return tables.length();
|
return tables.length();
|
||||||
}
|
}
|
||||||
size_t numSigs() const {
|
size_t numTypes() const {
|
||||||
return sigs.length();
|
return types.length();
|
||||||
}
|
}
|
||||||
size_t numFuncs() const {
|
size_t numFuncs() const {
|
||||||
return funcSigs.length();
|
return funcSigs.length();
|
||||||
|
@ -133,7 +133,7 @@ struct ModuleEnvironment
|
||||||
return funcIndex < funcImportGlobalDataOffsets.length();
|
return funcIndex < funcImportGlobalDataOffsets.length();
|
||||||
}
|
}
|
||||||
uint32_t funcIndexToSigIndex(uint32_t funcIndex) const {
|
uint32_t funcIndexToSigIndex(uint32_t funcIndex) const {
|
||||||
return funcSigs[funcIndex] - sigs.begin();
|
return TypeDef::fromSigWithIdPtr(funcSigs[funcIndex]) - types.begin();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче