зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1284155 - Baldr: add Table exports (r=bbouvier)
MozReview-Commit-ID: 4RVN5vi2ZQC --HG-- extra : rebase_source : 39118e95455995521b1902013937b76d79dab5f1
This commit is contained in:
Родитель
3c2b9e1f36
Коммит
3450e6c004
|
@ -551,12 +551,12 @@ class AstExport : public AstNode
|
||||||
AstExport(AstName name, AstRef func)
|
AstExport(AstName name, AstRef func)
|
||||||
: name_(name), kind_(DefinitionKind::Function), func_(func)
|
: name_(name), kind_(DefinitionKind::Function), func_(func)
|
||||||
{}
|
{}
|
||||||
explicit AstExport(AstName name)
|
explicit AstExport(AstName name, DefinitionKind kind)
|
||||||
: name_(name), kind_(DefinitionKind::Memory)
|
: name_(name), kind_(kind)
|
||||||
{}
|
{}
|
||||||
AstName name() const { return name_; }
|
AstName name() const { return name_; }
|
||||||
DefinitionKind kind() const { return kind_; }
|
DefinitionKind kind() const { return kind_; }
|
||||||
AstRef& func() { return func_; }
|
AstRef& func() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return func_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstDataSegment : public AstNode
|
class AstDataSegment : public AstNode
|
||||||
|
|
|
@ -69,7 +69,8 @@ enum class TypeConstructor
|
||||||
enum class DefinitionKind
|
enum class DefinitionKind
|
||||||
{
|
{
|
||||||
Function = 0x00,
|
Function = 0x00,
|
||||||
Memory = 0x01
|
Table = 0x01,
|
||||||
|
Memory = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ResizableFlags
|
enum class ResizableFlags
|
||||||
|
|
|
@ -1262,7 +1262,8 @@ AstDecodeMemorySection(AstDecodeContext& c)
|
||||||
return AstDecodeFail(c, "expected exported byte");
|
return AstDecodeFail(c, "expected exported byte");
|
||||||
|
|
||||||
if (exported) {
|
if (exported) {
|
||||||
AstExport* export_ = new(c.lifo) AstExport(AstName(MOZ_UTF16("memory")));
|
AstName fieldName(MOZ_UTF16("memory"));
|
||||||
|
AstExport* export_ = new(c.lifo) AstExport(fieldName, DefinitionKind::Memory);
|
||||||
if (!export_ || !c.module().append(export_))
|
if (!export_ || !c.module().append(export_))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -944,7 +944,7 @@ DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet
|
||||||
return Fail(d, "expected export internal index");
|
return Fail(d, "expected export internal index");
|
||||||
|
|
||||||
if (funcIndex >= mg.numFuncSigs())
|
if (funcIndex >= mg.numFuncSigs())
|
||||||
return Fail(d, "export function index out of range");
|
return Fail(d, "exported function index out of bounds");
|
||||||
|
|
||||||
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
||||||
return false;
|
return false;
|
||||||
|
@ -971,20 +971,30 @@ DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet
|
||||||
return Fail(d, "expected export internal index");
|
return Fail(d, "expected export internal index");
|
||||||
|
|
||||||
if (funcIndex >= mg.numFuncSigs())
|
if (funcIndex >= mg.numFuncSigs())
|
||||||
return Fail(d, "export function index out of range");
|
return Fail(d, "exported function index out of bounds");
|
||||||
|
|
||||||
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return mg.declareFuncExport(Move(fieldName), funcIndex);
|
return mg.declareFuncExport(Move(fieldName), funcIndex);
|
||||||
}
|
}
|
||||||
|
case DefinitionKind::Table: {
|
||||||
|
uint32_t tableIndex;
|
||||||
|
if (!d.readVarU32(&tableIndex))
|
||||||
|
return Fail(d, "expected table index");
|
||||||
|
|
||||||
|
if (tableIndex >= mg.tables().length())
|
||||||
|
return Fail(d, "exported table index out of bounds");
|
||||||
|
|
||||||
|
return mg.addTableExport(Move(fieldName));
|
||||||
|
}
|
||||||
case DefinitionKind::Memory: {
|
case DefinitionKind::Memory: {
|
||||||
uint32_t memoryIndex;
|
uint32_t memoryIndex;
|
||||||
if (!d.readVarU32(&memoryIndex))
|
if (!d.readVarU32(&memoryIndex))
|
||||||
return Fail(d, "expected memory index");
|
return Fail(d, "expected memory index");
|
||||||
|
|
||||||
if (memoryIndex > 0 || !mg.usesMemory())
|
if (memoryIndex > 0 || !mg.usesMemory())
|
||||||
return Fail(d, "memory index out of bounds");
|
return Fail(d, "exported memory index out of bounds");
|
||||||
|
|
||||||
return mg.addMemoryExport(Move(fieldName));
|
return mg.addMemoryExport(Move(fieldName));
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,6 +680,12 @@ ModuleGenerator::numExports() const
|
||||||
return metadata_->funcExports.length();
|
return metadata_->funcExports.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ModuleGenerator::addTableExport(UniqueChars fieldName)
|
||||||
|
{
|
||||||
|
return exports_.emplaceBack(Move(fieldName), DefinitionKind::Table);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ModuleGenerator::addMemoryExport(UniqueChars fieldName)
|
ModuleGenerator::addMemoryExport(UniqueChars fieldName)
|
||||||
{
|
{
|
||||||
|
|
|
@ -175,8 +175,9 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
// Exports:
|
// Exports:
|
||||||
MOZ_MUST_USE bool declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
|
MOZ_MUST_USE bool declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
|
||||||
uint32_t* funcExportIndex = nullptr);
|
uint32_t* funcExportIndex = nullptr);
|
||||||
uint32_t numExports() const;
|
MOZ_MUST_USE bool addTableExport(UniqueChars fieldName);
|
||||||
MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
|
MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
|
||||||
|
uint32_t numExports() const;
|
||||||
|
|
||||||
// Function definitions:
|
// Function definitions:
|
||||||
MOZ_MUST_USE bool startFuncDefs();
|
MOZ_MUST_USE bool startFuncDefs();
|
||||||
|
|
|
@ -80,6 +80,7 @@ class Instance
|
||||||
|
|
||||||
const CodeSegment& codeSegment() const { return *codeSegment_; }
|
const CodeSegment& codeSegment() const { return *codeSegment_; }
|
||||||
const Metadata& metadata() const { return *metadata_; }
|
const Metadata& metadata() const { return *metadata_; }
|
||||||
|
const SharedTableVector& tables() const { return tables_; }
|
||||||
SharedMem<uint8_t*> memoryBase() const;
|
SharedMem<uint8_t*> memoryBase() const;
|
||||||
size_t memoryLength() const;
|
size_t memoryLength() const;
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,8 @@ GetImports(JSContext* cx, HandleObject importObj, const ImportVector& imports,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case DefinitionKind::Table:
|
||||||
|
MOZ_CRASH("NYI");
|
||||||
case DefinitionKind::Memory:
|
case DefinitionKind::Memory:
|
||||||
if (!v.isObject() || !v.toObject().is<WasmMemoryObject>())
|
if (!v.isObject() || !v.toObject().is<WasmMemoryObject>())
|
||||||
return Throw(cx, "import object field is not a Memory");
|
return Throw(cx, "import object field is not a Memory");
|
||||||
|
@ -637,8 +639,10 @@ const JSPropertySpec WasmTableObject::properties[] =
|
||||||
{ JS_PS_END };
|
{ JS_PS_END };
|
||||||
|
|
||||||
/* static */ WasmTableObject*
|
/* static */ WasmTableObject*
|
||||||
WasmTableObject::create(ExclusiveContext* cx, Table& table, HandleObject proto)
|
WasmTableObject::create(JSContext* cx, Table& table)
|
||||||
{
|
{
|
||||||
|
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
|
||||||
|
|
||||||
AutoSetNewObjectMetadata metadata(cx);
|
AutoSetNewObjectMetadata metadata(cx);
|
||||||
auto* obj = NewObjectWithGivenProto<WasmTableObject>(cx, proto);
|
auto* obj = NewObjectWithGivenProto<WasmTableObject>(cx, proto);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
@ -688,8 +692,7 @@ WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||||
if (!table)
|
if (!table)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
|
RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table));
|
||||||
RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table, proto));
|
|
||||||
if (!tableObj)
|
if (!tableObj)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -166,14 +166,13 @@ class WasmTableObject : public NativeObject
|
||||||
static const JSPropertySpec properties[];
|
static const JSPropertySpec properties[];
|
||||||
static bool construct(JSContext*, unsigned, Value*);
|
static bool construct(JSContext*, unsigned, Value*);
|
||||||
|
|
||||||
static WasmTableObject* create(ExclusiveContext* cx,
|
static WasmTableObject* create(JSContext* cx, wasm::Table& table);
|
||||||
wasm::Table& table,
|
|
||||||
HandleObject proto);
|
|
||||||
wasm::Table& table() const;
|
wasm::Table& table() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Rooted<WasmTableObject*> RootedWasmTableObject;
|
typedef Rooted<WasmTableObject*> RootedWasmTableObject;
|
||||||
typedef Handle<WasmTableObject*> HandleWasmTableObject;
|
typedef Handle<WasmTableObject*> HandleWasmTableObject;
|
||||||
|
typedef MutableHandle<WasmTableObject*> MutableHandleWasmTableObject;
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
|
|
|
@ -464,9 +464,12 @@ CreateExportObject(JSContext* cx,
|
||||||
HandleWasmInstanceObject instanceObj,
|
HandleWasmInstanceObject instanceObj,
|
||||||
HandleWasmMemoryObject memoryObj,
|
HandleWasmMemoryObject memoryObj,
|
||||||
const ExportVector& exports,
|
const ExportVector& exports,
|
||||||
const Metadata& metadata,
|
|
||||||
MutableHandleObject exportObj)
|
MutableHandleObject exportObj)
|
||||||
{
|
{
|
||||||
|
const Instance& instance = instanceObj->instance();
|
||||||
|
const Metadata& metadata = instance.metadata();
|
||||||
|
const SharedTableVector& tables = instance.tables();
|
||||||
|
|
||||||
if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
|
if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
|
||||||
exportObj.set(NewExportedFunction(cx, instanceObj, 0));
|
exportObj.set(NewExportedFunction(cx, instanceObj, 0));
|
||||||
return !!exportObj;
|
return !!exportObj;
|
||||||
|
@ -483,6 +486,7 @@ CreateExportObject(JSContext* cx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RootedWasmTableObject tableObj(cx);
|
||||||
for (const Export& exp : exports) {
|
for (const Export& exp : exports) {
|
||||||
JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
|
JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
|
||||||
if (!atom)
|
if (!atom)
|
||||||
|
@ -494,6 +498,15 @@ CreateExportObject(JSContext* cx,
|
||||||
case DefinitionKind::Function:
|
case DefinitionKind::Function:
|
||||||
val = vals[exp.funcExportIndex()];
|
val = vals[exp.funcExportIndex()];
|
||||||
break;
|
break;
|
||||||
|
case DefinitionKind::Table:
|
||||||
|
MOZ_ASSERT(tables.length() == 1);
|
||||||
|
if (!tableObj) {
|
||||||
|
tableObj = WasmTableObject::create(cx, *tables[0]);
|
||||||
|
if (!tableObj)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
val = ObjectValue(*tableObj);
|
||||||
|
break;
|
||||||
case DefinitionKind::Memory:
|
case DefinitionKind::Memory:
|
||||||
if (metadata.assumptions.newFormat)
|
if (metadata.assumptions.newFormat)
|
||||||
val = ObjectValue(*memoryObj);
|
val = ObjectValue(*memoryObj);
|
||||||
|
@ -562,7 +575,7 @@ Module::instantiate(JSContext* cx,
|
||||||
// Create the export object.
|
// Create the export object.
|
||||||
|
|
||||||
RootedObject exportObj(cx);
|
RootedObject exportObj(cx);
|
||||||
if (!CreateExportObject(cx, instanceObj, memory, exports_, *metadata_, &exportObj))
|
if (!CreateExportObject(cx, instanceObj, memory, exports_, &exportObj))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
instanceObj->initExportsObject(exportObj);
|
instanceObj->initExportsObject(exportObj);
|
||||||
|
|
|
@ -2485,8 +2485,10 @@ ParseExport(WasmParseContext& c)
|
||||||
return new(c.lifo) AstExport(name.text(), AstRef(AstName(), exportee.index()));
|
return new(c.lifo) AstExport(name.text(), AstRef(AstName(), exportee.index()));
|
||||||
case WasmToken::Name:
|
case WasmToken::Name:
|
||||||
return new(c.lifo) AstExport(name.text(), AstRef(exportee.name(), AstNoIndex));
|
return new(c.lifo) AstExport(name.text(), AstRef(exportee.name(), AstNoIndex));
|
||||||
|
case WasmToken::Table:
|
||||||
|
return new(c.lifo) AstExport(name.text(), DefinitionKind::Table);
|
||||||
case WasmToken::Memory:
|
case WasmToken::Memory:
|
||||||
return new(c.lifo) AstExport(name.text());
|
return new(c.lifo) AstExport(name.text(), DefinitionKind::Memory);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3075,6 +3077,7 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case DefinitionKind::Memory:
|
case DefinitionKind::Memory:
|
||||||
|
case DefinitionKind::Table:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3554,6 +3557,8 @@ EncodeImport(Encoder& e, bool newFormat, AstImport& imp)
|
||||||
if (!e.writeVarU32(imp.funcSig().index()))
|
if (!e.writeVarU32(imp.funcSig().index()))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case DefinitionKind::Table:
|
||||||
|
MOZ_CRASH("NYI");
|
||||||
case DefinitionKind::Memory:
|
case DefinitionKind::Memory:
|
||||||
if (!EncodeResizable(e, imp.memory()))
|
if (!EncodeResizable(e, imp.memory()))
|
||||||
return false;
|
return false;
|
||||||
|
@ -3651,6 +3656,7 @@ EncodeExport(Encoder& e, bool newFormat, AstExport& exp)
|
||||||
if (!e.writeVarU32(exp.func().index()))
|
if (!e.writeVarU32(exp.func().index()))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case DefinitionKind::Table:
|
||||||
case DefinitionKind::Memory:
|
case DefinitionKind::Memory:
|
||||||
if (!e.writeVarU32(0))
|
if (!e.writeVarU32(0))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -29,8 +29,8 @@ wasmEvalText('(module (func) (func) (export "a" 1))');
|
||||||
wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
|
wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
|
||||||
wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
|
wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
|
||||||
|
|
||||||
assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /export function index out of range/);
|
assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /exported function index out of bounds/);
|
||||||
assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), TypeError, /export function index out of range/);
|
assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), TypeError, /exported function index out of bounds/);
|
||||||
|
|
||||||
var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))');
|
var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))');
|
||||||
assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
|
assertEq(Object.getOwnPropertyNames(o).sort().toString(), "a,b");
|
||||||
|
|
|
@ -56,6 +56,7 @@ assertEq(new Instance(m5, {a:{b:mem4Page}}) instanceof Instance, true);
|
||||||
|
|
||||||
assertErrorMessage(() => new Module(textToBinary('(module (memory 2 1))')), TypeError, /maximum length less than initial length/);
|
assertErrorMessage(() => new Module(textToBinary('(module (memory 2 1))')), TypeError, /maximum length less than initial length/);
|
||||||
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 2 1)))')), TypeError, /maximum length less than initial length/);
|
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 2 1)))')), TypeError, /maximum length less than initial length/);
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (table (resizable 2 1)))')), TypeError, /maximum length less than initial length/);
|
||||||
|
|
||||||
// Import order:
|
// Import order:
|
||||||
|
|
||||||
|
@ -158,6 +159,38 @@ assertEq(Object.keys(e).length, 1);
|
||||||
assertEq(String(Object.keys(e)), "");
|
assertEq(String(Object.keys(e)), "");
|
||||||
assertEq(e[""] instanceof Memory, true);
|
assertEq(e[""] instanceof Memory, true);
|
||||||
|
|
||||||
|
var code = textToBinary('(module (table) (export "tbl" table))');
|
||||||
|
var e = new Instance(new Module(code)).exports;
|
||||||
|
assertEq(Object.keys(e).join(), "tbl");
|
||||||
|
assertEq(e.tbl instanceof Table, true);
|
||||||
|
|
||||||
|
var code = textToBinary('(module (table (resizable 1)) (export "t1" table) (export "t2" table))');
|
||||||
|
var e = new Instance(new Module(code)).exports;
|
||||||
|
assertEq(Object.keys(e).join(), "t1,t2");
|
||||||
|
assertEq(e.t1 instanceof Table, true);
|
||||||
|
assertEq(e.t2 instanceof Table, true);
|
||||||
|
assertEq(e.t1, e.t2);
|
||||||
|
|
||||||
|
var code = textToBinary('(module (table) (memory 1 1) (func) (export "t" table) (export "m" memory) (export "f" 0))');
|
||||||
|
var e = new Instance(new Module(code)).exports;
|
||||||
|
assertEq(Object.keys(e).join(), "t,m,f");
|
||||||
|
assertEq(e.f(), undefined);
|
||||||
|
assertEq(e.t instanceof Table, true);
|
||||||
|
assertEq(e.m instanceof Memory, true);
|
||||||
|
|
||||||
|
var code = textToBinary('(module (table) (memory 1 1) (func) (export "m" memory) (export "f" 0) (export "t" table))');
|
||||||
|
var e = new Instance(new Module(code)).exports;
|
||||||
|
assertEq(Object.keys(e).join(), "m,f,t");
|
||||||
|
assertEq(e.f(), undefined);
|
||||||
|
assertEq(e.t instanceof Table, true);
|
||||||
|
assertEq(e.m instanceof Memory, true);
|
||||||
|
|
||||||
|
var code = textToBinary('(module (table) (export "" table))');
|
||||||
|
var e = new Instance(new Module(code)).exports;
|
||||||
|
assertEq(Object.keys(e).length, 1);
|
||||||
|
assertEq(String(Object.keys(e)), "");
|
||||||
|
assertEq(e[""] instanceof Table, true);
|
||||||
|
|
||||||
// Re-exports:
|
// Re-exports:
|
||||||
|
|
||||||
var code = textToBinary('(module (import "a" "b" (memory 1 1)) (export "foo" memory) (export "bar" memory))');
|
var code = textToBinary('(module (import "a" "b" (memory 1 1)) (export "foo" memory) (export "bar" memory))');
|
||||||
|
@ -166,6 +199,12 @@ var e = new Instance(new Module(code), {a:{b:mem}}).exports;
|
||||||
assertEq(mem, e.foo);
|
assertEq(mem, e.foo);
|
||||||
assertEq(mem, e.bar);
|
assertEq(mem, e.bar);
|
||||||
|
|
||||||
|
// Non-existent export errors
|
||||||
|
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (export "a" 0))')), TypeError, /exported function index out of bounds/);
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (export "a" memory))')), TypeError, /exported memory index out of bounds/);
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (export "a" table))')), TypeError, /exported table index out of bounds/);
|
||||||
|
|
||||||
// Default memory rules
|
// Default memory rules
|
||||||
|
|
||||||
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (memory 1 1))')), TypeError, /already have default memory/);
|
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (memory 1 1))')), TypeError, /already have default memory/);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче