From 8ff678788ada565d15273ca6ca872946f14584d6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 Sep 2016 16:48:20 -0700 Subject: support assert_malformed in shell test runner --- src/tools/wasm-shell.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/tools/wasm-shell.cpp') diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index a95ced87f..ddb2f8a85 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -34,6 +34,11 @@ using namespace cashew; using namespace wasm; +Name ASSERT_RETURN("assert_return"), + ASSERT_TRAP("assert_trap"), + ASSERT_INVALID("assert_invalid"), + ASSERT_MALFORMED("assert_malformed"); + // // An invocation into a module // @@ -109,7 +114,7 @@ static void run_asserts(size_t* i, bool* checked, Module* wasm, Colors::green(std::cerr); std::cerr << " [line: " << curr.line << "]\n"; Colors::normal(std::cerr); - if (id == ASSERT_INVALID) { + if (id == ASSERT_INVALID || id == ASSERT_MALFORMED) { // a module invalidity test Module wasm; bool invalid = false; -- cgit v1.2.3 From 0201f77b30f875de0d0fc8e407ffc985d47f8535 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 16 Sep 2016 21:08:58 -0700 Subject: support module operations in shell tests --- src/shared-constants.h | 1 - src/tools/wasm-shell.cpp | 83 ++++++++++++++++++++++++++++++++---------------- src/wasm-interpreter.h | 11 +++++++ src/wasm-s-parser.h | 4 +-- src/wasm.cpp | 1 - 5 files changed, 68 insertions(+), 32 deletions(-) (limited to 'src/tools/wasm-shell.cpp') diff --git a/src/shared-constants.h b/src/shared-constants.h index e37879088..2d656f0eb 100644 --- a/src/shared-constants.h +++ b/src/shared-constants.h @@ -49,7 +49,6 @@ extern Name GROW_WASM_MEMORY, FAKE_RETURN, SPECTEST, PRINT, - INVOKE, EXIT; } // namespace wasm diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index ddb2f8a85..e0bc5d7e9 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -37,28 +37,51 @@ using namespace wasm; Name ASSERT_RETURN("assert_return"), ASSERT_TRAP("assert_trap"), ASSERT_INVALID("assert_invalid"), - ASSERT_MALFORMED("assert_malformed"); + ASSERT_MALFORMED("assert_malformed"), + INVOKE("invoke"), + GET("get"); + +// Modules named in the file + +std::map> modules; +std::map> builders; +std::map> interfaces; +std::map> instances; // -// An invocation into a module +// An operation on a module // -struct Invocation { +struct Operation { ModuleInstance* instance; - IString name; + Name operation; + Name name; LiteralList arguments; - Invocation(Element& invoke, ModuleInstance* instance, SExpressionWasmBuilder& builder) : instance(instance) { - assert(invoke[0]->str() == INVOKE); - name = invoke[1]->str(); - for (size_t j = 2; j < invoke.size(); j++) { - Expression* argument = builder.parseExpression(*invoke[j]); + Operation(Element& element, ModuleInstance* instanceInit, SExpressionWasmBuilder& builder) : instance(instanceInit) { + operation = element[0]->str(); + Index i = 1; + if (element.size() >= 3 && element[2]->isStr()) { + // module also specified + Name moduleName = element[i++]->str(); + instance = instances[moduleName].get(); + } + name = element[i++]->str(); + for (size_t j = i; j < element.size(); j++) { + Expression* argument = builder.parseExpression(*element[j]); arguments.push_back(argument->dynCast()->value); } } - Literal invoke() { - return instance->callExport(name, arguments); + Literal operate() { + if (operation == INVOKE) { + return instance->callExport(name, arguments); + } else if (operation == GET) { + return instance->getExport(name); + } else { + Fatal() << "unknown operation: " << operation << '\n'; + WASM_UNREACHABLE(); + } } }; @@ -75,15 +98,17 @@ static void verify_result(Literal a, Literal b) { } } -static void run_asserts(size_t* i, bool* checked, Module* wasm, +static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm, Element* root, - std::unique_ptr* builder, + SExpressionWasmBuilder* builder, Name entry) { - std::unique_ptr interface; - std::unique_ptr instance; + ModuleInstance* instance = nullptr; if (wasm) { - interface = wasm::make_unique(); // prefix make_unique to work around visual studio bugs - instance = wasm::make_unique(*wasm, interface.get()); + auto tempInterface = wasm::make_unique(); // prefix make_unique to work around visual studio bugs + auto tempInstance = wasm::make_unique(*wasm, tempInterface.get()); + interfaces[moduleName].swap(tempInterface); + instances[moduleName].swap(tempInstance); + instance = instances[moduleName].get(); if (entry.is()) { Function* function = wasm->getFunction(entry); if (!function) { @@ -139,23 +164,23 @@ static void run_asserts(size_t* i, bool* checked, Module* wasm, } } else if (id == INVOKE) { assert(wasm); - Invocation invocation(curr, instance.get(), *builder->get()); - invocation.invoke(); + Operation operation(curr, instance, *builder); + operation.operate(); } else if (wasm) { // if no wasm, we skipped the module // an invoke test bool trapped = false; WASM_UNUSED(trapped); Literal result; try { - Invocation invocation(*curr[1], instance.get(), *builder->get()); - result = invocation.invoke(); + Operation operation(*curr[1], instance, *builder); + result = operation.operate(); } catch (const TrapException&) { trapped = true; } if (id == ASSERT_RETURN) { assert(!trapped); if (curr.size() >= 3) { - Literal expected = builder->get() + Literal expected = builder ->parseExpression(*curr[2]) ->dynCast() ->value; @@ -234,14 +259,16 @@ int main(int argc, const char* argv[]) { Colors::green(std::cerr); std::cerr << "BUILDING MODULE [line: " << curr.line << "]\n"; Colors::normal(std::cerr); - Module wasm; - std::unique_ptr builder; - builder = wasm::make_unique(wasm, *root[i]); + auto module = wasm::make_unique(); + Name moduleName; + auto builder = wasm::make_unique(*module, *root[i], &moduleName); + builders[moduleName].swap(builder); + modules[moduleName].swap(module); i++; - assert(WasmValidator().validate(wasm)); - run_asserts(&i, &checked, &wasm, &root, &builder, entry); + assert(WasmValidator().validate(*modules[moduleName])); + run_asserts(moduleName, &i, &checked, modules[moduleName].get(), &root, builders[moduleName].get(), entry); } else { - run_asserts(&i, &checked, nullptr, &root, nullptr, entry); + run_asserts(Name(), &i, &checked, nullptr, &root, nullptr, entry); } } } catch (ParseException& p) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 5d4e7d7b4..f699ba6f8 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -554,12 +554,23 @@ public: } } + // call an exported function Literal callExport(Name name, LiteralList& arguments) { Export *export_ = wasm.checkExport(name); if (!export_) externalInterface->trap("callExport not found"); return callFunction(export_->value, arguments); } + // get an exported global + Literal getExport(Name name) { + Export *export_ = wasm.checkExport(name); + if (!export_) externalInterface->trap("getExport external not found"); + Name internalName = export_->value; + auto iter = globals.find(internalName); + if (iter == globals.end()) externalInterface->trap("getExport internal not found"); + return iter->second; + } + std::string printFunctionStack() { std::string ret = "/== (binaryen interpreter stack trace)\n"; for (int i = int(functionStack.size()) - 1; i >= 0; i--) { diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index f244a08f9..0f11bd521 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -1473,7 +1473,7 @@ private: ex->kind = Export::Table; } else if (inner[0]->str() == GLOBAL) { ex->value = inner[1]->str(); - ex->kind = Export::Table; + ex->kind = Export::Global; } else { WASM_UNREACHABLE(); } @@ -1487,7 +1487,7 @@ private: ex->kind = Export::Table; } else if (s[2]->str() == GLOBAL) { ex->value = s[3]->str(); - ex->kind = Export::Table; + ex->kind = Export::Global; } else { WASM_UNREACHABLE(); } diff --git a/src/wasm.cpp b/src/wasm.cpp index 144cabd16..8badaa6be 100644 --- a/src/wasm.cpp +++ b/src/wasm.cpp @@ -74,7 +74,6 @@ Name GROW_WASM_MEMORY("__growWasmMemory"), FAKE_RETURN("fake_return_waka123"), SPECTEST("spectest"), PRINT("print"), - INVOKE("invoke"), EXIT("exit"); // core AST type checking -- cgit v1.2.3 From 552d700c7e21afae03e55b6d6574a67946510972 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 20 Sep 2016 10:38:36 -0700 Subject: global importing fixes: use the right counter for globals and for functions --- src/tools/wasm-shell.cpp | 13 ++++++++++- src/wasm-s-parser.h | 60 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 14 deletions(-) (limited to 'src/tools/wasm-shell.cpp') diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index e0bc5d7e9..320ed01e9 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -38,6 +38,7 @@ Name ASSERT_RETURN("assert_return"), ASSERT_TRAP("assert_trap"), ASSERT_INVALID("assert_invalid"), ASSERT_MALFORMED("assert_malformed"), + ASSERT_UNLINKABLE("assert_unlinkable"), INVOKE("invoke"), GET("get"); @@ -139,7 +140,7 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm, Colors::green(std::cerr); std::cerr << " [line: " << curr.line << "]\n"; Colors::normal(std::cerr); - if (id == ASSERT_INVALID || id == ASSERT_MALFORMED) { + if (id == ASSERT_INVALID || id == ASSERT_MALFORMED || id == ASSERT_UNLINKABLE) { // a module invalidity test Module wasm; bool invalid = false; @@ -155,6 +156,16 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm, // maybe parsed ok, but otherwise incorrect invalid = !WasmValidator().validate(wasm); } + if (!invalid && id == ASSERT_UNLINKABLE) { + // validate "instantiating" the mdoule + for (auto& import : wasm.imports) { + if (import->module != SPECTEST || import->base != PRINT) { + std::cerr << "unknown import: " << import->module << '.' << import->base << '\n'; + invalid = true; + break; + } + } + } if (!invalid) { Colors::red(std::cerr); std::cerr << "[should have been invalid]\n"; diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 592c84803..0d2a44407 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -80,7 +80,7 @@ public: } Element* operator[](unsigned i) { - if (i >= list().size()) throw ParseException("expected more elements in list", line, col); + if (i >= list().size()) assert(0 && "expected more elements in list"); return list()[i]; } @@ -270,13 +270,12 @@ class SExpressionWasmBuilder { MixedArena& allocator; std::vector functionNames; int functionCounter; - int importCounter; int globalCounter; std::map functionTypes; // we need to know function return types before we parse their contents public: // Assumes control of and modifies the input. - SExpressionWasmBuilder(Module& wasm, Element& module, Name* moduleName = nullptr) : wasm(wasm), allocator(wasm.allocator), importCounter(0), globalCounter(0) { + SExpressionWasmBuilder(Module& wasm, Element& module, Name* moduleName = nullptr) : wasm(wasm), allocator(wasm.allocator), globalCounter(0) { assert(module[0]->str() == MODULE); if (module.size() == 1) return; Index i = 1; @@ -385,6 +384,7 @@ private: if (id == IMPORT) parseImport(curr); if (isImport(curr)) { if (id == FUNC) parseFunction(curr, true /* preParseImport */); + else if (id == GLOBAL) parseGlobal(curr, true /* preParseImport */); else throw ParseException("fancy import we don't support yet", curr.line, curr.col); } } @@ -589,9 +589,8 @@ private: std::unique_ptr im = make_unique(); im->name = name; if (!im->name.is()) { - im->name = Name::fromInt(importCounter); + im->name = name; } - importCounter++; im->module = importModule; im->base = importBase; im->kind = Import::Function; @@ -640,6 +639,10 @@ private: abort(); } + bool isWasmType(IString str) { + return stringToWasmType(str, true) != none; + } + public: Expression* parseExpression(Element* s) { return parseExpression(*s); @@ -1562,12 +1565,26 @@ private: Index newStyleInner = 1; if (s.size() > 3 && s[3]->isStr()) { im->name = s[i++]->str(); - } else if (newStyle && (*s[3])[newStyleInner]->isStr()) { - im->name = (*s[3])[newStyleInner++]->str(); - } else { - im->name = Name::fromInt(importCounter); + } else if (newStyle && newStyleInner < s[3]->size() && (*s[3])[newStyleInner]->isStr()) { + auto str = (*s[3])[newStyleInner]->str(); + if (!isWasmType(str)) { + im->name = str; + newStyleInner++; + } + } + if (!im->name.is()) { + if (im->kind == Import::Function) { + im->name = Name::fromInt(functionCounter++); + } else if (im->kind == Import::Global) { + im->name = Name::fromInt(globalCounter++); + } else if (im->kind == Import::Memory) { + im->name = Name::fromInt(0); + } else if (im->kind == Import::Table) { + im->name = Name::fromInt(0); + } else { + WASM_UNREACHABLE(); + } } - importCounter++; if (!s[i]->quoted()) { if (s[i]->str() == MEMORY) { im->kind = Import::Memory; @@ -1626,7 +1643,7 @@ private: wasm.addImport(im.release()); } - void parseGlobal(Element& s) { + void parseGlobal(Element& s, bool preParseImport = false) { std::unique_ptr global = make_unique(); size_t i = 1; if (s[i]->dollared()) { @@ -1638,7 +1655,8 @@ private: bool mutable_ = false; WasmType type = none; bool exported = false; - while (s[i]->isList()) { + Name importModule, importBase; + while (i < s.size() && s[i]->isList()) { auto& inner = *s[i]; if (inner[0]->str() == EXPORT) { auto ex = make_unique(); @@ -1650,7 +1668,9 @@ private: exported = true; i++; } else if (inner[0]->str() == IMPORT) { - throw ParseException("TODO: import in the middle of a global definition", s.line, s.col); + importModule = inner[1]->str(); + importBase = inner[2]->str(); + i++; } else if (inner[0]->str() == MUT) { mutable_ = true; type = stringToWasmType(inner[1]->str()); @@ -1663,6 +1683,20 @@ private: if (type == none) { type = stringToWasmType(s[i++]->str()); } + if (importModule.is()) { + // this is an import, actually + assert(preParseImport); + if (mutable_) throw ParseException("cannot import a mutable global", s.line, s.col); + std::unique_ptr im = make_unique(); + im->name = global->name; + im->module = importModule; + im->base = importBase; + im->kind = Import::Global; + im->globalType = type; + wasm.addImport(im.release()); + return; + } + assert(!preParseImport); global->type = type; global->init = parseExpression(s[i++]); global->mutable_ = mutable_; -- cgit v1.2.3 From 469d90aaf3d708ffcb0f9f28b29120524055ba6f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 20 Sep 2016 11:13:23 -0700 Subject: validate spectest.print as a function --- src/tools/wasm-shell.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/tools/wasm-shell.cpp') diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 320ed01e9..83d39c9d4 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -159,7 +159,13 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm, if (!invalid && id == ASSERT_UNLINKABLE) { // validate "instantiating" the mdoule for (auto& import : wasm.imports) { - if (import->module != SPECTEST || import->base != PRINT) { + if (import->module == SPECTEST && import->base == PRINT) { + if (import->kind != Import::Function) { + std::cerr << "spectest.print should be a function, but is " << import->kind << '\n'; + invalid = true; + break; + } + } else { std::cerr << "unknown import: " << import->module << '.' << import->base << '\n'; invalid = true; break; -- cgit v1.2.3 From c79bbb19b59161e0768674816b477f74355912b1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 21 Sep 2016 15:30:12 -0700 Subject: error on putting spectest.print in a table --- src/shell-interface.h | 4 ++++ src/tools/wasm-shell.cpp | 11 +++++++++++ 2 files changed, 15 insertions(+) (limited to 'src/tools/wasm-shell.cpp') diff --git a/src/shell-interface.h b/src/shell-interface.h index 8cb7c2672..b9a90131b 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -122,6 +122,10 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { case f64: globals[import->name] = Literal(double(666.6)); break; default: WASM_UNREACHABLE(); } + } else if (import->kind == Import::Memory && import->module == SPECTEST && import->base == MEMORY) { + // imported memory has initial 1 and max 2 + wasm.memory.initial = 1; + wasm.memory.max = 2; } } } diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 83d39c9d4..670f5783d 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -171,6 +171,17 @@ static void run_asserts(Name moduleName, size_t* i, bool* checked, Module* wasm, break; } } + for (auto& segment : wasm.table.segments) { + for (auto name : segment.data) { + // spec tests consider it illegal to use spectest.print in a table + if (auto* import = wasm.checkImport(name)) { + if (import->module == SPECTEST && import->base == PRINT) { + std::cerr << "cannot put spectest.print in table\n"; + invalid = true; + } + } + } + } } if (!invalid) { Colors::red(std::cerr); -- cgit v1.2.3