зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1243252 - Baldr: add import section (r=bbouvier)
--HG-- extra : commitid : 64BPCvQPUL7 extra : rebase_source : 5cc46dd463ea6be7795c4787a99460fa9d19a4cc
This commit is contained in:
Родитель
38c56107c6
Коммит
c3fde7cc15
|
@ -2084,10 +2084,7 @@ class MOZ_STACK_CLASS ModuleValidator
|
||||||
uint32_t sigIndex;
|
uint32_t sigIndex;
|
||||||
if (!declareSig(Move(sig), &sigIndex))
|
if (!declareSig(Move(sig), &sigIndex))
|
||||||
return false;
|
return false;
|
||||||
uint32_t globalDataOffset;
|
if (!mg_.initImport(*importIndex, sigIndex))
|
||||||
if (!mg_.allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
|
|
||||||
return false;
|
|
||||||
if (!mg_.initImport(*importIndex, sigIndex, globalDataOffset))
|
|
||||||
return false;
|
return false;
|
||||||
return importMap_.add(p, NamedSig(name, mg_.sig(sigIndex)), *importIndex);
|
return importMap_.add(p, NamedSig(name, mg_.sig(sigIndex)), *importIndex);
|
||||||
}
|
}
|
||||||
|
@ -7148,7 +7145,7 @@ ValidateFFI(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal,
|
||||||
if (!GetDataProperty(cx, importVal, field, &v))
|
if (!GetDataProperty(cx, importVal, field, &v))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!v.isObject() || !v.toObject().is<JSFunction>())
|
if (!IsFunctionObject(v))
|
||||||
return LinkFail(cx, "FFI imports must be functions");
|
return LinkFail(cx, "FFI imports must be functions");
|
||||||
|
|
||||||
ffis[global.ffiIndex()].set(&v.toObject().as<JSFunction>());
|
ffis[global.ffiIndex()].set(&v.toObject().as<JSFunction>());
|
||||||
|
|
|
@ -314,6 +314,21 @@ DecodeSignatureSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DecodeSignatureIndex(JSContext* cx, Decoder& d, const ModuleGeneratorData& init,
|
||||||
|
const DeclaredSig** sig)
|
||||||
|
{
|
||||||
|
uint32_t sigIndex;
|
||||||
|
if (!d.readVarU32(&sigIndex))
|
||||||
|
return Fail(cx, d, "expected signature index");
|
||||||
|
|
||||||
|
if (sigIndex >= init.sigs.length())
|
||||||
|
return Fail(cx, d, "signature index out of range");
|
||||||
|
|
||||||
|
*sig = &init.sigs[sigIndex];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
|
DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
|
||||||
{
|
{
|
||||||
|
@ -332,14 +347,8 @@ DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < numDecls; i++) {
|
for (uint32_t i = 0; i < numDecls; i++) {
|
||||||
uint32_t sigIndex;
|
if (!DecodeSignatureIndex(cx, d, *init, &init->funcSigs[i]))
|
||||||
if (!d.readVarU32(&sigIndex))
|
return false;
|
||||||
return Fail(cx, d, "expected declaration signature index");
|
|
||||||
|
|
||||||
if (sigIndex >= init->sigs.length())
|
|
||||||
return Fail(cx, d, "declaration signature index out of range");
|
|
||||||
|
|
||||||
init->funcSigs[i] = &init->sigs[sigIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!d.finishSection(sectionStart))
|
if (!d.finishSection(sectionStart))
|
||||||
|
@ -348,6 +357,81 @@ DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ImportName
|
||||||
|
{
|
||||||
|
UniqueChars module;
|
||||||
|
UniqueChars func;
|
||||||
|
|
||||||
|
ImportName(UniqueChars module, UniqueChars func)
|
||||||
|
: module(Move(module)), func(Move(func))
|
||||||
|
{}
|
||||||
|
ImportName(ImportName&& rhs)
|
||||||
|
: module(Move(rhs.module)), func(Move(rhs.func))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Vector<ImportName, 0, SystemAllocPolicy> ImportNameVector;
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DecodeImport(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
|
||||||
|
{
|
||||||
|
if (!d.readCStringIf(FuncSubsection))
|
||||||
|
return Fail(cx, d, "expected 'func' tag");
|
||||||
|
|
||||||
|
const DeclaredSig* sig;
|
||||||
|
if (!DecodeSignatureIndex(cx, d, *init, &sig))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!init->imports.emplaceBack(sig))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* moduleStr;
|
||||||
|
if (!d.readCString(&moduleStr))
|
||||||
|
return Fail(cx, d, "expected import module name");
|
||||||
|
|
||||||
|
if (!*moduleStr)
|
||||||
|
return Fail(cx, d, "module name cannot be empty");
|
||||||
|
|
||||||
|
UniqueChars moduleName = DuplicateString(moduleStr);
|
||||||
|
if (!moduleName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* funcStr;
|
||||||
|
if (!d.readCString(&funcStr))
|
||||||
|
return Fail(cx, d, "expected import func name");
|
||||||
|
|
||||||
|
UniqueChars funcName = DuplicateString(funcStr);
|
||||||
|
if (!funcName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return importNames->emplaceBack(Move(moduleName), Move(funcName));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* imports)
|
||||||
|
{
|
||||||
|
if (!d.readCStringIf(ImportSection))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
uint32_t sectionStart;
|
||||||
|
if (!d.startSection(§ionStart))
|
||||||
|
return Fail(cx, d, "expected import section byte size");
|
||||||
|
|
||||||
|
uint32_t numImports;
|
||||||
|
if (!d.readVarU32(&numImports))
|
||||||
|
return Fail(cx, d, "expected number of imports");
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numImports; i++) {
|
||||||
|
if (!DecodeImport(cx, d, init, imports))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d.finishSection(sectionStart))
|
||||||
|
return Fail(cx, d, "import section byte size mismatch");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DecodeExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap)
|
DecodeExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap)
|
||||||
{
|
{
|
||||||
|
@ -518,7 +602,8 @@ DecodeUnknownSection(JSContext* cx, Decoder& d)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DecodeModule(JSContext* cx, UniqueChars filename, const uint8_t* bytes, uint32_t length,
|
DecodeModule(JSContext* cx, UniqueChars filename, const uint8_t* bytes, uint32_t length,
|
||||||
MutableHandle<WasmModuleObject*> moduleObj, ExportMap* exportMap)
|
ImportNameVector* importNames, ExportMap* exportMap,
|
||||||
|
MutableHandle<WasmModuleObject*> moduleObj)
|
||||||
{
|
{
|
||||||
Decoder d(bytes, bytes + length);
|
Decoder d(bytes, bytes + length);
|
||||||
|
|
||||||
|
@ -539,6 +624,9 @@ DecodeModule(JSContext* cx, UniqueChars filename, const uint8_t* bytes, uint32_t
|
||||||
if (!DecodeDeclarationSection(cx, d, init.get()))
|
if (!DecodeDeclarationSection(cx, d, init.get()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!DecodeImportSection(cx, d, init.get(), importNames))
|
||||||
|
return false;
|
||||||
|
|
||||||
ModuleGenerator mg(cx);
|
ModuleGenerator mg(cx);
|
||||||
if (!mg.init(Move(init)))
|
if (!mg.init(Move(init)))
|
||||||
return false;
|
return false;
|
||||||
|
@ -578,7 +666,49 @@ DecodeModule(JSContext* cx, UniqueChars filename, const uint8_t* bytes, uint32_t
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
// JS entry poitns
|
// JS entry points
|
||||||
|
|
||||||
|
static bool
|
||||||
|
GetProperty(JSContext* cx, HandleObject obj, const char* utf8Chars, MutableHandleValue v)
|
||||||
|
{
|
||||||
|
JSAtom* atom = AtomizeUTF8Chars(cx, utf8Chars, strlen(utf8Chars));
|
||||||
|
if (!atom)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RootedId id(cx, AtomToId(atom));
|
||||||
|
return GetProperty(cx, obj, obj, id, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ImportFunctions(JSContext* cx, HandleObject importObj, const ImportNameVector& importNames,
|
||||||
|
MutableHandle<FunctionVector> imports)
|
||||||
|
{
|
||||||
|
if (!importNames.empty() && !importObj)
|
||||||
|
return Fail(cx, "no import object given");
|
||||||
|
|
||||||
|
for (const ImportName& name : importNames) {
|
||||||
|
RootedValue v(cx);
|
||||||
|
if (!GetProperty(cx, importObj, name.module.get(), &v))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (*name.func.get()) {
|
||||||
|
if (!v.isObject())
|
||||||
|
return Fail(cx, "import object field is not an Object");
|
||||||
|
|
||||||
|
RootedObject obj(cx, &v.toObject());
|
||||||
|
if (!GetProperty(cx, obj, name.func.get(), &v))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsFunctionObject(v))
|
||||||
|
return Fail(cx, "import object field is not a Function");
|
||||||
|
|
||||||
|
if (!imports.append(&v.toObject().as<JSFunction>()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
SupportsWasm(JSContext* cx)
|
SupportsWasm(JSContext* cx)
|
||||||
|
@ -636,15 +766,6 @@ WasmEval(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.get(1).isUndefined() && !args.get(1).isObject()) {
|
|
||||||
ReportUsageError(cx, callee, "Second argument, if present, must be an Object");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniqueChars filename;
|
|
||||||
if (!DescribeScriptedCaller(cx, &filename))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Rooted<ArrayBufferObject*> code(cx, &args[0].toObject().as<ArrayBufferObject>());
|
Rooted<ArrayBufferObject*> code(cx, &args[0].toObject().as<ArrayBufferObject>());
|
||||||
const uint8_t* bytes = code->dataPointer();
|
const uint8_t* bytes = code->dataPointer();
|
||||||
uint32_t length = code->byteLength();
|
uint32_t length = code->byteLength();
|
||||||
|
@ -656,9 +777,23 @@ WasmEval(JSContext* cx, unsigned argc, Value* vp)
|
||||||
bytes = copy.begin();
|
bytes = copy.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rooted<WasmModuleObject*> moduleObj(cx);
|
RootedObject importObj(cx);
|
||||||
|
if (!args.get(1).isUndefined()) {
|
||||||
|
if (!args.get(1).isObject()) {
|
||||||
|
ReportUsageError(cx, callee, "Second argument, if present, must be an Object");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
importObj = &args[1].toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
UniqueChars filename;
|
||||||
|
if (!DescribeScriptedCaller(cx, &filename))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImportNameVector importNames;
|
||||||
ExportMap exportMap;
|
ExportMap exportMap;
|
||||||
if (!DecodeModule(cx, Move(filename), bytes, length, &moduleObj, &exportMap)) {
|
Rooted<WasmModuleObject*> moduleObj(cx);
|
||||||
|
if (!DecodeModule(cx, Move(filename), bytes, length, &importNames, &exportMap, &moduleObj)) {
|
||||||
if (!cx->isExceptionPending())
|
if (!cx->isExceptionPending())
|
||||||
ReportOutOfMemory(cx);
|
ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
|
@ -671,8 +806,8 @@ WasmEval(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return Fail(cx, "Heap not implemented yet");
|
return Fail(cx, "Heap not implemented yet");
|
||||||
|
|
||||||
Rooted<FunctionVector> imports(cx, FunctionVector(cx));
|
Rooted<FunctionVector> imports(cx, FunctionVector(cx));
|
||||||
if (module.imports().length() > 0)
|
if (!ImportFunctions(cx, importObj, importNames, &imports))
|
||||||
return Fail(cx, "Imports not implemented yet");
|
return false;
|
||||||
|
|
||||||
RootedObject exportObj(cx);
|
RootedObject exportObj(cx);
|
||||||
if (!module.dynamicallyLink(cx, moduleObj, heap, imports, exportMap, &exportObj))
|
if (!module.dynamicallyLink(cx, moduleObj, heap, imports, exportMap, &exportObj))
|
||||||
|
|
|
@ -35,6 +35,7 @@ static const uint32_t EncodingVersion = -1; // experimental
|
||||||
// Module section names:
|
// Module section names:
|
||||||
static const char SigSection[] = "sig";
|
static const char SigSection[] = "sig";
|
||||||
static const char DeclSection[] = "decl";
|
static const char DeclSection[] = "decl";
|
||||||
|
static const char ImportSection[] = "import";
|
||||||
static const char ExportSection[] = "export";
|
static const char ExportSection[] = "export";
|
||||||
static const char CodeSection[] = "code";
|
static const char CodeSection[] = "code";
|
||||||
static const char EndSection[] = "";
|
static const char EndSection[] = "";
|
||||||
|
|
|
@ -128,8 +128,12 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, ModuleKind kind)
|
||||||
if (kind == ModuleKind::Wasm) {
|
if (kind == ModuleKind::Wasm) {
|
||||||
numSigs_ = shared_->sigs.length();
|
numSigs_ = shared_->sigs.length();
|
||||||
module_->numFuncs = shared_->funcSigs.length();
|
module_->numFuncs = shared_->funcSigs.length();
|
||||||
for (uint32_t i = 0; i < shared_->imports.length(); i++) {
|
module_->globalBytes = AlignBytes(module_->globalBytes, sizeof(void*));
|
||||||
if (!addImport(*shared_->imports[i].sig, shared_->imports[i].globalDataOffset))
|
for (ModuleImportGeneratorData& import : shared_->imports) {
|
||||||
|
MOZ_ASSERT(!import.globalDataOffset);
|
||||||
|
import.globalDataOffset = module_->globalBytes;
|
||||||
|
module_->globalBytes += Module::SizeOfImportExit;
|
||||||
|
if (!addImport(*import.sig, import.globalDataOffset))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,8 +306,12 @@ ModuleGenerator::funcSig(uint32_t funcIndex) const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ModuleGenerator::initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset)
|
ModuleGenerator::initImport(uint32_t importIndex, uint32_t sigIndex)
|
||||||
{
|
{
|
||||||
|
uint32_t globalDataOffset;
|
||||||
|
if (!allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
|
||||||
|
return false;
|
||||||
|
|
||||||
MOZ_ASSERT(isAsmJS());
|
MOZ_ASSERT(isAsmJS());
|
||||||
MOZ_ASSERT(importIndex == module_->imports.length());
|
MOZ_ASSERT(importIndex == module_->imports.length());
|
||||||
if (!addImport(sig(sigIndex), globalDataOffset))
|
if (!addImport(sig(sigIndex), globalDataOffset))
|
||||||
|
|
|
@ -48,8 +48,8 @@ struct SlowFunction
|
||||||
typedef Vector<SlowFunction> SlowFunctionVector;
|
typedef Vector<SlowFunction> SlowFunctionVector;
|
||||||
|
|
||||||
// The ModuleGeneratorData holds all the state shared between the
|
// The ModuleGeneratorData holds all the state shared between the
|
||||||
// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData is
|
// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData
|
||||||
// encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
|
// is encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
|
||||||
// present a race-free interface to the code in each thread assuming any given
|
// present a race-free interface to the code in each thread assuming any given
|
||||||
// element is initialized by the ModuleGenerator thread before an index to that
|
// element is initialized by the ModuleGenerator thread before an index to that
|
||||||
// element is written to Bytecode sent to a ModuleGeneratorThreadView thread.
|
// element is written to Bytecode sent to a ModuleGeneratorThreadView thread.
|
||||||
|
@ -57,15 +57,17 @@ typedef Vector<SlowFunction> SlowFunctionVector;
|
||||||
|
|
||||||
struct ModuleImportGeneratorData
|
struct ModuleImportGeneratorData
|
||||||
{
|
{
|
||||||
DeclaredSig* sig;
|
const DeclaredSig* sig;
|
||||||
uint32_t globalDataOffset;
|
uint32_t globalDataOffset;
|
||||||
|
|
||||||
|
ModuleImportGeneratorData() : sig(nullptr), globalDataOffset(0) {}
|
||||||
|
explicit ModuleImportGeneratorData(const DeclaredSig* sig) : sig(sig), globalDataOffset(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Vector<ModuleImportGeneratorData, 0, SystemAllocPolicy> ModuleImportGeneratorDataVector;
|
typedef Vector<ModuleImportGeneratorData, 0, SystemAllocPolicy> ModuleImportGeneratorDataVector;
|
||||||
|
|
||||||
// Global variable descriptor, in asm.js only.
|
struct AsmJSGlobalVariable
|
||||||
|
{
|
||||||
struct AsmJSGlobalVariable {
|
|
||||||
ExprType type;
|
ExprType type;
|
||||||
unsigned globalDataOffset;
|
unsigned globalDataOffset;
|
||||||
bool isConst;
|
bool isConst;
|
||||||
|
@ -159,6 +161,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
bool finishTask(IonCompileTask* task);
|
bool finishTask(IonCompileTask* task);
|
||||||
bool addImport(const Sig& sig, uint32_t globalDataOffset);
|
bool addImport(const Sig& sig, uint32_t globalDataOffset);
|
||||||
bool startedFuncDefs() const { return !!threadView_; }
|
bool startedFuncDefs() const { return !!threadView_; }
|
||||||
|
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ModuleGenerator(ExclusiveContext* cx);
|
explicit ModuleGenerator(ExclusiveContext* cx);
|
||||||
|
@ -171,8 +174,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
jit::MacroAssembler& masm() { return masm_; }
|
jit::MacroAssembler& masm() { return masm_; }
|
||||||
const Uint32Vector& funcEntryOffsets() const { return funcEntryOffsets_; }
|
const Uint32Vector& funcEntryOffsets() const { return funcEntryOffsets_; }
|
||||||
|
|
||||||
// Global data:
|
// asm.js global variables:
|
||||||
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
|
|
||||||
bool allocateGlobalVar(ValType type, bool isConst, uint32_t* index);
|
bool allocateGlobalVar(ValType type, bool isConst, uint32_t* index);
|
||||||
const AsmJSGlobalVariable& globalVar(unsigned index) const { return shared_->globals[index]; }
|
const AsmJSGlobalVariable& globalVar(unsigned index) const { return shared_->globals[index]; }
|
||||||
|
|
||||||
|
@ -187,7 +189,7 @@ class MOZ_STACK_CLASS ModuleGenerator
|
||||||
const DeclaredSig& funcSig(uint32_t funcIndex) const;
|
const DeclaredSig& funcSig(uint32_t funcIndex) const;
|
||||||
|
|
||||||
// Imports:
|
// Imports:
|
||||||
bool initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset);
|
bool initImport(uint32_t importIndex, uint32_t sigIndex);
|
||||||
uint32_t numImports() const;
|
uint32_t numImports() const;
|
||||||
const ModuleImportGeneratorData& import(uint32_t index) const;
|
const ModuleImportGeneratorData& import(uint32_t index) const;
|
||||||
bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
|
bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
|
||||||
|
|
|
@ -177,11 +177,9 @@ class Import
|
||||||
return pod.exitGlobalDataOffset_;
|
return pod.exitGlobalDataOffset_;
|
||||||
}
|
}
|
||||||
uint32_t interpExitCodeOffset() const {
|
uint32_t interpExitCodeOffset() const {
|
||||||
MOZ_ASSERT(pod.interpExitCodeOffset_);
|
|
||||||
return pod.interpExitCodeOffset_;
|
return pod.interpExitCodeOffset_;
|
||||||
}
|
}
|
||||||
uint32_t jitExitCodeOffset() const {
|
uint32_t jitExitCodeOffset() const {
|
||||||
MOZ_ASSERT(pod.jitExitCodeOffset_);
|
|
||||||
return pod.jitExitCodeOffset_;
|
return pod.jitExitCodeOffset_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ enum class WasmAstKind
|
||||||
Export,
|
Export,
|
||||||
Func,
|
Func,
|
||||||
GetLocal,
|
GetLocal,
|
||||||
|
Import,
|
||||||
Module,
|
Module,
|
||||||
Nop,
|
Nop,
|
||||||
SetLocal
|
SetLocal
|
||||||
|
@ -213,6 +214,21 @@ class WasmAstFunc : public WasmAstNode
|
||||||
WasmAstExpr* maybeBody() const { return maybeBody_; }
|
WasmAstExpr* maybeBody() const { return maybeBody_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WasmAstImport : public WasmAstNode
|
||||||
|
{
|
||||||
|
TwoByteChars module_;
|
||||||
|
TwoByteChars func_;
|
||||||
|
uint32_t sigIndex_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WasmAstImport(TwoByteChars module, TwoByteChars func, uint32_t sigIndex)
|
||||||
|
: WasmAstNode(WasmAstKind::Import), module_(module), func_(func), sigIndex_(sigIndex)
|
||||||
|
{}
|
||||||
|
TwoByteChars module() const { return module_; }
|
||||||
|
TwoByteChars func() const { return func_; }
|
||||||
|
uint32_t sigIndex() const { return sigIndex_; }
|
||||||
|
};
|
||||||
|
|
||||||
class WasmAstExport : public WasmAstNode
|
class WasmAstExport : public WasmAstNode
|
||||||
{
|
{
|
||||||
TwoByteChars name_;
|
TwoByteChars name_;
|
||||||
|
@ -229,12 +245,14 @@ class WasmAstExport : public WasmAstNode
|
||||||
class WasmAstModule : public WasmAstNode
|
class WasmAstModule : public WasmAstNode
|
||||||
{
|
{
|
||||||
typedef WasmAstVector<WasmAstFunc*> FuncVector;
|
typedef WasmAstVector<WasmAstFunc*> FuncVector;
|
||||||
|
typedef WasmAstVector<WasmAstImport*> ImportVector;
|
||||||
typedef WasmAstVector<WasmAstExport*> ExportVector;
|
typedef WasmAstVector<WasmAstExport*> ExportVector;
|
||||||
typedef WasmAstVector<WasmAstSig*> SigVector;
|
typedef WasmAstVector<WasmAstSig*> SigVector;
|
||||||
typedef WasmAstHashMap<WasmAstSig*, uint32_t, WasmAstSig> SigMap;
|
typedef WasmAstHashMap<WasmAstSig*, uint32_t, WasmAstSig> SigMap;
|
||||||
|
|
||||||
LifoAlloc& lifo_;
|
LifoAlloc& lifo_;
|
||||||
FuncVector funcs_;
|
FuncVector funcs_;
|
||||||
|
ImportVector imports_;
|
||||||
ExportVector exports_;
|
ExportVector exports_;
|
||||||
SigVector sigs_;
|
SigVector sigs_;
|
||||||
SigMap sigMap_;
|
SigMap sigMap_;
|
||||||
|
@ -244,6 +262,7 @@ class WasmAstModule : public WasmAstNode
|
||||||
: WasmAstNode(WasmAstKind::Module),
|
: WasmAstNode(WasmAstKind::Module),
|
||||||
lifo_(lifo),
|
lifo_(lifo),
|
||||||
funcs_(lifo),
|
funcs_(lifo),
|
||||||
|
imports_(lifo),
|
||||||
exports_(lifo),
|
exports_(lifo),
|
||||||
sigs_(lifo),
|
sigs_(lifo),
|
||||||
sigMap_(lifo)
|
sigMap_(lifo)
|
||||||
|
@ -270,6 +289,12 @@ class WasmAstModule : public WasmAstNode
|
||||||
const FuncVector& funcs() const {
|
const FuncVector& funcs() const {
|
||||||
return funcs_;
|
return funcs_;
|
||||||
}
|
}
|
||||||
|
const ImportVector& imports() const {
|
||||||
|
return imports_;
|
||||||
|
}
|
||||||
|
bool append(WasmAstImport* imp) {
|
||||||
|
return imports_.append(imp);
|
||||||
|
}
|
||||||
bool append(WasmAstExport* exp) {
|
bool append(WasmAstExport* exp) {
|
||||||
return exports_.append(exp);
|
return exports_.append(exp);
|
||||||
}
|
}
|
||||||
|
@ -294,6 +319,7 @@ class WasmToken
|
||||||
Export,
|
Export,
|
||||||
Func,
|
Func,
|
||||||
GetLocal,
|
GetLocal,
|
||||||
|
Import,
|
||||||
Integer,
|
Integer,
|
||||||
Local,
|
Local,
|
||||||
Module,
|
Module,
|
||||||
|
@ -496,14 +522,12 @@ class WasmTokenStream
|
||||||
if (consume(end_, MOZ_UTF16("32"))) {
|
if (consume(end_, MOZ_UTF16("32"))) {
|
||||||
if (consume(end_, MOZ_UTF16(".const")))
|
if (consume(end_, MOZ_UTF16(".const")))
|
||||||
return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
|
return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
|
||||||
else
|
return WasmToken(WasmToken::ValueType, ValType::F32, begin, cur_);
|
||||||
return WasmToken(WasmToken::ValueType, ValType::F32, begin, cur_);
|
|
||||||
}
|
}
|
||||||
if (consume(end_, MOZ_UTF16("64"))) {
|
if (consume(end_, MOZ_UTF16("64"))) {
|
||||||
if (consume(end_, MOZ_UTF16(".const")))
|
if (consume(end_, MOZ_UTF16(".const")))
|
||||||
return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
|
return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
|
||||||
else
|
return WasmToken(WasmToken::ValueType, ValType::F64, begin, cur_);
|
||||||
return WasmToken(WasmToken::ValueType, ValType::F64, begin, cur_);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -516,15 +540,15 @@ class WasmTokenStream
|
||||||
if (consume(end_, MOZ_UTF16("32"))) {
|
if (consume(end_, MOZ_UTF16("32"))) {
|
||||||
if (consume(end_, MOZ_UTF16(".const")))
|
if (consume(end_, MOZ_UTF16(".const")))
|
||||||
return WasmToken(WasmToken::Const, ValType::I32, begin, cur_);
|
return WasmToken(WasmToken::Const, ValType::I32, begin, cur_);
|
||||||
else
|
return WasmToken(WasmToken::ValueType, ValType::I32, begin, cur_);
|
||||||
return WasmToken(WasmToken::ValueType, ValType::I32, begin, cur_);
|
|
||||||
}
|
}
|
||||||
if (consume(end_, MOZ_UTF16("64"))) {
|
if (consume(end_, MOZ_UTF16("64"))) {
|
||||||
if (consume(end_, MOZ_UTF16(".const")))
|
if (consume(end_, MOZ_UTF16(".const")))
|
||||||
return WasmToken(WasmToken::Const, ValType::I64, begin, cur_);
|
return WasmToken(WasmToken::Const, ValType::I64, begin, cur_);
|
||||||
else
|
return WasmToken(WasmToken::ValueType, ValType::I64, begin, cur_);
|
||||||
return WasmToken(WasmToken::ValueType, ValType::I64, begin, cur_);
|
|
||||||
}
|
}
|
||||||
|
if (consume(end_, MOZ_UTF16("mport")))
|
||||||
|
return WasmToken(WasmToken::Import, begin, cur_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
@ -737,6 +761,30 @@ ParseExprInsideParens(WasmParseContext& c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ParseValueType(WasmParseContext& c, WasmAstValTypeVector* vec)
|
||||||
|
{
|
||||||
|
WasmToken valueType;
|
||||||
|
return c.ts.match(WasmToken::ValueType, &valueType, c.error) &&
|
||||||
|
vec->append(valueType.valueType());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ParseResult(WasmParseContext& c, ExprType* result)
|
||||||
|
{
|
||||||
|
if (*result != ExprType::Void) {
|
||||||
|
c.ts.generateError(c.ts.peek(), c.error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WasmToken valueType;
|
||||||
|
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*result = ToExprType(valueType.valueType());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static WasmAstFunc*
|
static WasmAstFunc*
|
||||||
ParseFunc(WasmParseContext& c, WasmAstModule* module)
|
ParseFunc(WasmParseContext& c, WasmAstModule* module)
|
||||||
{
|
{
|
||||||
|
@ -746,44 +794,27 @@ ParseFunc(WasmParseContext& c, WasmAstModule* module)
|
||||||
|
|
||||||
WasmAstExpr* maybeBody = nullptr;
|
WasmAstExpr* maybeBody = nullptr;
|
||||||
while (c.ts.getIf(WasmToken::OpenParen) && !maybeBody) {
|
while (c.ts.getIf(WasmToken::OpenParen) && !maybeBody) {
|
||||||
WasmToken field = c.ts.get();
|
WasmToken token = c.ts.get();
|
||||||
|
switch (token.kind()) {
|
||||||
switch (field.kind()) {
|
case WasmToken::Local:
|
||||||
case WasmToken::Local: {
|
if (!ParseValueType(c, &vars))
|
||||||
WasmToken valueType;
|
|
||||||
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
|
|
||||||
return nullptr;
|
|
||||||
if (!vars.append(valueType.valueType()))
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
case WasmToken::Param:
|
||||||
case WasmToken::Param: {
|
if (!ParseValueType(c, &args))
|
||||||
WasmToken valueType;
|
|
||||||
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
|
|
||||||
return nullptr;
|
|
||||||
if (!args.append(valueType.valueType()))
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
case WasmToken::Result:
|
||||||
case WasmToken::Result: {
|
if (!ParseResult(c, &result))
|
||||||
if (result != ExprType::Void) {
|
|
||||||
c.ts.generateError(field, c.error);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
WasmToken valueType;
|
|
||||||
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
|
|
||||||
return nullptr;
|
|
||||||
result = ToExprType(valueType.valueType());
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
c.ts.unget(field);
|
c.ts.unget(token);
|
||||||
maybeBody = ParseExprInsideParens(c);
|
maybeBody = ParseExprInsideParens(c);
|
||||||
if (!maybeBody)
|
if (!maybeBody)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -795,6 +826,46 @@ ParseFunc(WasmParseContext& c, WasmAstModule* module)
|
||||||
return new(c.lifo) WasmAstFunc(sigIndex, Move(vars), maybeBody);
|
return new(c.lifo) WasmAstFunc(sigIndex, Move(vars), maybeBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WasmAstImport*
|
||||||
|
ParseImport(WasmParseContext& c, WasmAstModule* module)
|
||||||
|
{
|
||||||
|
WasmToken moduleName;
|
||||||
|
if (!c.ts.match(WasmToken::Text, &moduleName, c.error))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
WasmToken funcName;
|
||||||
|
if (!c.ts.match(WasmToken::Text, &funcName, c.error))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
WasmAstValTypeVector args(c.lifo);
|
||||||
|
ExprType result = ExprType::Void;
|
||||||
|
|
||||||
|
while (c.ts.getIf(WasmToken::OpenParen)) {
|
||||||
|
WasmToken token = c.ts.get();
|
||||||
|
switch (token.kind()) {
|
||||||
|
case WasmToken::Param:
|
||||||
|
if (!ParseValueType(c, &args))
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
case WasmToken::Result:
|
||||||
|
if (!ParseResult(c, &result))
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c.ts.generateError(token, c.error);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sigIndex;
|
||||||
|
if (!module->declare(WasmAstSig(Move(args), result), &sigIndex))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return new(c.lifo) WasmAstImport(moduleName.text(), funcName.text(), sigIndex);
|
||||||
|
}
|
||||||
|
|
||||||
static WasmAstExport*
|
static WasmAstExport*
|
||||||
ParseExport(WasmParseContext& c)
|
ParseExport(WasmParseContext& c)
|
||||||
{
|
{
|
||||||
|
@ -827,6 +898,12 @@ TextToAst(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
|
||||||
WasmToken section = c.ts.get();
|
WasmToken section = c.ts.get();
|
||||||
|
|
||||||
switch (section.kind()) {
|
switch (section.kind()) {
|
||||||
|
case WasmToken::Import: {
|
||||||
|
WasmAstImport* imp = ParseImport(c, module);
|
||||||
|
if (!imp || !module->append(imp))
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case WasmToken::Export: {
|
case WasmToken::Export: {
|
||||||
WasmAstExport* exp = ParseExport(c);
|
WasmAstExport* exp = ParseExport(c);
|
||||||
if (!exp || !module->append(exp))
|
if (!exp || !module->append(exp))
|
||||||
|
@ -933,7 +1010,7 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
|
||||||
static bool
|
static bool
|
||||||
EncodeSignatureSection(Encoder& e, WasmAstModule& module)
|
EncodeSignatureSection(Encoder& e, WasmAstModule& module)
|
||||||
{
|
{
|
||||||
if (module.funcs().empty())
|
if (module.sigs().empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!e.writeCString(SigSection))
|
if (!e.writeCString(SigSection))
|
||||||
|
@ -988,6 +1065,57 @@ EncodeDeclarationSection(Encoder& e, WasmAstModule& module)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
EncodeImport(Encoder& e, WasmAstImport& imp)
|
||||||
|
{
|
||||||
|
if (!e.writeCString(FuncSubsection))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!e.writeVarU32(imp.sigIndex()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UniqueChars moduleChars(JS::CharsToNewUTF8CharsZ(nullptr, imp.module()).c_str());
|
||||||
|
if (!moduleChars)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!e.writeCString(moduleChars.get()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UniqueChars funcChars(JS::CharsToNewUTF8CharsZ(nullptr, imp.func()).c_str());
|
||||||
|
if (!funcChars)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!e.writeCString(funcChars.get()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
EncodeImportSection(Encoder& e, WasmAstModule& module)
|
||||||
|
{
|
||||||
|
if (module.imports().empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!e.writeCString(ImportSection))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t offset;
|
||||||
|
if (!e.startSection(&offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!e.writeVarU32(module.imports().length()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (WasmAstImport* imp : module.imports()) {
|
||||||
|
if (!EncodeImport(e, *imp))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.finishSection(offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
EncodeExport(Encoder& e, WasmAstExport& exp)
|
EncodeExport(Encoder& e, WasmAstExport& exp)
|
||||||
{
|
{
|
||||||
|
@ -1109,6 +1237,9 @@ AstToBinary(WasmAstModule& module)
|
||||||
if (!EncodeDeclarationSection(e, module))
|
if (!EncodeDeclarationSection(e, module))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
if (!EncodeImportSection(e, module))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
if (!EncodeExportSection(e, module))
|
if (!EncodeExportSection(e, module))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,37 @@ wasmEvalText('(module (func (param f64)))');
|
||||||
assertErrorMessage(() => wasmEvalText('(module (func (param i64)))'), TypeError, /NYI/);
|
assertErrorMessage(() => wasmEvalText('(module (func (param i64)))'), TypeError, /NYI/);
|
||||||
assertErrorMessage(() => wasmEvalText('(module (func (result i64)))'), TypeError, /NYI/);
|
assertErrorMessage(() => wasmEvalText('(module (func (result i64)))'), TypeError, /NYI/);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// imports
|
||||||
|
|
||||||
|
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /Second argument, if present, must be an Object/);
|
||||||
|
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /Second argument, if present, must be an Object/);
|
||||||
|
|
||||||
|
const noImportObj = /no import object given/;
|
||||||
|
const notObject = /import object field is not an Object/;
|
||||||
|
const notFunction = /import object field is not a Function/;
|
||||||
|
|
||||||
|
var code = '(module (import "a" "b"))';
|
||||||
|
assertErrorMessage(() => wasmEvalText(code), TypeError, noImportObj);
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {}), TypeError, notObject);
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {a:1}), TypeError, notObject);
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {a:{}}), TypeError, notFunction);
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {a:{b:1}}), TypeError, notFunction);
|
||||||
|
wasmEvalText(code, {a:{b:()=>{}}});
|
||||||
|
|
||||||
|
var code = '(module (import "" "b"))';
|
||||||
|
assertErrorMessage(() => wasmEvalText(code), TypeError, /module name cannot be empty/);
|
||||||
|
|
||||||
|
var code = '(module (import "a" ""))';
|
||||||
|
assertErrorMessage(() => wasmEvalText(code), TypeError, noImportObj);
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {}), TypeError, notFunction);
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {a:1}), TypeError, notFunction);
|
||||||
|
wasmEvalText(code, {a:()=>{}});
|
||||||
|
|
||||||
|
var code = '(module (import "a" "") (import "b" "c") (import "c" ""))';
|
||||||
|
assertErrorMessage(() => wasmEvalText(code, {a:()=>{}, b:{c:()=>{}}, c:{}}), TypeError, notFunction);
|
||||||
|
wasmEvalText(code, {a:()=>{}, b:{c:()=>{}}, c:()=>{}});
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// locals
|
// locals
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,10 @@ const ver3 = 0xff;
|
||||||
// Section names
|
// Section names
|
||||||
const sigSectionStr = "sig";
|
const sigSectionStr = "sig";
|
||||||
const declSectionStr = "decl";
|
const declSectionStr = "decl";
|
||||||
|
const importSectionStr = "import";
|
||||||
const exportSectionStr = "export";
|
const exportSectionStr = "export";
|
||||||
const codeSectionStr = "code";
|
const codeSectionStr = "code";
|
||||||
|
const funcSubsectionStr = "func";
|
||||||
|
|
||||||
const magicError = /failed to match magic number/;
|
const magicError = /failed to match magic number/;
|
||||||
const versionError = /failed to match binary version/;
|
const versionError = /failed to match binary version/;
|
||||||
|
@ -36,7 +38,7 @@ const B32x4Code = 6;
|
||||||
const VoidCode = 7;
|
const VoidCode = 7;
|
||||||
|
|
||||||
function toBuf(array) {
|
function toBuf(array) {
|
||||||
for (var b of array)
|
for (let b of array)
|
||||||
assertEq(b < 256, true);
|
assertEq(b < 256, true);
|
||||||
return Uint8Array.from(array).buffer;
|
return Uint8Array.from(array).buffer;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +68,7 @@ assertEq(Object.getOwnPropertyNames(o).length, 0);
|
||||||
assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(1))), TypeError, sectionError);
|
assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(1))), TypeError, sectionError);
|
||||||
assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 1))), TypeError, extraError);
|
assertErrorMessage(() => wasmEval(toBuf(moduleHeaderThen(0, 1))), TypeError, extraError);
|
||||||
|
|
||||||
function sectionName(name) {
|
function cstring(name) {
|
||||||
return (name + '\0').split('').map(c => c.charCodeAt(0));
|
return (name + '\0').split('').map(c => c.charCodeAt(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +80,8 @@ function sectionLength(length) {
|
||||||
|
|
||||||
function moduleWithSections(sectionArray) {
|
function moduleWithSections(sectionArray) {
|
||||||
var bytes = moduleHeaderThen();
|
var bytes = moduleHeaderThen();
|
||||||
for (section of sectionArray) {
|
for (let section of sectionArray) {
|
||||||
bytes.push(...sectionName(section.name));
|
bytes.push(...cstring(section.name));
|
||||||
bytes.push(...sectionLength(section.body.length));
|
bytes.push(...sectionLength(section.body.length));
|
||||||
bytes.push(...section.body);
|
bytes.push(...section.body);
|
||||||
}
|
}
|
||||||
|
@ -90,15 +92,53 @@ function moduleWithSections(sectionArray) {
|
||||||
function sigSection(sigs) {
|
function sigSection(sigs) {
|
||||||
var body = [];
|
var body = [];
|
||||||
body.push(...varU32(sigs.length));
|
body.push(...varU32(sigs.length));
|
||||||
for (var sig of sigs) {
|
for (let sig of sigs) {
|
||||||
body.push(...varU32(sig.args.length));
|
body.push(...varU32(sig.args.length));
|
||||||
body.push(...varU32(sig.ret));
|
body.push(...varU32(sig.ret));
|
||||||
for (var arg of sig.args)
|
for (let arg of sig.args)
|
||||||
body.push(...varU32(arg));
|
body.push(...varU32(arg));
|
||||||
}
|
}
|
||||||
return { name: sigSectionStr, body };
|
return { name: sigSectionStr, body };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function declSection(decls) {
|
||||||
|
var body = [];
|
||||||
|
body.push(...varU32(decls.length));
|
||||||
|
for (let decl of decls)
|
||||||
|
body.push(...varU32(decl));
|
||||||
|
return { name: declSectionStr, body };
|
||||||
|
}
|
||||||
|
|
||||||
|
function codeSection(funcs) {
|
||||||
|
var body = [];
|
||||||
|
body.push(...varU32(funcs.length));
|
||||||
|
for (let func of funcs) {
|
||||||
|
body.push(...cstring(funcSubsectionStr));
|
||||||
|
var locals = varU32(func.locals.length);
|
||||||
|
for (let local of func.locals)
|
||||||
|
locals.push(...varU32(local));
|
||||||
|
body.push(...sectionLength(locals.length + func.body.length));
|
||||||
|
body = body.concat(locals, func.body);
|
||||||
|
}
|
||||||
|
return { name: codeSectionStr, body };
|
||||||
|
}
|
||||||
|
|
||||||
|
function importSection(imports) {
|
||||||
|
var body = [];
|
||||||
|
body.push(...varU32(imports.length));
|
||||||
|
for (let imp of imports) {
|
||||||
|
body.push(...cstring(funcSubsectionStr));
|
||||||
|
body.push(...varU32(imp.sigIndex));
|
||||||
|
body.push(...cstring(imp.module));
|
||||||
|
body.push(...cstring(imp.func));
|
||||||
|
}
|
||||||
|
return { name: importSectionStr, body };
|
||||||
|
}
|
||||||
|
|
||||||
|
const trivialSigSection = sigSection([{args:[], ret:VoidCode}]);
|
||||||
|
const trivialDeclSection = declSection([0]);
|
||||||
|
const trivialCodeSection = codeSection([{locals:[], body:[0, 0]}]);
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([{name: sigSectionStr, body: [1]}]))), TypeError);
|
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([{name: sigSectionStr, body: [1]}]))), TypeError);
|
||||||
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([{name: sigSectionStr, body: [1, 1, 0]}]))), TypeError);
|
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([{name: sigSectionStr, body: [1, 1, 0]}]))), TypeError);
|
||||||
|
|
||||||
|
@ -109,15 +149,13 @@ wasmEval(toBuf(moduleWithSections([sigSection([{args:[I32Code], ret:VoidCode}])]
|
||||||
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[], ret:100}])]))), TypeError, /bad expression type/);
|
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[], ret:100}])]))), TypeError, /bad expression type/);
|
||||||
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[100], ret:VoidCode}])]))), TypeError, /bad value type/);
|
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[100], ret:VoidCode}])]))), TypeError, /bad value type/);
|
||||||
|
|
||||||
function declSection(decls) {
|
|
||||||
var body = [];
|
|
||||||
body.push(...varU32(decls.length));
|
|
||||||
for (var decl of decls)
|
|
||||||
body.push(...varU32(decl));
|
|
||||||
return { name: declSectionStr, body };
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([sigSection([]), declSection([0])]))), TypeError, /signature index out of range/);
|
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([sigSection([]), declSection([0])]))), TypeError, /signature index out of range/);
|
||||||
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[], ret:VoidCode}]), declSection([1])]))), TypeError, /signature index out of range/);
|
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, declSection([1])]))), TypeError, /signature index out of range/);
|
||||||
|
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, declSection([0])]))), TypeError, /fewer function definitions than declarations/);
|
||||||
|
wasmEval(toBuf(moduleWithSections([trivialSigSection, trivialDeclSection, trivialCodeSection])));
|
||||||
|
|
||||||
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([sigSection([{args:[], ret:VoidCode}]), declSection([0])]))), TypeError, /fewer function definitions than declarations/);
|
assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, {name: importSectionStr, body:[]}]))), TypeError);
|
||||||
|
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([importSection([{sigIndex:0, module:"a", func:"b"}])]))), TypeError, /signature index out of range/);
|
||||||
|
assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([{sigIndex:1, module:"a", func:"b"}])]))), TypeError, /signature index out of range/);
|
||||||
|
wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([])])));
|
||||||
|
wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([{sigIndex:0, module:"a", func:""}])])), {a:()=>{}});
|
||||||
|
|
Загрузка…
Ссылка в новой задаче