зеркало из 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)
|
||||
: name_(name), kind_(DefinitionKind::Function), func_(func)
|
||||
{}
|
||||
explicit AstExport(AstName name)
|
||||
: name_(name), kind_(DefinitionKind::Memory)
|
||||
explicit AstExport(AstName name, DefinitionKind kind)
|
||||
: name_(name), kind_(kind)
|
||||
{}
|
||||
AstName name() const { return name_; }
|
||||
DefinitionKind kind() const { return kind_; }
|
||||
AstRef& func() { return func_; }
|
||||
AstRef& func() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return func_; }
|
||||
};
|
||||
|
||||
class AstDataSegment : public AstNode
|
||||
|
|
|
@ -69,7 +69,8 @@ enum class TypeConstructor
|
|||
enum class DefinitionKind
|
||||
{
|
||||
Function = 0x00,
|
||||
Memory = 0x01
|
||||
Table = 0x01,
|
||||
Memory = 0x02
|
||||
};
|
||||
|
||||
enum class ResizableFlags
|
||||
|
|
|
@ -1262,7 +1262,8 @@ AstDecodeMemorySection(AstDecodeContext& c)
|
|||
return AstDecodeFail(c, "expected exported byte");
|
||||
|
||||
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_))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -944,7 +944,7 @@ DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet
|
|||
return Fail(d, "expected export internal index");
|
||||
|
||||
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)))
|
||||
return false;
|
||||
|
@ -971,20 +971,30 @@ DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet
|
|||
return Fail(d, "expected export internal index");
|
||||
|
||||
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)))
|
||||
return false;
|
||||
|
||||
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: {
|
||||
uint32_t memoryIndex;
|
||||
if (!d.readVarU32(&memoryIndex))
|
||||
return Fail(d, "expected memory index");
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -680,6 +680,12 @@ ModuleGenerator::numExports() const
|
|||
return metadata_->funcExports.length();
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::addTableExport(UniqueChars fieldName)
|
||||
{
|
||||
return exports_.emplaceBack(Move(fieldName), DefinitionKind::Table);
|
||||
}
|
||||
|
||||
bool
|
||||
ModuleGenerator::addMemoryExport(UniqueChars fieldName)
|
||||
{
|
||||
|
|
|
@ -175,8 +175,9 @@ class MOZ_STACK_CLASS ModuleGenerator
|
|||
// Exports:
|
||||
MOZ_MUST_USE bool declareFuncExport(UniqueChars fieldName, uint32_t funcIndex,
|
||||
uint32_t* funcExportIndex = nullptr);
|
||||
uint32_t numExports() const;
|
||||
MOZ_MUST_USE bool addTableExport(UniqueChars fieldName);
|
||||
MOZ_MUST_USE bool addMemoryExport(UniqueChars fieldName);
|
||||
uint32_t numExports() const;
|
||||
|
||||
// Function definitions:
|
||||
MOZ_MUST_USE bool startFuncDefs();
|
||||
|
|
|
@ -80,6 +80,7 @@ class Instance
|
|||
|
||||
const CodeSegment& codeSegment() const { return *codeSegment_; }
|
||||
const Metadata& metadata() const { return *metadata_; }
|
||||
const SharedTableVector& tables() const { return tables_; }
|
||||
SharedMem<uint8_t*> memoryBase() const;
|
||||
size_t memoryLength() const;
|
||||
|
||||
|
|
|
@ -110,6 +110,8 @@ GetImports(JSContext* cx, HandleObject importObj, const ImportVector& imports,
|
|||
return false;
|
||||
|
||||
break;
|
||||
case DefinitionKind::Table:
|
||||
MOZ_CRASH("NYI");
|
||||
case DefinitionKind::Memory:
|
||||
if (!v.isObject() || !v.toObject().is<WasmMemoryObject>())
|
||||
return Throw(cx, "import object field is not a Memory");
|
||||
|
@ -637,8 +639,10 @@ const JSPropertySpec WasmTableObject::properties[] =
|
|||
{ JS_PS_END };
|
||||
|
||||
/* 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);
|
||||
auto* obj = NewObjectWithGivenProto<WasmTableObject>(cx, proto);
|
||||
if (!obj)
|
||||
|
@ -688,8 +692,7 @@ WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!table)
|
||||
return false;
|
||||
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
|
||||
RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table, proto));
|
||||
RootedWasmTableObject tableObj(cx, WasmTableObject::create(cx, *table));
|
||||
if (!tableObj)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -166,14 +166,13 @@ class WasmTableObject : public NativeObject
|
|||
static const JSPropertySpec properties[];
|
||||
static bool construct(JSContext*, unsigned, Value*);
|
||||
|
||||
static WasmTableObject* create(ExclusiveContext* cx,
|
||||
wasm::Table& table,
|
||||
HandleObject proto);
|
||||
static WasmTableObject* create(JSContext* cx, wasm::Table& table);
|
||||
wasm::Table& table() const;
|
||||
};
|
||||
|
||||
typedef Rooted<WasmTableObject*> RootedWasmTableObject;
|
||||
typedef Handle<WasmTableObject*> HandleWasmTableObject;
|
||||
typedef MutableHandle<WasmTableObject*> MutableHandleWasmTableObject;
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -464,9 +464,12 @@ CreateExportObject(JSContext* cx,
|
|||
HandleWasmInstanceObject instanceObj,
|
||||
HandleWasmMemoryObject memoryObj,
|
||||
const ExportVector& exports,
|
||||
const Metadata& metadata,
|
||||
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) {
|
||||
exportObj.set(NewExportedFunction(cx, instanceObj, 0));
|
||||
return !!exportObj;
|
||||
|
@ -483,6 +486,7 @@ CreateExportObject(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedWasmTableObject tableObj(cx);
|
||||
for (const Export& exp : exports) {
|
||||
JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
|
||||
if (!atom)
|
||||
|
@ -494,6 +498,15 @@ CreateExportObject(JSContext* cx,
|
|||
case DefinitionKind::Function:
|
||||
val = vals[exp.funcExportIndex()];
|
||||
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:
|
||||
if (metadata.assumptions.newFormat)
|
||||
val = ObjectValue(*memoryObj);
|
||||
|
@ -562,7 +575,7 @@ Module::instantiate(JSContext* cx,
|
|||
// Create the export object.
|
||||
|
||||
RootedObject exportObj(cx);
|
||||
if (!CreateExportObject(cx, instanceObj, memory, exports_, *metadata_, &exportObj))
|
||||
if (!CreateExportObject(cx, instanceObj, memory, exports_, &exportObj))
|
||||
return false;
|
||||
|
||||
instanceObj->initExportsObject(exportObj);
|
||||
|
|
|
@ -2485,8 +2485,10 @@ ParseExport(WasmParseContext& c)
|
|||
return new(c.lifo) AstExport(name.text(), AstRef(AstName(), exportee.index()));
|
||||
case WasmToken::Name:
|
||||
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:
|
||||
return new(c.lifo) AstExport(name.text());
|
||||
return new(c.lifo) AstExport(name.text(), DefinitionKind::Memory);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3075,6 +3077,7 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
|
|||
return false;
|
||||
break;
|
||||
case DefinitionKind::Memory:
|
||||
case DefinitionKind::Table:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3554,6 +3557,8 @@ EncodeImport(Encoder& e, bool newFormat, AstImport& imp)
|
|||
if (!e.writeVarU32(imp.funcSig().index()))
|
||||
return false;
|
||||
break;
|
||||
case DefinitionKind::Table:
|
||||
MOZ_CRASH("NYI");
|
||||
case DefinitionKind::Memory:
|
||||
if (!EncodeResizable(e, imp.memory()))
|
||||
return false;
|
||||
|
@ -3651,6 +3656,7 @@ EncodeExport(Encoder& e, bool newFormat, AstExport& exp)
|
|||
if (!e.writeVarU32(exp.func().index()))
|
||||
return false;
|
||||
break;
|
||||
case DefinitionKind::Table:
|
||||
case DefinitionKind::Memory:
|
||||
if (!e.writeVarU32(0))
|
||||
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))');
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /export function index out of range/);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), 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, /exported function index out of bounds/);
|
||||
|
||||
var o = wasmEvalText('(module (func) (export "a" 0) (export "b" 0))');
|
||||
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 (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:
|
||||
|
||||
|
@ -158,6 +159,38 @@ assertEq(Object.keys(e).length, 1);
|
|||
assertEq(String(Object.keys(e)), "");
|
||||
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:
|
||||
|
||||
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.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
|
||||
|
||||
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (memory 1 1))')), TypeError, /already have default memory/);
|
||||
|
|
Загрузка…
Ссылка в новой задаче