Bug 1243252 - Baldr: add import section (r=bbouvier)

--HG--
extra : commitid : 64BPCvQPUL7
extra : rebase_source : 5cc46dd463ea6be7795c4787a99460fa9d19a4cc
This commit is contained in:
Luke Wagner 2016-01-28 10:30:41 -06:00
Родитель 38c56107c6
Коммит c3fde7cc15
9 изменённых файлов: 434 добавлений и 93 удалений

Просмотреть файл

@ -2084,10 +2084,7 @@ class MOZ_STACK_CLASS ModuleValidator
uint32_t sigIndex;
if (!declareSig(Move(sig), &sigIndex))
return false;
uint32_t globalDataOffset;
if (!mg_.allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
return false;
if (!mg_.initImport(*importIndex, sigIndex, globalDataOffset))
if (!mg_.initImport(*importIndex, sigIndex))
return false;
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))
return false;
if (!v.isObject() || !v.toObject().is<JSFunction>())
if (!IsFunctionObject(v))
return LinkFail(cx, "FFI imports must be functions");
ffis[global.ffiIndex()].set(&v.toObject().as<JSFunction>());

Просмотреть файл

@ -314,6 +314,21 @@ DecodeSignatureSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
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
DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
{
@ -332,14 +347,8 @@ DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
return false;
for (uint32_t i = 0; i < numDecls; i++) {
uint32_t sigIndex;
if (!d.readVarU32(&sigIndex))
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 (!DecodeSignatureIndex(cx, d, *init, &init->funcSigs[i]))
return false;
}
if (!d.finishSection(sectionStart))
@ -348,6 +357,81 @@ DecodeDeclarationSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
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(&sectionStart))
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
DecodeExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap)
{
@ -518,7 +602,8 @@ DecodeUnknownSection(JSContext* cx, Decoder& d)
static bool
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);
@ -539,6 +624,9 @@ DecodeModule(JSContext* cx, UniqueChars filename, const uint8_t* bytes, uint32_t
if (!DecodeDeclarationSection(cx, d, init.get()))
return false;
if (!DecodeImportSection(cx, d, init.get(), importNames))
return false;
ModuleGenerator mg(cx);
if (!mg.init(Move(init)))
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
SupportsWasm(JSContext* cx)
@ -636,15 +766,6 @@ WasmEval(JSContext* cx, unsigned argc, Value* vp)
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>());
const uint8_t* bytes = code->dataPointer();
uint32_t length = code->byteLength();
@ -656,9 +777,23 @@ WasmEval(JSContext* cx, unsigned argc, Value* vp)
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;
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())
ReportOutOfMemory(cx);
return false;
@ -671,8 +806,8 @@ WasmEval(JSContext* cx, unsigned argc, Value* vp)
return Fail(cx, "Heap not implemented yet");
Rooted<FunctionVector> imports(cx, FunctionVector(cx));
if (module.imports().length() > 0)
return Fail(cx, "Imports not implemented yet");
if (!ImportFunctions(cx, importObj, importNames, &imports))
return false;
RootedObject exportObj(cx);
if (!module.dynamicallyLink(cx, moduleObj, heap, imports, exportMap, &exportObj))

Просмотреть файл

@ -35,6 +35,7 @@ static const uint32_t EncodingVersion = -1; // experimental
// Module section names:
static const char SigSection[] = "sig";
static const char DeclSection[] = "decl";
static const char ImportSection[] = "import";
static const char ExportSection[] = "export";
static const char CodeSection[] = "code";
static const char EndSection[] = "";

Просмотреть файл

@ -128,8 +128,12 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, ModuleKind kind)
if (kind == ModuleKind::Wasm) {
numSigs_ = shared_->sigs.length();
module_->numFuncs = shared_->funcSigs.length();
for (uint32_t i = 0; i < shared_->imports.length(); i++) {
if (!addImport(*shared_->imports[i].sig, shared_->imports[i].globalDataOffset))
module_->globalBytes = AlignBytes(module_->globalBytes, sizeof(void*));
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;
}
}
@ -302,8 +306,12 @@ ModuleGenerator::funcSig(uint32_t funcIndex) const
}
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(importIndex == module_->imports.length());
if (!addImport(sig(sigIndex), globalDataOffset))

Просмотреть файл

