summaryrefslogtreecommitdiff
path: root/src/binaryen-shell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/binaryen-shell.cpp')
-rw-r--r--src/binaryen-shell.cpp166
1 files changed, 100 insertions, 66 deletions
diff --git a/src/binaryen-shell.cpp b/src/binaryen-shell.cpp
index 55beb6aa8..b0965344c 100644
--- a/src/binaryen-shell.cpp
+++ b/src/binaryen-shell.cpp
@@ -44,7 +44,11 @@ IString ASSERT_RETURN("assert_return"),
ASSERT_INVALID("assert_invalid"),
SPECTEST("spectest"),
PRINT("print"),
- INVOKE("invoke");
+ INVOKE("invoke"),
+ EXIT("exit");
+
+struct ExitException {
+};
//
// Implementation of the shell interpreter execution environment
@@ -59,6 +63,7 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
memory = (char*)calloc(wasm.memory.initial, 1);
// apply memory segments
for (auto segment : wasm.memory.segments) {
+ assert(segment.offset + segment.size <= wasm.memory.initial);
memcpy(memory + segment.offset, segment.data, segment.size);
}
}
@@ -69,6 +74,9 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
std::cout << argument << '\n';
}
return Literal();
+ } else if (import->module == ENV && import->base == EXIT) {
+ std::cout << "exit()\n";
+ throw ExitException();
}
std::cout << "callImport " << import->name.str << "\n";
abort();
@@ -169,6 +177,87 @@ struct Invocation {
}
};
+static void run_asserts(size_t* i, bool* checked, AllocatingModule* wasm,
+ Element* root,
+ std::unique_ptr<SExpressionWasmBuilder>* builder,
+ bool print_before, bool print_after,
+ Name entry) {
+ auto interface = new ShellExternalInterface();
+ auto instance = new ModuleInstance(*wasm, interface);
+ if (entry.is() > 0) {
+ ModuleInstance::LiteralList arguments;
+ try {
+ instance->callExport(entry, arguments);
+ } catch (ExitException& x) {
+ }
+ }
+ while (*i < root->size()) {
+ Element& curr = *(*root)[*i];
+ IString id = curr[0]->str();
+ if (id == MODULE) break;
+ *checked = true;
+ Colors::red(std::cerr);
+ std::cerr << *i << '/' << (root->size()-1);
+ Colors::green(std::cerr);
+ std::cerr << " CHECKING: ";
+ Colors::normal(std::cerr);
+ std::cerr << curr << '\n';
+ if (id == ASSERT_INVALID) {
+ // a module invalidity test
+ AllocatingModule wasm;
+ bool invalid = false;
+ jmp_buf trapState;
+ if (setjmp(trapState) == 0) {
+ *builder = std::unique_ptr<SExpressionWasmBuilder>(new SExpressionWasmBuilder(wasm, *curr[1], [&]() {
+ invalid = true;
+ longjmp(trapState, 1);
+ }));
+ }
+ if (print_before || print_after) {
+ Colors::bold(std::cout);
+ std::cerr << "printing in module invalidity test:\n";
+ Colors::normal(std::cout);
+ std::cout << wasm;
+ }
+ if (!invalid) {
+ // maybe parsed ok, but otherwise incorrect
+ invalid = !WasmValidator().validate(wasm);
+ }
+ assert(invalid);
+ } else if (id == INVOKE) {
+ Invocation invocation(curr, instance, *builder->get());
+ invocation.invoke();
+ } else {
+ // an invoke test
+ Invocation invocation(*curr[1], instance, *builder->get());
+ bool trapped = false;
+ Literal result;
+ if (setjmp(interface->trapState) == 0) {
+ result = invocation.invoke();
+ } else {
+ trapped = true;
+ }
+ if (id == ASSERT_RETURN) {
+ assert(!trapped);
+ if (curr.size() >= 3) {
+ Literal expected = builder->get()
+ ->parseExpression(*curr[2])
+ ->dyn_cast<Const>()
+ ->value;
+ std::cerr << "seen " << result << ", expected " << expected << '\n';
+ assert(expected == result);
+ } else {
+ Literal expected;
+ std::cerr << "seen " << result << ", expected " << expected << '\n';
+ assert(expected == result);
+ }
+ }
+ if (id == ASSERT_TRAP) assert(trapped);
+ }
+ *i += 1;
+ }
+}
+
//
// main
//
@@ -180,6 +269,7 @@ int main(int argc, char **argv) {
bool print_before = false;
bool print_after = false;
std::vector<std::string> passes;
+ Name entry;
assert(argc > 0 && "expect at least program name as an argument");
for (size_t i = 1, e = argc; i != e; i++) {
@@ -198,6 +288,9 @@ int main(int argc, char **argv) {
std::cout << " -print-before : print modules before processing them\n";
std::cout << " -print-after : print modules after processing them\n";
std::cout << "\n";
+ std::cout << "execution options:\n";
+ std::cout << " --entry=[ENTRY] : call ENTRY() after parsing the module\n";
+ std::cout << "\n";
std::cout << "passes:\n";
std::cout << " -O : execute default optimization passes\n";
auto allPasses = PassRegistry::get()->getRegisteredNames();
@@ -211,6 +304,8 @@ int main(int argc, char **argv) {
passes.push_back("remove-unused-names");
passes.push_back("merge-blocks");
passes.push_back("simplify-locals");
+ } else if (arg.substr(0, 7) == "--entry") {
+ entry = Name(strchr(curr, '=') + 1);
} else {
// otherwise, assumed to be a pass
const char* name = curr + 1;
@@ -265,12 +360,10 @@ int main(int argc, char **argv) {
while (i < root.size()) {
if (debug) std::cerr << "parsing s-expressions to wasm...\n";
AllocatingModule wasm;
- SExpressionWasmBuilder builder(wasm, *root[i], [&]() { abort(); }, debug);
+ std::unique_ptr<SExpressionWasmBuilder> builder(
+ new SExpressionWasmBuilder(wasm, *root[i], [&]() { abort(); }, debug));
i++;
- auto interface = new ShellExternalInterface();
- auto instance = new ModuleInstance(wasm, interface);
-
if (print_before) {
Colors::bold(std::cout);
std::cerr << "printing before:\n";
@@ -296,67 +389,8 @@ int main(int argc, char **argv) {
std::cout << wasm;
}
- // run asserts
- while (i < root.size()) {
- Element& curr = *root[i];
- IString id = curr[0]->str();
- if (id == MODULE) break;
- checked = true;
- Colors::red(std::cerr);
- std::cerr << i << '/' << (root.size()-1);
- Colors::green(std::cerr);
- std::cerr << " CHECKING: ";
- Colors::normal(std::cerr);
- std::cerr << curr << '\n';
- if (id == ASSERT_INVALID) {
- // a module invalidity test
- AllocatingModule wasm;
- bool invalid = false;
- jmp_buf trapState;
- std::unique_ptr<SExpressionWasmBuilder> builder;
- if (setjmp(trapState) == 0) {
- builder = std::unique_ptr<SExpressionWasmBuilder>(new SExpressionWasmBuilder(wasm, *curr[1], [&]() {
- invalid = true;
- longjmp(trapState, 1);
- }));
- }
- if (print_before || print_after) {
- Colors::bold(std::cout);
- std::cerr << "printing in module invalidity test:\n";
- Colors::normal(std::cout);
- std::cout << wasm;
- }
- if (!invalid) {
- // maybe parsed ok, but otherwise incorrect
- invalid = !WasmValidator().validate(wasm);
- }
- assert(invalid);
- } else if (id == INVOKE) {
- Invocation invocation(curr, instance, builder);
- invocation.invoke();
- } else {
- // an invoke test
- Invocation invocation(*curr[1], instance, builder);
- bool trapped = false;
- Literal result;
- if (setjmp(interface->trapState) == 0) {
- result = invocation.invoke();
- } else {
- trapped = true;
- }
- if (id == ASSERT_RETURN) {
- assert(!trapped);
- Literal expected;
- if (curr.size() >= 3) {
- expected = builder.parseExpression(*curr[2])->dyn_cast<Const>()->value;
- }
- std::cerr << "seen " << result << ", expected " << expected << '\n';
- assert(expected == result);
- }
- if (id == ASSERT_TRAP) assert(trapped);
- }
- i++;
- }
+ run_asserts(&i, &checked, &wasm, &root, &builder, print_before,
+ print_after, entry);
}
if (checked) {