summaryrefslogtreecommitdiff
path: root/src/wasm-shell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-shell.cpp')
-rw-r--r--src/wasm-shell.cpp86
1 files changed, 84 insertions, 2 deletions
diff --git a/src/wasm-shell.cpp b/src/wasm-shell.cpp
index 7eb4b847a..89c51c293 100644
--- a/src/wasm-shell.cpp
+++ b/src/wasm-shell.cpp
@@ -3,7 +3,10 @@
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format) and executes it.
//
+#include <setjmp.h>
+
#include "wasm-s-parser.h"
+#include "wasm-interpreter.h"
using namespace cashew;
using namespace wasm;
@@ -12,6 +15,78 @@ IString ASSERT_RETURN("assert_return"),
ASSERT_TRAP("assert_trap"),
INVOKE("invoke");
+//
+// Implementation of the shell interpreter execution environment
+//
+
+struct ShellExternalInterface : ModuleInstance::ExternalInterface {
+ char *memory;
+ size_t memorySize;
+
+ ShellExternalInterface() : memory(nullptr) {}
+
+ void init(Module& wasm) override {
+ memory = new char[wasm.memory.initial];
+ memorySize = wasm.memory.initial;
+ }
+
+ jmp_buf trapState;
+
+ void trap() {
+ longjmp(trapState, 1);
+ }
+
+ Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override {
+ std::cout << "callImport " << import->name.str << "\n";
+ abort();
+ }
+
+ Literal load(Load* load, Literal ptr) override {
+ // ignore align - assume we are on x86 etc. which does that
+ size_t addr = ptr.geti32();
+ int64_t full = addr;
+ full += load->offset;
+ if (full + load->bytes >= memorySize) trap();
+ addr = full;
+ switch (load->type) {
+ case i32: {
+ switch (load->bytes) {
+ case 1: return load->signed_ ? (int32_t)((int8_t*)memory)[addr] : (int32_t)((uint8_t*)memory)[addr];
+ case 2: return load->signed_ ? (int32_t)((int16_t*)memory)[addr] : (int32_t)((uint16_t*)memory)[addr];
+ case 4: return load->signed_ ? (int32_t)((int32_t*)memory)[addr] : (int32_t)((uint32_t*)memory)[addr];
+ default: abort();
+ }
+ break;
+ }
+ case f32: return ((float*)memory)[addr];
+ case f64: return ((double*)memory)[addr];
+ default: abort();
+ }
+ }
+
+ void store(Store* store, Literal ptr, Literal value) override {
+ // ignore align - assume we are on x86 etc. which does that
+ size_t addr = ptr.geti32();
+ int64_t full = addr;
+ full += store->offset;
+ if (full + store->bytes >= memorySize) trap();
+ switch (store->type) {
+ case i32: {
+ switch (store->bytes) {
+ case 1: ((int8_t*)memory)[addr] = value.geti32();
+ case 2: ((int16_t*)memory)[addr] = value.geti32();
+ case 4: ((int32_t*)memory)[addr] = value.geti32();
+ default: abort();
+ }
+ break;
+ }
+ case f32: ((float*)memory)[addr] = value.getf32();
+ case f64: ((double*)memory)[addr] = value.getf64();
+ default: abort();
+ }
+ }
+};
+
int main(int argc, char **argv) {
debug = getenv("WASM_SHELL_DEBUG") ? getenv("WASM_SHELL_DEBUG")[0] - '0' : 0;
@@ -46,6 +121,9 @@ int main(int argc, char **argv) {
SExpressionWasmBuilder builder(wasm, *root[i]);
i++;
+ auto interface = new ShellExternalInterface();
+ auto instance = new ModuleInstance(wasm, interface);
+
if (print_wasm) {
if (debug) std::cerr << "printing...\n";
std::cout << wasm;
@@ -59,12 +137,16 @@ int main(int argc, char **argv) {
Element& invoke = *curr[1];
assert(invoke[0]->str() == INVOKE);
IString name = invoke[1]->str();
- LiteralList arguments;
+ ModuleInstance::LiteralList arguments;
for (size_t j = 2; j < invoke.size(); j++) {
Expression* argument = builder.parseExpression(*invoke[2]);
arguments.push_back(argument->dyn_cast<Const>()->value);
}
- interpreter.callFunction(name, arguments);
+ if (setjmp(interface->trapState) == 0) {
+ instance->callFunction(name, arguments);
+ } else {
+ std::cout << "TRAPPED\n";
+ }
i++;
}
}