@ -48,8 +48,8 @@ struct SlowFunction
typedef Vector<SlowFunction> SlowFunctionVector;
// The ModuleGeneratorData holds all the state shared between the
// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData is
// encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
// ModuleGenerator and ModuleGeneratorThreadView. The ModuleGeneratorData
// is encapsulated by ModuleGenerator/ModuleGeneratorThreadView classes which
// 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 written to Bytecode sent to a ModuleGeneratorThreadView thread.
@ -57,15 +57,17 @@ typedef Vector<SlowFunction> SlowFunctionVector;
struct ModuleImportGeneratorData
{
DeclaredSig* sig;
const DeclaredSig* sig;
uint32_t globalDataOffset;
ModuleImportGeneratorData() : sig(nullptr), globalDataOffset(0) {}
explicit ModuleImportGeneratorData(const DeclaredSig* sig) : sig(sig), globalDataOffset(0) {}
};
typedef Vector<ModuleImportGeneratorData, 0, SystemAllocPolicy> ModuleImportGeneratorDataVector;
// Global variable descriptor, in asm.js only.
struct AsmJSGlobalVariable {
struct AsmJSGlobalVariable
{
ExprType type;
unsigned globalDataOffset;
bool isConst;
@ -159,6 +161,7 @@ class MOZ_STACK_CLASS ModuleGenerator
bool finishTask(IonCompileTask* task);
bool addImport(const Sig& sig, uint32_t globalDataOffset);
bool startedFuncDefs() const { return !!threadView_; }
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
public:
explicit ModuleGenerator(ExclusiveContext* cx);
@ -171,8 +174,7 @@ class MOZ_STACK_CLASS ModuleGenerator
jit::MacroAssembler& masm() { return masm_; }
const Uint32Vector& funcEntryOffsets() const { return funcEntryOffsets_; }
// Global data:
bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
// asm.js global variables:
bool allocateGlobalVar(ValType type, bool isConst, uint32_t* 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;
// Imports:
bool initImport(uint32_t importIndex, uint32_t sigIndex, uint32_t globalDataOffset);
bool initImport(uint32_t importIndex, uint32_t sigIndex);
uint32_t numImports() const;
const ModuleImportGeneratorData& import(uint32_t index) const;
bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);

Просмотреть файл

@ -177,11 +177,9 @@ class Import
return pod.exitGlobalDataOffset_;
}
uint32_t interpExitCodeOffset() const {
MOZ_ASSERT(pod.interpExitCodeOffset_);
return pod.interpExitCodeOffset_;
}
uint32_t jitExitCodeOffset() const {
MOZ_ASSERT(pod.jitExitCodeOffset_);
return pod.jitExitCodeOffset_;
}

Просмотреть файл

@ -95,6 +95,7 @@ enum class WasmAstKind
Export,
Func,
GetLocal,
Import,
Module,
Nop,
SetLocal
@ -213,6 +214,21 @@ class WasmAstFunc : public WasmAstNode
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
{
TwoByteChars name_;
@ -229,12 +245,14 @@ class WasmAstExport : public WasmAstNode
class WasmAstModule : public WasmAstNode
{
typedef WasmAstVector<WasmAstFunc*> FuncVector;
typedef WasmAstVector<WasmAstImport*> ImportVector;
typedef WasmAstVector<WasmAstExport*> ExportVector;
typedef WasmAstVector<WasmAstSig*> SigVector;
typedef WasmAstHashMap<WasmAstSig*, uint32_t, WasmAstSig> SigMap;
LifoAlloc& lifo_;
FuncVector funcs_;
ImportVector imports_;
ExportVector exports_;
SigVector sigs_;
SigMap sigMap_;
@ -244,6 +262,7 @@ class WasmAstModule : public WasmAstNode
: WasmAstNode(WasmAstKind::Module),
lifo_(lifo),
funcs_(lifo),
imports_(lifo),
exports_(lifo),
sigs_(lifo),
sigMap_(lifo)
@ -270,6 +289,12 @@ class WasmAstModule : public WasmAstNode
const FuncVector& funcs() const {
return funcs_;
}
const ImportVector& imports() const {
return imports_;
}
bool append(WasmAstImport* imp) {
return imports_.append(imp);
}
bool append(WasmAstExport* exp) {
return exports_.append(exp);
}
@ -294,6 +319,7 @@ class WasmToken
Export,
Func,
GetLocal,
Import,
Integer,
Local,
Module,
@ -496,14 +522,12 @@ class WasmTokenStream
if (consume(end_, MOZ_UTF16("32"))) {
if (consume(end_, MOZ_UTF16(".const")))
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(".const")))
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;
@ -516,15 +540,15 @@ class WasmTokenStream
if (consume(end_, MOZ_UTF16("32"))) {
if (consume(end_, MOZ_UTF16(".const")))
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(".const")))
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;
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*
ParseFunc(WasmParseContext& c, WasmAstModule* module)
{
@ -746,44 +794,27 @@ ParseFunc(WasmParseContext& c, WasmAstModule* module)
WasmAstExpr* maybeBody = nullptr;
while (c.ts.getIf(WasmToken::OpenParen) && !maybeBody) {
WasmToken field = c.ts.get();
switch (field.kind()) {
case WasmToken::Local: {
WasmToken valueType;
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
return nullptr;
if (!vars.append(valueType.valueType()))
WasmToken token = c.ts.get();
switch (token.kind()) {
case WasmToken::Local:
if (!ParseValueType(c, &vars))
return nullptr;
break;
}
case WasmToken::Param: {
WasmToken valueType;
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
return nullptr;
if (!args.append(valueType.valueType()))
case WasmToken::Param:
if (!ParseValueType(c, &args))
return nullptr;
break;
}
case WasmToken::Result: {
if (result != ExprType::Void) {
c.ts.generateError(field, c.error);
case WasmToken::Result:
if (!ParseResult(c, &result))
return nullptr;
}
WasmToken valueType;
if (!c.ts.match(WasmToken::ValueType, &valueType, c.error))
return nullptr;
result = ToExprType(valueType.valueType());
break;
}
default:
c.ts.unget(field);
c.ts.unget(token);
maybeBody = ParseExprInsideParens(c);
if (!maybeBody)
return nullptr;
break;
}
if (!c.ts.match(WasmToken::CloseParen, c.error))
return nullptr;
}
@ -795,6 +826,46 @@ ParseFunc(WasmParseContext& c, WasmAstModule* module)
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*
ParseExport(WasmParseContext& c)
{
@ -827,6 +898,12 @@ TextToAst(const char16_t* text, LifoAlloc& lifo, UniqueChars* error)
WasmToken section = c.ts.get();
switch (section.kind()) {
case WasmToken::Import: {
WasmAstImport* imp = ParseImport(c, module);
if (!imp || !module->append(imp))
return nullptr;
break;
}
case WasmToken::Export: {
WasmAstExport* exp = ParseExport(c);
if (!exp || !module->append(exp))
@ -933,7 +1010,7 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
static bool
EncodeSignatureSection(Encoder& e, WasmAstModule& module)
{
if (module.funcs().empty())
if (module.sigs().empty())
return true;
if (!e.writeCString(SigSection))
@ -988,6 +1065,57 @@ EncodeDeclarationSection(Encoder& e, WasmAstModule& module)
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
EncodeExport(Encoder& e, WasmAstExport& exp)
{
@ -1109,6 +1237,9 @@ AstToBinary(WasmAstModule& module)
if (!EncodeDeclarationSection(e, module))
return nullptr;
if (!EncodeImportSection(e, module))
return nullptr;
if (!EncodeExportSection(e, module))
return nullptr;

Просмотреть файл

@ -95,6 +95,37 @@ wasmEvalText('(module (func (param f64)))');
assertErrorMessage(() => wasmEvalText('(module (func (param 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

Просмотреть файл

@ -18,8 +18,10 @@ const ver3 = 0xff;
// Section names
const sigSectionStr = "sig";
const declSectionStr = "decl";
const importSectionStr = "import";
const exportSectionStr = "export";
const codeSectionStr = "code";
const funcSubsectionStr = "func";
const magicError = /failed to match magic number/;
const versionError = /failed to match binary version/;
@ -36,7 +38,7 @@ const B32x4Code = 6;
const VoidCode = 7;
function toBuf(array) {
for (var b of array)
for (let b of array)
assertEq(b < 256, true);
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(0, 1))), TypeError, extraError);
function sectionName(name) {
function cstring(name) {
return (name + '\0').split('').map(c => c.charCodeAt(0));
}
@ -78,8 +80,8 @@ function sectionLength(length) {
function moduleWithSections(sectionArray) {
var bytes = moduleHeaderThen();
for (section of sectionArray) {
bytes.push(...sectionName(section.name));
for (let section of sectionArray) {
bytes.push(...cstring(section.name));
bytes.push(...sectionLength(section.body.length));
bytes.push(...section.body);
}
@ -90,15 +92,53 @@ function moduleWithSections(sectionArray) {
function sigSection(sigs) {
var body = [];
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.ret));
for (var arg of sig.args)
for (let arg of sig.args)
body.push(...varU32(arg));
}
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, 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:[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([{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:()=>{}});