зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1284155 - Baldr: add 'newFormat' binary encoding flag (r=sunfish)
MozReview-Commit-ID: JvHGfetLQjT
This commit is contained in:
Родитель
d28873f5c8
Коммит
fbeece22fc
|
@ -520,23 +520,21 @@ class AstImport : public AstNode
|
|||
AstRef& sig() { return sig_; }
|
||||
};
|
||||
|
||||
enum class AstExportKind { Func, Memory };
|
||||
|
||||
class AstExport : public AstNode
|
||||
{
|
||||
AstName name_;
|
||||
AstExportKind kind_;
|
||||
DefinitionKind kind_;
|
||||
AstRef func_;
|
||||
|
||||
public:
|
||||
AstExport(AstName name, AstRef func)
|
||||
: name_(name), kind_(AstExportKind::Func), func_(func)
|
||||
: name_(name), kind_(DefinitionKind::Function), func_(func)
|
||||
{}
|
||||
explicit AstExport(AstName name)
|
||||
: name_(name), kind_(AstExportKind::Memory)
|
||||
: name_(name), kind_(DefinitionKind::Memory)
|
||||
{}
|
||||
AstName name() const { return name_; }
|
||||
AstExportKind kind() const { return kind_; }
|
||||
DefinitionKind kind() const { return kind_; }
|
||||
AstRef& func() { return func_; }
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,12 @@ enum class TypeConstructor
|
|||
Function = 0x40
|
||||
};
|
||||
|
||||
enum class DefinitionKind
|
||||
{
|
||||
Function = 0x00,
|
||||
Memory = 0x01
|
||||
};
|
||||
|
||||
enum class Expr
|
||||
{
|
||||
// Control flow operators
|
||||
|
|
|
@ -1494,7 +1494,7 @@ PrintExport(WasmPrintContext& c, AstExport& export_, const AstModule::FuncVector
|
|||
return false;
|
||||
if (!c.buffer.append("export "))
|
||||
return false;
|
||||
if (export_.kind() == AstExportKind::Memory) {
|
||||
if (export_.kind() == DefinitionKind::Memory) {
|
||||
if (!c.buffer.append("memory"))
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -1171,7 +1171,7 @@ RenderExport(WasmRenderContext& c, AstExport& export_, const AstModule::FuncVect
|
|||
return false;
|
||||
if (!c.buffer.append("\" "))
|
||||
return false;
|
||||
if (export_.kind() == AstExportKind::Memory) {
|
||||
if (export_.kind() == DefinitionKind::Memory) {
|
||||
if (!c.buffer.append("memory"))
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -668,17 +668,32 @@ MaybeDecodeName(Decoder& d)
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeImport(Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
|
||||
DecodeImport(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportNameVector* importNames)
|
||||
{
|
||||
const DeclaredSig* sig = nullptr;
|
||||
if (!DecodeSignatureIndex(d, *init, &sig))
|
||||
return false;
|
||||
if (!newFormat) {
|
||||
const DeclaredSig* sig = nullptr;
|
||||
if (!DecodeSignatureIndex(d, *init, &sig))
|
||||
return false;
|
||||
|
||||
if (!init->imports.emplaceBack(sig))
|
||||
return false;
|
||||
if (!CheckTypeForJS(d, *sig))
|
||||
return false;
|
||||
|
||||
if (!CheckTypeForJS(d, *sig))
|
||||
return false;
|
||||
if (!init->imports.emplaceBack(sig))
|
||||
return false;
|
||||
|
||||
UniqueChars moduleName = MaybeDecodeName(d);
|
||||
if (!moduleName)
|
||||
return Fail(d, "expected valid import module name");
|
||||
|
||||
if (!strlen(moduleName.get()))
|
||||
return Fail(d, "module name cannot be empty");
|
||||
|
||||
UniqueChars funcName = MaybeDecodeName(d);
|
||||
if (!funcName)
|
||||
return Fail(d, "expected valid import func name");
|
||||
|
||||
return importNames->emplaceBack(Move(moduleName), Move(funcName));
|
||||
}
|
||||
|
||||
UniqueChars moduleName = MaybeDecodeName(d);
|
||||
if (!moduleName)
|
||||
|
@ -691,11 +706,33 @@ DecodeImport(Decoder& d, ModuleGeneratorData* init, ImportNameVector* importName
|
|||
if (!funcName)
|
||||
return Fail(d, "expected valid import func name");
|
||||
|
||||
return importNames->emplaceBack(Move(moduleName), Move(funcName));
|
||||
if (!importNames->emplaceBack(Move(moduleName), Move(funcName)))
|
||||
return false;
|
||||
|
||||
uint32_t importKind;
|
||||
if (!d.readVarU32(&importKind))
|
||||
return Fail(d, "failed to read import kind");
|
||||
|
||||
switch (DefinitionKind(importKind)) {
|
||||
case DefinitionKind::Function: {
|
||||
const DeclaredSig* sig = nullptr;
|
||||
if (!DecodeSignatureIndex(d, *init, &sig))
|
||||
return false;
|
||||
if (!CheckTypeForJS(d, *sig))
|
||||
return false;
|
||||
if (!init->imports.emplaceBack(sig))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return Fail(d, "unsupported import kind");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeImportSection(Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
|
||||
DecodeImportSection(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportNameVector* importNames)
|
||||
{
|
||||
uint32_t sectionStart, sectionSize;
|
||||
if (!d.startSection(ImportSectionId, §ionStart, §ionSize))
|
||||
|
@ -711,7 +748,7 @@ DecodeImportSection(Decoder& d, ModuleGeneratorData* init, ImportNameVector* imp
|
|||
return Fail(d, "too many imports");
|
||||
|
||||
for (uint32_t i = 0; i < numImports; i++) {
|
||||
if (!DecodeImport(d, init, importNames))
|
||||
if (!DecodeImport(d, newFormat, init, importNames))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -722,7 +759,7 @@ DecodeImportSection(Decoder& d, ModuleGeneratorData* init, ImportNameVector* imp
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeMemorySection(Decoder& d, ModuleGenerator& mg)
|
||||
DecodeMemorySection(Decoder& d, bool newFormat, ModuleGenerator& mg)
|
||||
{
|
||||
uint32_t sectionStart, sectionSize;
|
||||
if (!d.startSection(MemorySectionId, §ionStart, §ionSize))
|
||||
|
@ -755,14 +792,16 @@ DecodeMemorySection(Decoder& d, ModuleGenerator& mg)
|
|||
if (maxSize.value() < initialSize.value())
|
||||
return Fail(d, "maximum memory size less than initial memory size");
|
||||
|
||||
uint8_t exported;
|
||||
if (!d.readFixedU8(&exported))
|
||||
return Fail(d, "expected exported byte");
|
||||
if (!newFormat) {
|
||||
uint8_t exported;
|
||||
if (!d.readFixedU8(&exported))
|
||||
return Fail(d, "expected exported byte");
|
||||
|
||||
if (exported) {
|
||||
UniqueChars fieldName = DuplicateString("memory");
|
||||
if (!fieldName || !mg.addMemoryExport(Move(fieldName)))
|
||||
return false;
|
||||
if (exported) {
|
||||
UniqueChars fieldName = DuplicateString("memory");
|
||||
if (!fieldName || !mg.addMemoryExport(Move(fieldName)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!d.finishSection(sectionStart, sectionSize))
|
||||
|
@ -796,27 +835,67 @@ DecodeExportName(Decoder& d, CStringSet* dupSet)
|
|||
}
|
||||
|
||||
static bool
|
||||
DecodeFunctionExport(Decoder& d, ModuleGenerator& mg, CStringSet* dupSet)
|
||||
DecodeExport(Decoder& d, bool newFormat, ModuleGenerator& mg, CStringSet* dupSet)
|
||||
{
|
||||
uint32_t funcIndex;
|
||||
if (!d.readVarU32(&funcIndex))
|
||||
return Fail(d, "expected export internal index");
|
||||
if (!newFormat) {
|
||||
uint32_t funcIndex;
|
||||
if (!d.readVarU32(&funcIndex))
|
||||
return Fail(d, "expected export internal index");
|
||||
|
||||
if (funcIndex >= mg.numFuncSigs())
|
||||
return Fail(d, "export function index out of range");
|
||||
if (funcIndex >= mg.numFuncSigs())
|
||||
return Fail(d, "export function index out of range");
|
||||
|
||||
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
||||
return false;
|
||||
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
||||
return false;
|
||||
|
||||
UniqueChars fieldName = DecodeExportName(d, dupSet);
|
||||
if (!fieldName)
|
||||
return false;
|
||||
|
||||
return mg.declareExport(Move(fieldName), funcIndex);
|
||||
}
|
||||
|
||||
UniqueChars fieldName = DecodeExportName(d, dupSet);
|
||||
if (!fieldName)
|
||||
return false;
|
||||
|
||||
return mg.declareExport(Move(fieldName), funcIndex);
|
||||
uint32_t exportKind;
|
||||
if (!d.readVarU32(&exportKind))
|
||||
return Fail(d, "failed to read export kind");
|
||||
|
||||
switch (DefinitionKind(exportKind)) {
|
||||
case DefinitionKind::Function: {
|
||||
uint32_t funcIndex;
|
||||
if (!d.readVarU32(&funcIndex))
|
||||
return Fail(d, "expected export internal index");
|
||||
|
||||
if (funcIndex >= mg.numFuncSigs())
|
||||
return Fail(d, "export function index out of range");
|
||||
|
||||
if (!CheckTypeForJS(d, mg.funcSig(funcIndex)))
|
||||
return false;
|
||||
|
||||
return mg.declareExport(Move(fieldName), funcIndex);
|
||||
}
|
||||
case DefinitionKind::Memory: {
|
||||
uint32_t memoryIndex;
|
||||
if (!d.readVarU32(&memoryIndex))
|
||||
return Fail(d, "expected memory index");
|
||||
|
||||
if (memoryIndex > 0)
|
||||
return Fail(d, "memory index out of bounds");
|
||||
|
||||
return mg.addMemoryExport(Move(fieldName));
|
||||
}
|
||||
default:
|
||||
return Fail(d, "unexpected export kind");
|
||||
}
|
||||
|
||||
MOZ_CRASH("unreachable");
|
||||
}
|
||||
|
||||
static bool
|
||||
DecodeExportSection(Decoder& d, ModuleGenerator& mg)
|
||||
DecodeExportSection(Decoder& d, bool newFormat, ModuleGenerator& mg)
|
||||
{
|
||||
uint32_t sectionStart, sectionSize;
|
||||
if (!d.startSection(ExportSectionId, §ionStart, §ionSize))
|
||||
|
@ -836,7 +915,7 @@ DecodeExportSection(Decoder& d, ModuleGenerator& mg)
|
|||
return Fail(d, "too many exports");
|
||||
|
||||
for (uint32_t i = 0; i < numExports; i++) {
|
||||
if (!DecodeFunctionExport(d, mg, &dupSet))
|
||||
if (!DecodeExport(d, newFormat, mg, &dupSet))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1074,6 +1153,8 @@ CompileArgs::init(ExclusiveContext* cx)
|
|||
UniqueModule
|
||||
wasm::Compile(Bytes&& bytecode, CompileArgs&& args, UniqueChars* error)
|
||||
{
|
||||
bool newFormat = args.assumptions.newFormat;
|
||||
|
||||
auto init = js::MakeUnique<ModuleGeneratorData>(args.assumptions.usesSignal);
|
||||
if (!init)
|
||||
return nullptr;
|
||||
|
@ -1087,7 +1168,7 @@ wasm::Compile(Bytes&& bytecode, CompileArgs&& args, UniqueChars* error)
|
|||
return nullptr;
|
||||
|
||||
ImportNameVector importNames;
|
||||
if (!DecodeImportSection(d, init.get(), &importNames))
|
||||
if (!DecodeImportSection(d, newFormat, init.get(), &importNames))
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeFunctionSection(d, init.get()))
|
||||
|
@ -1100,10 +1181,10 @@ wasm::Compile(Bytes&& bytecode, CompileArgs&& args, UniqueChars* error)
|
|||
if (!mg.init(Move(init), Move(args)))
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeMemorySection(d, mg))
|
||||
if (!DecodeMemorySection(d, newFormat, mg))
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeExportSection(d, mg))
|
||||
if (!DecodeExportSection(d, newFormat, mg))
|
||||
return nullptr;
|
||||
|
||||
if (!DecodeCodeSection(d, mg))
|
||||
|
|
|
@ -324,6 +324,8 @@ ModuleConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!compileArgs.init(cx))
|
||||
return true;
|
||||
|
||||
compileArgs.assumptions.newFormat = true;
|
||||
|
||||
JS::AutoFilename af;
|
||||
if (DescribeScriptedCaller(cx, &af)) {
|
||||
compileArgs.filename = DuplicateString(cx, af.get());
|
||||
|
|
|
@ -2433,10 +2433,6 @@ ParseExport(WasmParseContext& c)
|
|||
case WasmToken::Name:
|
||||
return new(c.lifo) AstExport(name.text(), AstRef(exportee.name(), AstNoIndex));
|
||||
case WasmToken::Memory:
|
||||
if (name.text() != AstName(MOZ_UTF16("memory"), 6)) {
|
||||
c.ts.generateError(exportee, c.error);
|
||||
return nullptr;
|
||||
}
|
||||
return new(c.lifo) AstExport(name.text());
|
||||
default:
|
||||
break;
|
||||
|
@ -2978,7 +2974,7 @@ ResolveModule(LifoAlloc& lifo, AstModule* module, UniqueChars* error)
|
|||
}
|
||||
|
||||
for (AstExport* export_ : module->exports()) {
|
||||
if (export_->kind() != AstExportKind::Func)
|
||||
if (export_->kind() != DefinitionKind::Function)
|
||||
continue;
|
||||
if (!r.resolveFunction(export_->func()))
|
||||
return false;
|
||||
|
@ -3397,10 +3393,20 @@ EncodeBytes(Encoder& e, AstName wasmName)
|
|||
}
|
||||
|
||||
static bool
|
||||
EncodeImport(Encoder& e, AstImport& imp)
|
||||
EncodeImport(Encoder& e, bool newFormat, AstImport& imp)
|
||||
{
|
||||
if (!e.writeVarU32(imp.sig().index()))
|
||||
return false;
|
||||
if (!newFormat) {
|
||||
if (!e.writeVarU32(imp.sig().index()))
|
||||
return false;
|
||||
|
||||
if (!EncodeBytes(e, imp.module()))
|
||||
return false;
|
||||
|
||||
if (!EncodeBytes(e, imp.func()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!EncodeBytes(e, imp.module()))
|
||||
return false;
|
||||
|
@ -3408,11 +3414,17 @@ EncodeImport(Encoder& e, AstImport& imp)
|
|||
if (!EncodeBytes(e, imp.func()))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(uint32_t(DefinitionKind::Function)))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(imp.sig().index()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeImportSection(Encoder& e, AstModule& module)
|
||||
EncodeImportSection(Encoder& e, bool newFormat, AstModule& module)
|
||||
{
|
||||
if (module.imports().empty())
|
||||
return true;
|
||||
|
@ -3425,7 +3437,7 @@ EncodeImportSection(Encoder& e, AstModule& module)
|
|||
return false;
|
||||
|
||||
for (AstImport* imp : module.imports()) {
|
||||
if (!EncodeImport(e, *imp))
|
||||
if (!EncodeImport(e, newFormat, *imp))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3434,7 +3446,7 @@ EncodeImportSection(Encoder& e, AstModule& module)
|
|||
}
|
||||
|
||||
static bool
|
||||
EncodeMemorySection(Encoder& e, AstModule& module)
|
||||
EncodeMemorySection(Encoder& e, bool newFormat, AstModule& module)
|
||||
{
|
||||
if (!module.maybeMemory())
|
||||
return true;
|
||||
|
@ -3452,61 +3464,85 @@ EncodeMemorySection(Encoder& e, AstModule& module)
|
|||
if (!e.writeVarU32(maxSize))
|
||||
return false;
|
||||
|
||||
uint8_t exported = 0;
|
||||
for (AstExport* exp : module.exports()) {
|
||||
if (exp->kind() == AstExportKind::Memory) {
|
||||
exported = 1;
|
||||
break;
|
||||
if (!newFormat) {
|
||||
uint8_t exported = 0;
|
||||
for (AstExport* exp : module.exports()) {
|
||||
if (exp->kind() == DefinitionKind::Memory) {
|
||||
exported = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!e.writeFixedU8(exported))
|
||||
return false;
|
||||
if (!e.writeFixedU8(exported))
|
||||
return false;
|
||||
}
|
||||
|
||||
e.finishSection(offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeFunctionExport(Encoder& e, AstExport& exp)
|
||||
EncodeExport(Encoder& e, bool newFormat, AstExport& exp)
|
||||
{
|
||||
if (!e.writeVarU32(exp.func().index()))
|
||||
return false;
|
||||
if (!newFormat) {
|
||||
if (exp.kind() != DefinitionKind::Function)
|
||||
return true;
|
||||
|
||||
if (!e.writeVarU32(exp.func().index()))
|
||||
return false;
|
||||
|
||||
if (!EncodeBytes(e, exp.name()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!EncodeBytes(e, exp.name()))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(uint32_t(exp.kind())))
|
||||
return false;
|
||||
|
||||
switch (exp.kind()) {
|
||||
case DefinitionKind::Function:
|
||||
if (!e.writeVarU32(exp.func().index()))
|
||||
return false;
|
||||
break;
|
||||
case DefinitionKind::Memory:
|
||||
if (!e.writeVarU32(0))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeExportSection(Encoder& e, AstModule& module)
|
||||
EncodeExportSection(Encoder& e, bool newFormat, AstModule& module)
|
||||
{
|
||||
uint32_t numFuncExports = 0;
|
||||
for (AstExport* exp : module.exports()) {
|
||||
if (exp->kind() == AstExportKind::Func)
|
||||
numFuncExports++;
|
||||
uint32_t numExports = 0;
|
||||
if (newFormat) {
|
||||
numExports = module.exports().length();
|
||||
} else {
|
||||
for (AstExport* exp : module.exports()) {
|
||||
if (exp->kind() == DefinitionKind::Function)
|
||||
numExports++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!numFuncExports)
|
||||
if (!numExports)
|
||||
return true;
|
||||
|
||||
size_t offset;
|
||||
if (!e.startSection(ExportSectionId, &offset))
|
||||
return false;
|
||||
|
||||
if (!e.writeVarU32(numFuncExports))
|
||||
if (!e.writeVarU32(numExports))
|
||||
return false;
|
||||
|
||||
for (AstExport* exp : module.exports()) {
|
||||
switch (exp->kind()) {
|
||||
case AstExportKind::Func:
|
||||
if (!EncodeFunctionExport(e, *exp))
|
||||
return false;
|
||||
break;
|
||||
case AstExportKind::Memory:
|
||||
continue;
|
||||
}
|
||||
if (!EncodeExport(e, newFormat, *exp))
|
||||
return false;
|
||||
}
|
||||
|
||||
e.finishSection(offset);
|
||||
|
@ -3632,7 +3668,7 @@ EncodeDataSection(Encoder& e, AstModule& module)
|
|||
}
|
||||
|
||||
static bool
|
||||
EncodeModule(AstModule& module, Bytes* bytes)
|
||||
EncodeModule(AstModule& module, bool newFormat, Bytes* bytes)
|
||||
{
|
||||
Encoder e(*bytes);
|
||||
|
||||
|
@ -3645,7 +3681,7 @@ EncodeModule(AstModule& module, Bytes* bytes)
|
|||
if (!EncodeTypeSection(e, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeImportSection(e, module))
|
||||
if (!EncodeImportSection(e, newFormat, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeFunctionSection(e, module))
|
||||
|
@ -3654,10 +3690,10 @@ EncodeModule(AstModule& module, Bytes* bytes)
|
|||
if (!EncodeTableSection(e, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeMemorySection(e, module))
|
||||
if (!EncodeMemorySection(e, newFormat, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeExportSection(e, module))
|
||||
if (!EncodeExportSection(e, newFormat, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeCodeSection(e, module))
|
||||
|
@ -3672,7 +3708,7 @@ EncodeModule(AstModule& module, Bytes* bytes)
|
|||
/*****************************************************************************/
|
||||
|
||||
bool
|
||||
wasm::TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error)
|
||||
wasm::TextToBinary(const char16_t* text, bool newFormat, Bytes* bytes, UniqueChars* error)
|
||||
{
|
||||
LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
AstModule* module = ParseModule(text, lifo, error);
|
||||
|
@ -3682,5 +3718,5 @@ wasm::TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error)
|
|||
if (!ResolveModule(lifo, module, error))
|
||||
return false;
|
||||
|
||||
return EncodeModule(*module, bytes);
|
||||
return EncodeModule(*module, newFormat, bytes);
|
||||
}
|
||||
|
|
|
@ -28,9 +28,12 @@ namespace wasm {
|
|||
// Translate the textual representation of a wasm module (given by a
|
||||
// null-terminated char16_t array) into serialized bytes. If there is an error
|
||||
// other than out-of-memory an error message string will be stored in 'error'.
|
||||
// The 'newFormat' argument is transitional and enables the new binary
|
||||
// format for memory and table imports and exports so that tests can be written
|
||||
// before the transition is complete.
|
||||
|
||||
extern MOZ_MUST_USE bool
|
||||
TextToBinary(const char16_t* text, Bytes* bytes, UniqueChars* error);
|
||||
TextToBinary(const char16_t* text, bool newFormat, Bytes* bytes, UniqueChars* error);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -349,7 +349,8 @@ Assumptions::operator==(const Assumptions& rhs) const
|
|||
return usesSignal == rhs.usesSignal &&
|
||||
cpuId == rhs.cpuId &&
|
||||
buildId.length() == rhs.buildId.length() &&
|
||||
PodEqual(buildId.begin(), rhs.buildId.begin(), buildId.length());
|
||||
PodEqual(buildId.begin(), rhs.buildId.begin(), buildId.length()) &&
|
||||
newFormat == rhs.newFormat;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -357,7 +358,8 @@ Assumptions::serializedSize() const
|
|||
{
|
||||
return sizeof(usesSignal) +
|
||||
sizeof(uint32_t) +
|
||||
SerializedPodVectorSize(buildId);
|
||||
SerializedPodVectorSize(buildId) +
|
||||
sizeof(bool);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
|
@ -366,6 +368,7 @@ Assumptions::serialize(uint8_t* cursor) const
|
|||
cursor = WriteBytes(cursor, &usesSignal, sizeof(usesSignal));
|
||||
cursor = WriteScalar<uint32_t>(cursor, cpuId);
|
||||
cursor = SerializePodVector(cursor, buildId);
|
||||
cursor = WriteScalar<bool>(cursor, newFormat);
|
||||
return cursor;
|
||||
}
|
||||
|
||||
|
@ -374,7 +377,8 @@ Assumptions::deserialize(const uint8_t* cursor)
|
|||
{
|
||||
(cursor = ReadBytes(cursor, &usesSignal, sizeof(usesSignal))) &&
|
||||
(cursor = ReadScalar<uint32_t>(cursor, &cpuId)) &&
|
||||
(cursor = DeserializePodVector(cursor, &buildId));
|
||||
(cursor = DeserializePodVector(cursor, &buildId)) &&
|
||||
(cursor = ReadScalar<bool>(cursor, &newFormat));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
|
|
|
@ -794,7 +794,9 @@ struct Assumptions
|
|||
SignalUsage usesSignal;
|
||||
uint32_t cpuId;
|
||||
JS::BuildIdCharVector buildId;
|
||||
bool newFormat;
|
||||
|
||||
Assumptions() : cpuId(0), newFormat(false) {}
|
||||
MOZ_MUST_USE bool init(SignalUsage usesSignal, JS::BuildIdOp buildIdOp);
|
||||
|
||||
bool operator==(const Assumptions& rhs) const;
|
||||
|
|
|
@ -517,10 +517,8 @@ WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
|
|||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject callee(cx, &args.callee());
|
||||
|
||||
if (args.length() != 1) {
|
||||
ReportUsageError(cx, callee, "Wrong number of arguments");
|
||||
if (!args.requireAtLeast(cx, "wasmTextToBinary", 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args[0].isString()) {
|
||||
ReportUsageError(cx, callee, "First argument must be a String");
|
||||
|
@ -531,9 +529,28 @@ WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!twoByteChars.initTwoByte(cx, args[0].toString()))
|
||||
return false;
|
||||
|
||||
bool newFormat = false;
|
||||
if (args.hasDefined(1)) {
|
||||
if (!args[1].isString()) {
|
||||
ReportUsageError(cx, callee, "Second argument, if present, must be a String");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSLinearString* str = args[1].toString()->ensureLinear(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
if (!StringEqualsAscii(str, "new-format")) {
|
||||
ReportUsageError(cx, callee, "Unknown string value for second argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
newFormat = true;
|
||||
}
|
||||
|
||||
wasm::Bytes bytes;
|
||||
UniqueChars error;
|
||||
if (!wasm::TextToBinary(twoByteChars.twoByteChars(), &bytes, &error)) {
|
||||
if (!wasm::TextToBinary(twoByteChars.twoByteChars(), newFormat, &bytes, &error)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
|
||||
error.get() ? error.get() : "out of memory");
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
load(libdir + 'wasm.js');
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
const Module = WebAssembly.Module;
|
||||
const Instance = WebAssembly.Instance;
|
||||
|
||||
// Explicitly opt into the new binary format for imports and exports until it
|
||||
// is used by default everywhere.
|
||||
const textToBinary = str => wasmTextToBinary(str, 'new-format');
|
||||
|
||||
const m1 = new Module(textToBinary('(module (import "foo" "bar") (import "baz" "quux"))'));
|
||||
assertErrorMessage(() => new Instance(m1), TypeError, /no import object given/);
|
||||
|
||||
// Import order:
|
||||
|
||||
var arr = [];
|
||||
var importObj = {
|
||||
get foo() { arr.push("foo") },
|
||||
get baz() { arr.push("bad") },
|
||||
};
|
||||
assertErrorMessage(() => new Instance(m1, importObj), TypeError, /import object field is not an Object/);
|
||||
assertEq(arr.join(), "foo");
|
||||
|
||||
var arr = [];
|
||||
var importObj = {
|
||||
get foo() {
|
||||
arr.push("foo");
|
||||
return { get bar() { arr.push("bar"); return null } }
|
||||
},
|
||||
get baz() { arr.push("bad") },
|
||||
};
|
||||
assertErrorMessage(() => new Instance(m1, importObj), TypeError, /import object field is not a Function/);
|
||||
assertEq(arr.join(), "foo,bar");
|
||||
|
||||
var arr = [];
|
||||
var importObj = {
|
||||
get foo() {
|
||||
arr.push("foo");
|
||||
return { get bar() { arr.push("bar"); return () => arr.push("bad") } }
|
||||
},
|
||||
get baz() {
|
||||
arr.push("baz");
|
||||
return { get quux() { arr.push("quux"); return () => arr.push("bad") } }
|
||||
}
|
||||
};
|
||||
assertEq(new Instance(m1, importObj) instanceof Instance, true);
|
||||
assertEq(arr.join(), "foo,bar,baz,quux");
|
||||
|
||||
// Export key order:
|
||||
|
||||
var code = textToBinary('(module)');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).length, 0);
|
||||
|
||||
var code = textToBinary('(module (func) (export "foo" 0))');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).join(), "foo");
|
||||
assertEq(e.foo(), undefined);
|
||||
|
||||
var code = textToBinary('(module (func) (export "foo" 0) (export "bar" 0))');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).join(), "foo,bar");
|
||||
assertEq(e.foo(), undefined);
|
||||
assertEq(e.bar(), undefined);
|
||||
assertEq(e.foo, e.bar);
|
||||
|
||||
var code = textToBinary('(module (memory 1 1) (export "memory" memory))');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).join(), "memory");
|
||||
|
||||
var code = textToBinary('(module (memory 1 1) (export "foo" memory) (export "bar" memory))');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).join(), "foo,bar");
|
||||
assertEq(e.foo, e.bar);
|
|
@ -1,7 +1,11 @@
|
|||
load(libdir + 'wasm.js');
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
const emptyModule = wasmTextToBinary('(module)');
|
||||
// Explicitly opt into the new binary format for imports and exports until it
|
||||
// is used by default everywhere.
|
||||
const textToBinary = str => wasmTextToBinary(str, 'new-format');
|
||||
|
||||
const emptyModule = textToBinary('(module)');
|
||||
|
||||
// 'WebAssembly' property on global object
|
||||
const wasmDesc = Object.getOwnPropertyDescriptor(this, 'WebAssembly');
|
||||
|
@ -98,23 +102,4 @@ assertEq(exportsDesc.writable, true);
|
|||
assertEq(exportsDesc.enumerable, true);
|
||||
assertEq(exportsDesc.configurable, true);
|
||||
|
||||
// Exports object:
|
||||
// Note: at some point the exports object should become an ES6 module namespace
|
||||
// exotic object. For now, don't probe too hard on the property descriptors or
|
||||
// the exports object itself.
|
||||
|
||||
const e1 = i1.exports;
|
||||
assertEq(e1, exportsDesc.value);
|
||||
assertEq(Object.keys(e1).length, 0);
|
||||
|
||||
var code = wasmTextToBinary('(module (func) (export "foo" 0))');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).join(), "foo");
|
||||
assertEq(e.foo(), undefined);
|
||||
|
||||
var code = wasmTextToBinary('(module (func) (export "foo" 0) (export "bar" 0))');
|
||||
var e = new Instance(new Module(code)).exports;
|
||||
assertEq(Object.keys(e).join(), "foo,bar");
|
||||
assertEq(e.foo(), undefined);
|
||||
assertEq(e.bar(), undefined);
|
||||
assertEq(e.foo, e.bar);
|
||||
// TODO: test export object objects are ES6 module namespace objects.
|
||||
|
|
Загрузка…
Ссылка в новой задаче