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/wasm.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/wasm.cpp') diff --git a/src/wasm.cpp b/src/wasm.cpp index f6486eb50..144cabd16 100644 --- a/src/wasm.cpp +++ b/src/wasm.cpp @@ -72,9 +72,6 @@ Name GROW_WASM_MEMORY("__growWasmMemory"), BR("br"), ANYFUNC("anyfunc"), FAKE_RETURN("fake_return_waka123"), - ASSERT_RETURN("assert_return"), - ASSERT_TRAP("assert_trap"), - ASSERT_INVALID("assert_invalid"), SPECTEST("spectest"), PRINT("print"), INVOKE("invoke"), -- 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/wasm.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 38dc263c303be13bec2fcee713bdb18fa89057c8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 19 Sep 2016 14:02:57 -0700 Subject: global parsing --- src/shared-constants.h | 1 + src/wasm-binary.h | 1 + src/wasm-s-parser.h | 38 +++++++++++++++++++++++++++++++++----- src/wasm.cpp | 1 + src/wasm.h | 1 + 5 files changed, 37 insertions(+), 5 deletions(-) (limited to 'src/wasm.cpp') diff --git a/src/shared-constants.h b/src/shared-constants.h index 2d656f0eb..923ccc7de 100644 --- a/src/shared-constants.h +++ b/src/shared-constants.h @@ -47,6 +47,7 @@ extern Name GROW_WASM_MEMORY, BR, ANYFUNC, FAKE_RETURN, + MUT, SPECTEST, PRINT, EXIT; diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 9b8451b98..147746c82 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1653,6 +1653,7 @@ public: auto curr = new Global; curr->type = getWasmType(); curr->init = readExpression(); + curr->mutable_ = true; // TODO wasm.addGlobal(curr); } } diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 5acae1e6b..b4fcd3466 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -383,7 +383,10 @@ private: void preParseImports(Element& curr) { IString id = curr[0]->str(); if (id == IMPORT) parseImport(curr); - if (id == FUNC && isImport(curr)) parseFunction(curr, true /* preParseImport */); + if (isImport(curr)) { + if (id == FUNC) parseFunction(curr, true /* preParseImport */); + else throw ParseException("fancy import we don't support yet", curr.line, curr.col); + } } void parseModuleElement(Element& curr) { @@ -1022,6 +1025,7 @@ private: Expression* makeSetGlobal(Element& s) { auto ret = allocator.alloc(); ret->name = s[1]->str(); + if (wasm.checkGlobal(ret->name) && !wasm.checkGlobal(ret->name)->mutable_) throw ParseException("set_global of immutable", s.line, s.col); ret->value = parseExpression(s[2]); return ret; } @@ -1513,6 +1517,8 @@ private: ex->kind = Export::Table; } else if (inner[0]->str() == GLOBAL) { ex->kind = Export::Global; + auto* global = wasm.getGlobal(ex->value); + if (global->mutable_) throw ParseException("cannot export a mutable global", s.line, s.col); } else { WASM_UNREACHABLE(); } @@ -1609,7 +1615,14 @@ private: } im->functionType = ensureFunctionType(getSig(type.get()), &wasm); } else if (im->kind == Import::Global) { - im->globalType = stringToWasmType(inner[j]->str()); + if (inner[j]->isStr()) { + im->globalType = stringToWasmType(inner[j]->str()); + } else { + auto& inner2 = *inner[j]; + assert(inner2[0]->str() == MUT); + im->globalType = stringToWasmType(inner2[1]->str()); + throw ParseException("cannot import a mutable global", s.line, s.col); + } } wasm.addImport(im.release()); } @@ -1623,7 +1636,10 @@ private: global->name = Name::fromInt(globalCounter); } globalCounter++; - if (s[i]->isList()) { + bool mutable_ = false; + WasmType type = none; + bool exported = false; + while (s[i]->isList()) { auto& inner = *s[i]; if (inner[0]->str() == EXPORT) { auto ex = make_unique(); @@ -1632,13 +1648,25 @@ private: ex->kind = Export::Global; if (wasm.checkExport(ex->name)) throw ParseException("duplicate export", s.line, s.col); wasm.addExport(ex.release()); + exported = true; + i++; + } else if (inner[0]->str() == IMPORT) { + throw ParseException("TODO: import in the middle of a global definition", s.line, s.col); + } else if (inner[0]->str() == MUT) { + mutable_ = true; + type = stringToWasmType(inner[1]->str()); i++; } else { - WASM_UNREACHABLE(); + break; } } - global->type = stringToWasmType(s[i++]->str()); + if (exported && mutable_) throw ParseException("cannot export a mutable global", s.line, s.col); + if (type == none) { + type = stringToWasmType(s[i++]->str()); + } + global->type = type; global->init = parseExpression(s[i++]); + global->mutable_ = mutable_; assert(i == s.size()); wasm.addGlobal(global.release()); } diff --git a/src/wasm.cpp b/src/wasm.cpp index 8badaa6be..a910575f0 100644 --- a/src/wasm.cpp +++ b/src/wasm.cpp @@ -72,6 +72,7 @@ Name GROW_WASM_MEMORY("__growWasmMemory"), BR("br"), ANYFUNC("anyfunc"), FAKE_RETURN("fake_return_waka123"), + MUT("mut"), SPECTEST("spectest"), PRINT("print"), EXIT("exit"); diff --git a/src/wasm.h b/src/wasm.h index 1bce0bac9..5c20a3a10 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1523,6 +1523,7 @@ public: Name name; WasmType type; Expression* init; + bool mutable_; }; class Module { -- cgit v1.2.3