зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1284155 - Baldr: add support for same-instance Table imports (r=bbouvier)
MozReview-Commit-ID: DMMtDimNiAt --HG-- extra : rebase_source : dba9107260d5f2f697f95e05258a8a5b76f88faa
This commit is contained in:
Родитель
27473ec09d
Коммит
c7232efb25
|
@ -1677,6 +1677,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||||
importMap_(cx),
|
importMap_(cx),
|
||||||
arrayViews_(cx),
|
arrayViews_(cx),
|
||||||
atomicsPresent_(false),
|
atomicsPresent_(false),
|
||||||
|
mg_(ImportVector()),
|
||||||
errorString_(nullptr),
|
errorString_(nullptr),
|
||||||
errorOffset_(UINT32_MAX),
|
errorOffset_(UINT32_MAX),
|
||||||
errorOverRecursed_(false)
|
errorOverRecursed_(false)
|
||||||
|
@ -2303,17 +2304,13 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||||
uint32_t endAfterCurly = pos.end;
|
uint32_t endAfterCurly = pos.end;
|
||||||
asmJSMetadata_->srcLengthWithRightBrace = endAfterCurly - asmJSMetadata_->srcStart;
|
asmJSMetadata_->srcLengthWithRightBrace = endAfterCurly - asmJSMetadata_->srcStart;
|
||||||
|
|
||||||
// asm.js has its own, different, version of imports through
|
|
||||||
// AsmJSGlobal.
|
|
||||||
ImportVector imports;
|
|
||||||
|
|
||||||
// asm.js does not have any wasm bytecode to save; view-source is
|
// asm.js does not have any wasm bytecode to save; view-source is
|
||||||
// provided through the ScriptSource.
|
// provided through the ScriptSource.
|
||||||
SharedBytes bytes = js_new<ShareableBytes>();
|
SharedBytes bytes = js_new<ShareableBytes>();
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return mg_.finish(Move(imports), *bytes);
|
return mg_.finish(*bytes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -530,15 +530,15 @@ class AstImport : public AstNode
|
||||||
AstImport(AstName name, AstName module, AstName field, AstRef funcSig)
|
AstImport(AstName name, AstName module, AstName field, AstRef funcSig)
|
||||||
: name_(name), module_(module), field_(field), kind_(DefinitionKind::Function), funcSig_(funcSig)
|
: name_(name), module_(module), field_(field), kind_(DefinitionKind::Function), funcSig_(funcSig)
|
||||||
{}
|
{}
|
||||||
AstImport(AstName name, AstName module, AstName field, AstResizable resizable)
|
AstImport(AstName name, AstName module, AstName field, DefinitionKind kind, AstResizable resizable)
|
||||||
: name_(name), module_(module), field_(field), kind_(DefinitionKind::Memory), resizable_(resizable)
|
: name_(name), module_(module), field_(field), kind_(kind), resizable_(resizable)
|
||||||
{}
|
{}
|
||||||
AstName name() const { return name_; }
|
AstName name() const { return name_; }
|
||||||
AstName module() const { return module_; }
|
AstName module() const { return module_; }
|
||||||
AstName field() const { return field_; }
|
AstName field() const { return field_; }
|
||||||
DefinitionKind kind() const { return kind_; }
|
DefinitionKind kind() const { return kind_; }
|
||||||
AstRef& funcSig() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return funcSig_; }
|
AstRef& funcSig() { MOZ_ASSERT(kind_ == DefinitionKind::Function); return funcSig_; }
|
||||||
AstResizable memory() const { MOZ_ASSERT(kind_ == DefinitionKind::Memory); return resizable_; }
|
AstResizable resizable() const { MOZ_ASSERT(kind_ != DefinitionKind::Function); return resizable_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstExport : public AstNode
|
class AstExport : public AstNode
|
||||||
|
|
|
@ -5200,7 +5200,7 @@ BaseCompiler::emitCallIndirect(uint32_t callOffset)
|
||||||
? mg_.tables[mg_.asmJSSigToTableIndex[sigIndex]]
|
? mg_.tables[mg_.asmJSSigToTableIndex[sigIndex]]
|
||||||
: mg_.tables[0];
|
: mg_.tables[0];
|
||||||
|
|
||||||
funcPtrCall(sig, sigIndex, table.length, table.globalDataOffset, callee, baselineCall);
|
funcPtrCall(sig, sigIndex, table.initial, table.globalDataOffset, callee, baselineCall);
|
||||||
|
|
||||||
endCall(baselineCall);
|
endCall(baselineCall);
|
||||||
|
|
||||||
|
|
|
@ -232,10 +232,11 @@ struct TableDesc
|
||||||
{
|
{
|
||||||
TableKind kind;
|
TableKind kind;
|
||||||
uint32_t globalDataOffset;
|
uint32_t globalDataOffset;
|
||||||
uint32_t length;
|
uint32_t initial;
|
||||||
|
uint32_t maximum;
|
||||||
|
|
||||||
TableDesc() : kind(TableKind::AnyFunction), globalDataOffset(0), length(0) {}
|
TableDesc() { PodZero(this); }
|
||||||
explicit TableDesc(TableKind kind) : kind(kind) {}
|
explicit TableDesc(TableKind kind) : kind(kind), globalDataOffset(0), initial(0), maximum(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
WASM_DECLARE_POD_VECTOR(TableDesc, TableDescVector)
|
WASM_DECLARE_POD_VECTOR(TableDesc, TableDescVector)
|
||||||
|
|
|
@ -714,7 +714,8 @@ DecodeResizableTable(Decoder& d, ModuleGeneratorData* init)
|
||||||
return Fail(d, "already have default table");
|
return Fail(d, "already have default table");
|
||||||
|
|
||||||
TableDesc table(TableKind::AnyFunction);
|
TableDesc table(TableKind::AnyFunction);
|
||||||
table.length = resizable.initial;
|
table.initial = resizable.initial;
|
||||||
|
table.maximum = resizable.maximum ? *resizable.maximum : UINT32_MAX;
|
||||||
return init->tables.append(table);
|
return init->tables.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,6 +773,11 @@ DecodeImport(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportVector
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DefinitionKind::Table: {
|
||||||
|
if (!DecodeResizableTable(d, init))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DefinitionKind::Memory: {
|
case DefinitionKind::Memory: {
|
||||||
if (!DecodeResizableMemory(d, init))
|
if (!DecodeResizableMemory(d, init))
|
||||||
return false;
|
return false;
|
||||||
|
@ -825,17 +831,18 @@ DecodeTableSection(Decoder& d, bool newFormat, ModuleGeneratorData* init, Uint32
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
TableDesc table(TableKind::AnyFunction);
|
TableDesc table(TableKind::AnyFunction);
|
||||||
|
table.maximum = UINT32_MAX;
|
||||||
|
|
||||||
if (!d.readVarU32(&table.length))
|
if (!d.readVarU32(&table.initial))
|
||||||
return Fail(d, "expected number of table elems");
|
return Fail(d, "expected number of table elems");
|
||||||
|
|
||||||
if (table.length > MaxTableElems)
|
if (table.initial > MaxTableElems)
|
||||||
return Fail(d, "too many table elements");
|
return Fail(d, "too many table elements");
|
||||||
|
|
||||||
if (!oldElems->resize(table.length))
|
if (!oldElems->resize(table.initial))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < table.length; i++) {
|
for (uint32_t i = 0; i < table.initial; i++) {
|
||||||
uint32_t funcIndex;
|
uint32_t funcIndex;
|
||||||
if (!d.readVarU32(&funcIndex))
|
if (!d.readVarU32(&funcIndex))
|
||||||
return Fail(d, "expected table element");
|
return Fail(d, "expected table element");
|
||||||
|
@ -1214,7 +1221,7 @@ DecodeElemSection(Decoder& d, bool newFormat, Uint32Vector&& oldElems, ModuleGen
|
||||||
if (!d.readVarU32(&numElems))
|
if (!d.readVarU32(&numElems))
|
||||||
return Fail(d, "expected segment size");
|
return Fail(d, "expected segment size");
|
||||||
|
|
||||||
uint32_t tableLength = mg.tables()[seg.tableIndex].length;
|
uint32_t tableLength = mg.tables()[seg.tableIndex].initial;
|
||||||
if (seg.offset > tableLength || tableLength - seg.offset < numElems)
|
if (seg.offset > tableLength || tableLength - seg.offset < numElems)
|
||||||
return Fail(d, "element segment does not fit");
|
return Fail(d, "element segment does not fit");
|
||||||
|
|
||||||
|
@ -1425,7 +1432,7 @@ wasm::Compile(const ShareableBytes& bytecode, CompileArgs&& args, UniqueChars* e
|
||||||
if (!DecodeMemorySection(d, newFormat, init.get(), &memoryExported))
|
if (!DecodeMemorySection(d, newFormat, init.get(), &memoryExported))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ModuleGenerator mg;
|
ModuleGenerator mg(Move(imports));
|
||||||
if (!mg.init(Move(init), Move(args)))
|
if (!mg.init(Move(init), Move(args)))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -1452,5 +1459,5 @@ wasm::Compile(const ShareableBytes& bytecode, CompileArgs&& args, UniqueChars* e
|
||||||
|
|
||||||
MOZ_ASSERT(!*error, "unreported error in decoding");
|
MOZ_ASSERT(!*error, "unreported error in decoding");
|
||||||
|
|
||||||
return mg.finish(Move(imports), bytecode);
|
return mg.finish(bytecode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,9 @@ using mozilla::MakeEnumeratedRange;
|
||||||
static const unsigned GENERATOR_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
|
static const unsigned GENERATOR_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
|
||||||
static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
|
static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
|
||||||
|
|
||||||
ModuleGenerator::ModuleGenerator()
|
ModuleGenerator::ModuleGenerator(ImportVector&& imports)
|
||||||
: alwaysBaseline_(false),
|
: alwaysBaseline_(false),
|
||||||
|
imports_(Move(imports)),
|
||||||
numSigs_(0),
|
numSigs_(0),
|
||||||
numTables_(0),
|
numTables_(0),
|
||||||
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
|
lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
|
||||||
|
@ -51,7 +52,7 @@ ModuleGenerator::ModuleGenerator()
|
||||||
masm_(MacroAssembler::AsmJSToken(), masmAlloc_),
|
masm_(MacroAssembler::AsmJSToken(), masmAlloc_),
|
||||||
lastPatchedCallsite_(0),
|
lastPatchedCallsite_(0),
|
||||||
startOfUnpatchedBranches_(0),
|
startOfUnpatchedBranches_(0),
|
||||||
tableExported_(false),
|
externalTable_(false),
|
||||||
parallel_(false),
|
parallel_(false),
|
||||||
outstanding_(0),
|
outstanding_(0),
|
||||||
activeFunc_(nullptr),
|
activeFunc_(nullptr),
|
||||||
|
@ -59,6 +60,13 @@ ModuleGenerator::ModuleGenerator()
|
||||||
finishedFuncDefs_(false)
|
finishedFuncDefs_(false)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsCompilingAsmJS());
|
MOZ_ASSERT(IsCompilingAsmJS());
|
||||||
|
|
||||||
|
for (const Import& import : imports_) {
|
||||||
|
if (import.kind == DefinitionKind::Table) {
|
||||||
|
externalTable_ = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleGenerator::~ModuleGenerator()
|
ModuleGenerator::~ModuleGenerator()
|
||||||
|
@ -695,7 +703,7 @@ bool
|
||||||
ModuleGenerator::addTableExport(UniqueChars fieldName)
|
ModuleGenerator::addTableExport(UniqueChars fieldName)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(elemSegments_.empty());
|
MOZ_ASSERT(elemSegments_.empty());
|
||||||
tableExported_ = true;
|
externalTable_ = true;
|
||||||
return exports_.emplaceBack(Move(fieldName), DefinitionKind::Table);
|
return exports_.emplaceBack(Move(fieldName), DefinitionKind::Table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,9 +851,9 @@ ModuleGenerator::finishFuncDefs()
|
||||||
bool
|
bool
|
||||||
ModuleGenerator::addElemSegment(ElemSegment&& seg)
|
ModuleGenerator::addElemSegment(ElemSegment&& seg)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(seg.offset + seg.elems.length() <= shared_->tables[seg.tableIndex].length);
|
MOZ_ASSERT(seg.offset + seg.elems.length() <= shared_->tables[seg.tableIndex].initial);
|
||||||
|
|
||||||
if (tableExported_) {
|
if (externalTable_) {
|
||||||
for (uint32_t funcIndex : seg.elems) {
|
for (uint32_t funcIndex : seg.elems) {
|
||||||
if (!exportedFuncs_.put(funcIndex))
|
if (!exportedFuncs_.put(funcIndex))
|
||||||
return false;
|
return false;
|
||||||
|
@ -874,9 +882,10 @@ ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length)
|
||||||
|
|
||||||
TableDesc& table = shared_->tables[numTables_++];
|
TableDesc& table = shared_->tables[numTables_++];
|
||||||
MOZ_ASSERT(table.globalDataOffset == 0);
|
MOZ_ASSERT(table.globalDataOffset == 0);
|
||||||
MOZ_ASSERT(table.length == 0);
|
MOZ_ASSERT(table.initial == 0);
|
||||||
table.kind = TableKind::TypedFunction;
|
table.kind = TableKind::TypedFunction;
|
||||||
table.length = length;
|
table.initial = length;
|
||||||
|
table.maximum = UINT32_MAX;
|
||||||
return allocateGlobalBytes(sizeof(void*), sizeof(void*), &table.globalDataOffset);
|
return allocateGlobalBytes(sizeof(void*), sizeof(void*), &table.globalDataOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,13 +895,13 @@ ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncInd
|
||||||
MOZ_ASSERT(isAsmJS());
|
MOZ_ASSERT(isAsmJS());
|
||||||
|
|
||||||
uint32_t tableIndex = shared_->asmJSSigToTableIndex[sigIndex];
|
uint32_t tableIndex = shared_->asmJSSigToTableIndex[sigIndex];
|
||||||
MOZ_ASSERT(shared_->tables[tableIndex].length == elemFuncIndices.length());
|
MOZ_ASSERT(shared_->tables[tableIndex].initial == elemFuncIndices.length());
|
||||||
|
|
||||||
return elemSegments_.emplaceBack(tableIndex, 0, Move(elemFuncIndices));
|
return elemSegments_.emplaceBack(tableIndex, 0, Move(elemFuncIndices));
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedModule
|
SharedModule
|
||||||
ModuleGenerator::finish(ImportVector&& imports, const ShareableBytes& bytecode)
|
ModuleGenerator::finish(const ShareableBytes& bytecode)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!activeFunc_);
|
MOZ_ASSERT(!activeFunc_);
|
||||||
MOZ_ASSERT(finishedFuncDefs_);
|
MOZ_ASSERT(finishedFuncDefs_);
|
||||||
|
@ -976,7 +985,7 @@ ModuleGenerator::finish(ImportVector&& imports, const ShareableBytes& bytecode)
|
||||||
|
|
||||||
return SharedModule(js_new<Module>(Move(code),
|
return SharedModule(js_new<Module>(Move(code),
|
||||||
Move(linkData_),
|
Move(linkData_),
|
||||||
Move(imports),
|
Move(imports_),
|
||||||
Move(exports_),
|
Move(exports_),
|
||||||
Move(dataSegments_),
|
Move(dataSegments_),
|
||||||
Move(elemSegments_),
|
Move(elemSegments_),
|
||||||
|
|
|
@ -100,6 +100,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
LinkData linkData_;
|
LinkData linkData_;
|
||||||
MutableMetadata metadata_;
|
MutableMetadata metadata_;
|
||||||
ExportVector exports_;
|
ExportVector exports_;
|
||||||
|
ImportVector imports_;
|
||||||
DataSegmentVector dataSegments_;
|
DataSegmentVector dataSegments_;
|
||||||
ElemSegmentVector elemSegments_;
|
ElemSegmentVector elemSegments_;
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
uint32_t lastPatchedCallsite_;
|
uint32_t lastPatchedCallsite_;
|
||||||
uint32_t startOfUnpatchedBranches_;
|
uint32_t startOfUnpatchedBranches_;
|
||||||
JumpSiteArray jumpThunks_;
|
JumpSiteArray jumpThunks_;
|
||||||
bool tableExported_;
|
bool externalTable_;
|
||||||
|
|
||||||
// Parallel compilation
|
// Parallel compilation
|
||||||
bool parallel_;
|
bool parallel_;
|
||||||
|
@ -141,7 +142,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
|
MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ModuleGenerator();
|
explicit ModuleGenerator(ImportVector&& imports);
|
||||||
~ModuleGenerator();
|
~ModuleGenerator();
|
||||||
|
|
||||||
MOZ_MUST_USE bool init(UniqueModuleGeneratorData shared, CompileArgs&& args,
|
MOZ_MUST_USE bool init(UniqueModuleGeneratorData shared, CompileArgs&& args,
|
||||||
|
@ -207,7 +208,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
// Finish compilation, provided the list of imports and source bytecode.
|
// Finish compilation, provided the list of imports and source bytecode.
|
||||||
// Both these Vectors may be empty (viz., b/c asm.js does different things
|
// Both these Vectors may be empty (viz., b/c asm.js does different things
|
||||||
// for imports and source).
|
// for imports and source).
|
||||||
SharedModule finish(ImportVector&& imports, const ShareableBytes& bytecode);
|
SharedModule finish(const ShareableBytes& bytecode);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A FunctionGenerator encapsulates the generation of a single function body.
|
// A FunctionGenerator encapsulates the generation of a single function body.
|
||||||
|
|
|
@ -386,11 +386,6 @@ Instance::Instance(UniqueCodeSegment codeSegment,
|
||||||
|
|
||||||
for (size_t i = 0; i < tables_.length(); i++)
|
for (size_t i = 0; i < tables_.length(); i++)
|
||||||
*addressOfTableBase(i) = tables_[i]->array();
|
*addressOfTableBase(i) = tables_[i]->array();
|
||||||
|
|
||||||
for (SharedTable& table : tables_) {
|
|
||||||
for (size_t i = 0; i < table->length(); i++)
|
|
||||||
table->array()[i] = codeSegment_->badIndirectCallCode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance::~Instance()
|
Instance::~Instance()
|
||||||
|
|
|
@ -1737,7 +1737,7 @@ EmitCallIndirect(FunctionCompiler& f, uint32_t callOffset)
|
||||||
: f.mg().tables[0];
|
: f.mg().tables[0];
|
||||||
|
|
||||||
MDefinition* def;
|
MDefinition* def;
|
||||||
if (!f.funcPtrCall(sigIndex, table.length, table.globalDataOffset, callee, args, &def))
|
if (!f.funcPtrCall(sigIndex, table.initial, table.globalDataOffset, callee, args, &def))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsVoid(sig.ret()))
|
if (IsVoid(sig.ret()))
|
||||||
|
|
|
@ -69,6 +69,13 @@ Throw(JSContext* cx, const char* str)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
Throw(JSContext* cx, unsigned errorNumber, const char* str)
|
||||||
|
{
|
||||||
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, errorNumber, str);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
GetProperty(JSContext* cx, HandleObject obj, const char* chars, MutableHandleValue v)
|
GetProperty(JSContext* cx, HandleObject obj, const char* chars, MutableHandleValue v)
|
||||||
{
|
{
|
||||||
|
@ -98,7 +105,7 @@ GetImports(JSContext* cx,
|
||||||
|
|
||||||
if (strlen(import.func.get()) > 0) {
|
if (strlen(import.func.get()) > 0) {
|
||||||
if (!v.isObject())
|
if (!v.isObject())
|
||||||
return Throw(cx, "import object field is not an Object");
|
return Throw(cx, JSMSG_WASM_BAD_IMPORT_FIELD, "an Object");
|
||||||
|
|
||||||
RootedObject obj(cx, &v.toObject());
|
RootedObject obj(cx, &v.toObject());
|
||||||
if (!GetProperty(cx, obj, import.func.get(), &v))
|
if (!GetProperty(cx, obj, import.func.get(), &v))
|
||||||
|
@ -108,17 +115,22 @@ GetImports(JSContext* cx,
|
||||||
switch (import.kind) {
|
switch (import.kind) {
|
||||||
case DefinitionKind::Function:
|
case DefinitionKind::Function:
|
||||||
if (!IsFunctionObject(v))
|
if (!IsFunctionObject(v))
|
||||||
return Throw(cx, "import object field is not a Function");
|
return Throw(cx, JSMSG_WASM_BAD_IMPORT_FIELD, "a Function");
|
||||||
|
|
||||||
if (!funcImports.append(&v.toObject().as<JSFunction>()))
|
if (!funcImports.append(&v.toObject().as<JSFunction>()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DefinitionKind::Table:
|
case DefinitionKind::Table:
|
||||||
MOZ_CRASH("NYI");
|
if (!v.isObject() || !v.toObject().is<WasmTableObject>())
|
||||||
|
return Throw(cx, JSMSG_WASM_BAD_IMPORT_FIELD, "a Table");
|
||||||
|
|
||||||
|
MOZ_ASSERT(!tableImport);
|
||||||
|
tableImport.set(&v.toObject().as<WasmTableObject>());
|
||||||
|
break;
|
||||||
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, JSMSG_WASM_BAD_IMPORT_FIELD, "a Memory");
|
||||||
|
|
||||||
MOZ_ASSERT(!memoryImport);
|
MOZ_ASSERT(!memoryImport);
|
||||||
memoryImport.set(&v.toObject().as<WasmMemoryObject>());
|
memoryImport.set(&v.toObject().as<WasmMemoryObject>());
|
||||||
|
@ -787,6 +799,11 @@ bool
|
||||||
WasmTableObject::init(JSContext* cx, HandleWasmInstanceObject instanceObj)
|
WasmTableObject::init(JSContext* cx, HandleWasmInstanceObject instanceObj)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!initialized());
|
MOZ_ASSERT(!initialized());
|
||||||
|
MOZ_ASSERT(!table().initialized());
|
||||||
|
|
||||||
|
// Ensure initialization is atomic so that the table is never left in an
|
||||||
|
// inconsistent state (where the Table is initialized but the
|
||||||
|
// WasmTableObject is not).
|
||||||
|
|
||||||
auto instanceVector = MakeUnique<InstanceVector>();
|
auto instanceVector = MakeUnique<InstanceVector>();
|
||||||
if (!instanceVector || !instanceVector->appendN(instanceObj.get(), table().length())) {
|
if (!instanceVector || !instanceVector->appendN(instanceObj.get(), table().length())) {
|
||||||
|
@ -795,8 +812,10 @@ WasmTableObject::init(JSContext* cx, HandleWasmInstanceObject instanceObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
initReservedSlot(INSTANCE_VECTOR_SLOT, PrivateValue(instanceVector.release()));
|
initReservedSlot(INSTANCE_VECTOR_SLOT, PrivateValue(instanceVector.release()));
|
||||||
|
table().init(instanceObj->instance().codeSegment());
|
||||||
|
|
||||||
MOZ_ASSERT(initialized());
|
MOZ_ASSERT(initialized());
|
||||||
|
MOZ_ASSERT(table().initialized());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,10 +996,8 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
|
||||||
MOZ_ASSERT(value == f);
|
MOZ_ASSERT(value == f);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (instanceVector[index] != instanceObj) {
|
if (!tableObj->setInstance(cx, index, instanceObj))
|
||||||
JS_ReportError(cx, "cross-module Table.prototype.set NYI");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Instance& instance = instanceObj->instance();
|
Instance& instance = instanceObj->instance();
|
||||||
const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex);
|
const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex);
|
||||||
|
@ -1020,12 +1037,19 @@ WasmTableObject::instanceVector() const
|
||||||
return *(InstanceVector*)getReservedSlot(INSTANCE_VECTOR_SLOT).toPrivate();
|
return *(InstanceVector*)getReservedSlot(INSTANCE_VECTOR_SLOT).toPrivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
WasmTableObject::setInstance(uint32_t index, HandleWasmInstanceObject instanceObj)
|
WasmTableObject::setInstance(JSContext* cx, uint32_t index, HandleWasmInstanceObject instanceObj)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(initialized());
|
MOZ_ASSERT(initialized());
|
||||||
MOZ_ASSERT(instanceObj->instance().codeSegment().containsCodePC(table().array()[index]));
|
MOZ_ASSERT(instanceObj->instance().codeSegment().containsCodePC(table().array()[index]));
|
||||||
|
|
||||||
|
if (instanceVector()[index] != instanceObj) {
|
||||||
|
JS_ReportError(cx, "cross-module Table import NYI");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
instanceVector()[index] = instanceObj;
|
instanceVector()[index] = instanceObj;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
@ -227,7 +227,7 @@ class WasmTableObject : public NativeObject
|
||||||
// vector.
|
// vector.
|
||||||
|
|
||||||
wasm::Table& table() const;
|
wasm::Table& table() const;
|
||||||
void setInstance(uint32_t index, HandleWasmInstanceObject instanceObj);
|
bool setInstance(JSContext* cx, uint32_t index, HandleWasmInstanceObject instanceObj);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Rooted<WasmTableObject*> RootedWasmTableObject;
|
typedef Rooted<WasmTableObject*> RootedWasmTableObject;
|
||||||
|
|
|
@ -349,26 +349,43 @@ Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
||||||
bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
Module::initElems(HandleWasmInstanceObject instanceObj, HandleWasmTableObject tableObj) const
|
Module::initElems(JSContext* cx, HandleWasmInstanceObject instanceObj,
|
||||||
|
HandleWasmTableObject tableObj) const
|
||||||
{
|
{
|
||||||
Instance& instance = instanceObj->instance();
|
Instance& instance = instanceObj->instance();
|
||||||
const CodeSegment& codeSegment = instance.codeSegment();
|
const CodeSegment& codeSegment = instance.codeSegment();
|
||||||
const SharedTableVector& tables = instance.tables();
|
const SharedTableVector& tables = instance.tables();
|
||||||
|
|
||||||
|
// Initialize tables that have a WasmTableObject first, so that this
|
||||||
|
// initialization can be done atomically.
|
||||||
|
if (tableObj && !tableObj->initialized() && !tableObj->init(cx, instanceObj))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Initialize all remaining Tables that do not have objects.
|
||||||
|
for (const SharedTable& table : tables) {
|
||||||
|
if (!table->initialized())
|
||||||
|
table->init(codeSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that all tables have been initialized, write elements.
|
||||||
for (const ElemSegment& seg : elemSegments_) {
|
for (const ElemSegment& seg : elemSegments_) {
|
||||||
Table& table = *tables[seg.tableIndex];
|
Table& table = *tables[seg.tableIndex];
|
||||||
MOZ_ASSERT(seg.offset + seg.elems.length() <= table.length());
|
MOZ_ASSERT(seg.offset + seg.elems.length() <= table.length());
|
||||||
|
|
||||||
for (uint32_t i = 0; i < seg.elems.length(); i++)
|
|
||||||
table.array()[seg.offset + i] = codeSegment.code() + seg.elems[i];
|
|
||||||
|
|
||||||
if (tableObj) {
|
if (tableObj) {
|
||||||
MOZ_ASSERT(seg.tableIndex == 0);
|
MOZ_ASSERT(seg.tableIndex == 0);
|
||||||
for (uint32_t i = 0; i < seg.elems.length(); i++)
|
for (uint32_t i = 0; i < seg.elems.length(); i++) {
|
||||||
tableObj->setInstance(seg.offset + i, instanceObj);
|
if (!tableObj->setInstance(cx, seg.offset + i, instanceObj))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < seg.elems.length(); i++)
|
||||||
|
table.array()[seg.offset + i] = codeSegment.code() + seg.elems[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// asm.js module instantiation supplies its own buffer, but for wasm, create and
|
// asm.js module instantiation supplies its own buffer, but for wasm, create and
|
||||||
|
@ -388,7 +405,7 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c
|
||||||
buffer = &memory->buffer();
|
buffer = &memory->buffer();
|
||||||
uint32_t length = buffer->byteLength();
|
uint32_t length = buffer->byteLength();
|
||||||
if (length < metadata_->minMemoryLength || length > metadata_->maxMemoryLength) {
|
if (length < metadata_->minMemoryLength || length > metadata_->maxMemoryLength) {
|
||||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_MEM_IMP_SIZE);
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Memory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,12 +448,17 @@ Module::instantiateTable(JSContext* cx, const CodeSegment& codeSegment,
|
||||||
for (const TableDesc& tableDesc : metadata_->tables) {
|
for (const TableDesc& tableDesc : metadata_->tables) {
|
||||||
SharedTable table;
|
SharedTable table;
|
||||||
if (tableImport) {
|
if (tableImport) {
|
||||||
MOZ_CRASH("NYI: table imports");
|
table = &tableImport->table();
|
||||||
|
if (table->length() < tableDesc.initial || table->length() > tableDesc.maximum) {
|
||||||
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, "Table");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
table = Table::create(cx, tableDesc.kind, tableDesc.length);
|
table = Table::create(cx, tableDesc.kind, tableDesc.initial);
|
||||||
if (!table)
|
if (!table)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tables->emplaceBack(table)) {
|
if (!tables->emplaceBack(table)) {
|
||||||
ReportOutOfMemory(cx);
|
ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
|
@ -488,7 +510,7 @@ CreateExportObject(JSContext* cx,
|
||||||
if (!tableObj) {
|
if (!tableObj) {
|
||||||
MOZ_ASSERT(instance.tables().length() == 1);
|
MOZ_ASSERT(instance.tables().length() == 1);
|
||||||
tableObj.set(WasmTableObject::create(cx, *instance.tables()[0]));
|
tableObj.set(WasmTableObject::create(cx, *instance.tables()[0]));
|
||||||
if (!tableObj || !tableObj->init(cx, instanceObj))
|
if (!tableObj)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
val = ObjectValue(*tableObj);
|
val = ObjectValue(*tableObj);
|
||||||
|
@ -581,9 +603,12 @@ Module::instantiate(JSContext* cx,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Initialize table elements only after the instance is fully initialized
|
// Initialize table elements only after the instance is fully initialized
|
||||||
// since the Table object needs to point to a valid instance object.
|
// since the Table object needs to point to a valid instance object. Perform
|
||||||
|
// initialization as the final step after the instance is fully live since
|
||||||
|
// it is observable (in the case of an imported Table object).
|
||||||
|
|
||||||
initElems(instanceObj, table);
|
if (!initElems(cx, instanceObj, table))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Done! Notify the Debugger of the new Instance.
|
// Done! Notify the Debugger of the new Instance.
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,8 @@ class Module : public RefCounted<Module>
|
||||||
bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const;
|
bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const;
|
||||||
bool instantiateTable(JSContext* cx, const CodeSegment& codeSegment,
|
bool instantiateTable(JSContext* cx, const CodeSegment& codeSegment,
|
||||||
HandleWasmTableObject tableImport, SharedTableVector* tables) const;
|
HandleWasmTableObject tableImport, SharedTableVector* tables) const;
|
||||||
void initElems(HandleWasmInstanceObject instanceObj, HandleWasmTableObject tableObj) const;
|
bool initElems(JSContext* cx, HandleWasmInstanceObject instanceObj,
|
||||||
|
HandleWasmTableObject tableObj) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Module(Bytes&& code,
|
Module(Bytes&& code,
|
||||||
|
|
|
@ -24,19 +24,33 @@ using namespace js::wasm;
|
||||||
/* static */ SharedTable
|
/* static */ SharedTable
|
||||||
Table::create(JSContext* cx, TableKind kind, uint32_t length)
|
Table::create(JSContext* cx, TableKind kind, uint32_t length)
|
||||||
{
|
{
|
||||||
SharedTable table = js_new<Table>();
|
SharedTable table = cx->new_<Table>();
|
||||||
if (!table)
|
if (!table)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
table->array_.reset(js_pod_calloc<void*>(length));
|
table->array_.reset(cx->pod_calloc<void*>(length));
|
||||||
if (!table->array_)
|
if (!table->array_)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
table->kind_ = kind;
|
table->kind_ = kind;
|
||||||
table->length_ = length;
|
table->length_ = length;
|
||||||
|
table->initialized_ = false;
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Table::init(const CodeSegment& codeSegment)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!initialized());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < length_; i++) {
|
||||||
|
MOZ_ASSERT(!array_.get()[i]);
|
||||||
|
array_.get()[i] = codeSegment.badIndirectCallCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Table::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
Table::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,14 +33,22 @@ class Table : public ShareableBase<Table>
|
||||||
TableKind kind_;
|
TableKind kind_;
|
||||||
UniquePtr<void*> array_;
|
UniquePtr<void*> array_;
|
||||||
uint32_t length_;
|
uint32_t length_;
|
||||||
|
bool initialized_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static RefPtr<Table> create(JSContext* cx, TableKind kind, uint32_t length);
|
static RefPtr<Table> create(JSContext* cx, TableKind kind, uint32_t length);
|
||||||
|
|
||||||
|
// These accessors may be used before initialization.
|
||||||
|
|
||||||
bool isTypedFunction() const { return kind_ == TableKind::TypedFunction; }
|
bool isTypedFunction() const { return kind_ == TableKind::TypedFunction; }
|
||||||
void** array() const { return array_.get(); }
|
void** array() const { return array_.get(); }
|
||||||
uint32_t length() const { return length_; }
|
uint32_t length() const { return length_; }
|
||||||
|
|
||||||
|
// A Table must be initialized before any dependent instance can execute.
|
||||||
|
|
||||||
|
bool initialized() const { return initialized_; }
|
||||||
|
void init(const CodeSegment& codeSegment);
|
||||||
|
|
||||||
// about:memory reporting:
|
// about:memory reporting:
|
||||||
|
|
||||||
size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const;
|
size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const;
|
||||||
|
|
|
@ -2439,13 +2439,25 @@ ParseImport(WasmParseContext& c, bool newFormat, AstModule* module)
|
||||||
AstRef sigRef;
|
AstRef sigRef;
|
||||||
WasmToken openParen;
|
WasmToken openParen;
|
||||||
if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
|
if (c.ts.getIf(WasmToken::OpenParen, &openParen)) {
|
||||||
if (newFormat && c.ts.getIf(WasmToken::Memory)) {
|
if (newFormat) {
|
||||||
AstResizable memory;
|
if (c.ts.getIf(WasmToken::Memory)) {
|
||||||
if (!ParseResizable(c, &memory))
|
AstResizable memory;
|
||||||
return nullptr;
|
if (!ParseResizable(c, &memory))
|
||||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
return nullptr;
|
||||||
return nullptr;
|
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||||
return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(), memory);
|
return nullptr;
|
||||||
|
return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
|
||||||
|
DefinitionKind::Memory, memory);
|
||||||
|
}
|
||||||
|
if (c.ts.getIf(WasmToken::Table)) {
|
||||||
|
AstResizable table;
|
||||||
|
if (!ParseResizable(c, &table))
|
||||||
|
return nullptr;
|
||||||
|
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||||
|
return nullptr;
|
||||||
|
return new(c.lifo) AstImport(name, moduleName.text(), fieldName.text(),
|
||||||
|
DefinitionKind::Table, table);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.ts.getIf(WasmToken::Type)) {
|
if (c.ts.getIf(WasmToken::Type)) {
|
||||||
|
@ -3558,9 +3570,8 @@ EncodeImport(Encoder& e, bool newFormat, AstImport& imp)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case DefinitionKind::Table:
|
case DefinitionKind::Table:
|
||||||
MOZ_CRASH("NYI");
|
|
||||||
case DefinitionKind::Memory:
|
case DefinitionKind::Memory:
|
||||||
if (!EncodeResizable(e, imp.memory()))
|
if (!EncodeResizable(e, imp.resizable()))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ const mem1Page = new Memory({initial:1});
|
||||||
const mem2Page = new Memory({initial:2});
|
const mem2Page = new Memory({initial:2});
|
||||||
const mem3Page = new Memory({initial:3});
|
const mem3Page = new Memory({initial:3});
|
||||||
const mem4Page = new Memory({initial:4});
|
const mem4Page = new Memory({initial:4});
|
||||||
|
const tab1Elem = new Table({initial:1});
|
||||||
|
const tab2Elem = new Table({initial:2});
|
||||||
|
const tab3Elem = new Table({initial:3});
|
||||||
|
const tab4Elem = new Table({initial:4});
|
||||||
|
|
||||||
// Explicitly opt into the new binary format for imports and exports until it
|
// Explicitly opt into the new binary format for imports and exports until it
|
||||||
// is used by default everywhere.
|
// is used by default everywhere.
|
||||||
|
@ -54,9 +58,22 @@ assertEq(new Instance(m5, {a:{b:mem2Page}}) instanceof Instance, true);
|
||||||
assertEq(new Instance(m5, {a:{b:mem3Page}}) instanceof Instance, true);
|
assertEq(new Instance(m5, {a:{b:mem3Page}}) instanceof Instance, true);
|
||||||
assertEq(new Instance(m5, {a:{b:mem4Page}}) instanceof Instance, true);
|
assertEq(new Instance(m5, {a:{b:mem4Page}}) instanceof Instance, true);
|
||||||
|
|
||||||
|
const m6 = new Module(textToBinary('(module (import "a" "b" (table 2)))'));
|
||||||
|
assertErrorMessage(() => new Instance(m6, {a:{b:tab1Elem}}), TypeError, /imported Table with incompatible size/);
|
||||||
|
assertEq(new Instance(m6, {a:{b:tab2Elem}}) instanceof Instance, true);
|
||||||
|
assertEq(new Instance(m6, {a:{b:tab3Elem}}) instanceof Instance, true);
|
||||||
|
assertEq(new Instance(m6, {a:{b:tab4Elem}}) instanceof Instance, true);
|
||||||
|
|
||||||
|
const m7 = new Module(textToBinary('(module (import "a" "b" (table 2 3)))'));
|
||||||
|
assertErrorMessage(() => new Instance(m7, {a:{b:tab1Elem}}), TypeError, /imported Table with incompatible size/);
|
||||||
|
assertEq(new Instance(m7, {a:{b:tab2Elem}}) instanceof Instance, true);
|
||||||
|
assertEq(new Instance(m7, {a:{b:tab3Elem}}) instanceof Instance, true);
|
||||||
|
assertErrorMessage(() => new Instance(m7, {a:{b:tab4Elem}}), TypeError, /imported Table with incompatible size/);
|
||||||
|
|
||||||
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/);
|
assertErrorMessage(() => new Module(textToBinary('(module (table (resizable 2 1)))')), TypeError, /maximum length less than initial length/);
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (table 2 1)))')), TypeError, /maximum length less than initial length/);
|
||||||
|
|
||||||
// Import order:
|
// Import order:
|
||||||
|
|
||||||
|
@ -241,16 +258,24 @@ 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);
|
||||||
|
|
||||||
|
var code = textToBinary('(module (import "a" "b" (table 1 1)) (export "foo" table) (export "bar" table))');
|
||||||
|
var tbl = new Table({initial:1});
|
||||||
|
var e = new Instance(new Module(code), {a:{b:tbl}}).exports;
|
||||||
|
assertEq(tbl, e.foo);
|
||||||
|
assertEq(tbl, e.bar);
|
||||||
|
|
||||||
// Non-existent export errors
|
// 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" 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" memory))')), TypeError, /exported memory index out of bounds/);
|
||||||
assertErrorMessage(() => new Module(textToBinary('(module (export "a" table))')), TypeError, /exported table index out of bounds/);
|
assertErrorMessage(() => new Module(textToBinary('(module (export "a" table))')), TypeError, /exported table index out of bounds/);
|
||||||
|
|
||||||
// Default memory rules
|
// Default memory/table 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/);
|
||||||
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (import "x" "y" (memory 2 2)))')), TypeError, /already have default memory/);
|
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (memory 1 1)) (import "x" "y" (memory 2 2)))')), TypeError, /already have default memory/);
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (table 1 1)) (table 1 1))')), TypeError, /already have default table/);
|
||||||
|
assertErrorMessage(() => new Module(textToBinary('(module (import "a" "b" (table 1 1)) (import "x" "y" (table 2 2)))')), TypeError, /already have default table/);
|
||||||
|
|
||||||
// Data segments on imports
|
// Data segments on imports
|
||||||
|
|
||||||
|
@ -278,3 +303,25 @@ assertEq(i8[2], 0x0);
|
||||||
assertEq(i8[100], 0xc);
|
assertEq(i8[100], 0xc);
|
||||||
assertEq(i8[101], 0xd);
|
assertEq(i8[101], 0xd);
|
||||||
assertEq(i8[102], 0x0);
|
assertEq(i8[102], 0x0);
|
||||||
|
|
||||||
|
// Elem segments on imports
|
||||||
|
|
||||||
|
var m = new Module(textToBinary(`
|
||||||
|
(module
|
||||||
|
(import "a" "b" (table 10))
|
||||||
|
(elem 0 $one $two)
|
||||||
|
(elem 3 $three $four)
|
||||||
|
(func $one (result i32) (i32.const 1))
|
||||||
|
(func $two (result i32) (i32.const 2))
|
||||||
|
(func $three (result i32) (i32.const 3))
|
||||||
|
(func $four (result i32) (i32.const 4)))
|
||||||
|
`));
|
||||||
|
var tbl = new Table({initial:10});
|
||||||
|
new Instance(m, {a:{b:tbl}});
|
||||||
|
assertEq(tbl.get(0)(), 1);
|
||||||
|
assertEq(tbl.get(1)(), 2);
|
||||||
|
assertEq(tbl.get(2), null);
|
||||||
|
assertEq(tbl.get(3)(), 3);
|
||||||
|
assertEq(tbl.get(4)(), 4);
|
||||||
|
for (var i = 5; i < 10; i++)
|
||||||
|
assertEq(tbl.get(i), null);
|
||||||
|
|
|
@ -53,6 +53,13 @@ assertEq(call(5), 2);
|
||||||
assertErrorMessage(() => call(6), Error, /bad wasm indirect call/);
|
assertErrorMessage(() => call(6), Error, /bad wasm indirect call/);
|
||||||
assertErrorMessage(() => call(10), Error, /out-of-range/);
|
assertErrorMessage(() => call(10), Error, /out-of-range/);
|
||||||
|
|
||||||
|
var tbl = new Table({initial:3});
|
||||||
|
var call = evalText(`(module (import "a" "b" (table 2)) (export "tbl" table) (elem 0 $f0 $f1) ${callee(0)} ${callee(1)} ${caller})`, {a:{b:tbl}}).exports.call;
|
||||||
|
assertEq(call(0), 0);
|
||||||
|
assertEq(call(1), 1);
|
||||||
|
assertEq(tbl.get(0)(), 0);
|
||||||
|
assertEq(tbl.get(1)(), 1);
|
||||||
|
|
||||||
// A table should not hold exported functions alive and exported functions
|
// A table should not hold exported functions alive and exported functions
|
||||||
// should not hold their originating table alive. Live exported functions should
|
// should not hold their originating table alive. Live exported functions should
|
||||||
// hold instances alive. Nothing should hold the export object alive.
|
// hold instances alive. Nothing should hold the export object alive.
|
||||||
|
|
|
@ -348,9 +348,10 @@ MSG_DEF(JSMSG_WASM_BAD_IND_CALL, 0, JSEXN_ERR, "bad wasm indirect
|
||||||
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object")
|
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module")
|
MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor")
|
MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_MEM_IMP_SIZE, 0, JSEXN_TYPEERR, "imported Memory with incompatible size")
|
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_TYPEERR, "imported {0} with incompatible size")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_SIZE, 2, JSEXN_TYPEERR, "bad {0} {1} size")
|
MSG_DEF(JSMSG_WASM_BAD_SIZE, 2, JSEXN_TYPEERR, "bad {0} {1} size")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object")
|
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object")
|
||||||
|
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object field is not {0}")
|
||||||
MSG_DEF(JSMSG_WASM_BAD_SET_VALUE, 0, JSEXN_TYPEERR, "second argument must be null or an exported WebAssembly Function object")
|
MSG_DEF(JSMSG_WASM_BAD_SET_VALUE, 0, JSEXN_TYPEERR, "second argument must be null or an exported WebAssembly Function object")
|
||||||
MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_ERR, "unreachable executed")
|
MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_ERR, "unreachable executed")
|
||||||
MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_ERR, "integer overflow")
|
MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_ERR, "integer overflow")
|
||||||
|
|
Загрузка…
Ссылка в новой задаче