diff --git a/.github/workflows/publish-standalone.yml b/.github/workflows/publish-standalone.yml new file mode 100644 index 0000000..c6298d5 --- /dev/null +++ b/.github/workflows/publish-standalone.yml @@ -0,0 +1,13 @@ +name: Publish Standalone + +on: + workflow_dispatch: + +jobs: + publish-standalone: + needs: build + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - uses: ./.github/actions/setup + - run: make -C src/standalone install-deps all \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1f6d6a5..789e025 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +/.vscode/*.log node_modules/ public/waforth/ public/thurtle/ diff --git a/src/standalone/.gitignore b/src/standalone/.gitignore index 497e8d4..78be286 100644 --- a/src/standalone/.gitignore +++ b/src/standalone/.gitignore @@ -1,3 +1,4 @@ /waforth /waforth_core.h /wasm-micro-runtime +/wasmtime-* diff --git a/src/standalone/Makefile b/src/standalone/Makefile index b115875..84a7dd4 100644 --- a/src/standalone/Makefile +++ b/src/standalone/Makefile @@ -1,16 +1,20 @@ -WAMR_DIR=wasm-micro-runtime -CC=clang -CFLAGS=-g -I$(WAMR_DIR)/core/iwasm/include -DWASM_ENABLE_DEBUG_INTERP -LDFLAGS=-g -L$(WAMR_DIR)/product-mini/platforms/darwin/build -rpath $(WAMR_DIR)/product-mini/platforms/darwin/build -LIBS=-liwasm +WASMTIME_DIR=wasmtime-v0.37.0-x86_64-macos-c-api +WASMTIME_RELEASE_URL=https://github.com/bytecodealliance/wasmtime/releases/download/v0.37.0/wasmtime-v0.37.0-x86_64-macos-c-api.tar.xz + +CFLAGS=-I$(WASMTIME_DIR)/include +LDFLAGS= +LIBS=$(WASMTIME_DIR)/lib/libwasmtime.a BIN2H=../../scripts/bin2h WAT2WASM=wat2wasm +WAT2WASM_FLAGS=--debug-names OBJECTS=main.o -all: $(OBJECTS) - $(CC) -o waforth $(OBJECTS) $(LDFLAGS) $(LIBS) +all: waforth + +waforth: $(OBJECTS) + $(CC) -o $@ $(OBJECTS) $(LDFLAGS) $(LIBS) main.o: waforth_core.h @@ -18,4 +22,14 @@ waforth_core.wasm: ../waforth.wat $(WAT2WASM) $(WAT2WASM_FLAGS) -o $@ $< waforth_core.h: waforth_core.wasm - $(BIN2H) ../waforth.wasm waforth_core.h \ No newline at end of file + $(BIN2H) $< $@ + +.PHONY: install-deps +install-deps: + -rm -rf wasmtime-* + curl -L -s $(WASMTIME_RELEASE_URL) | tar xvz + + +.PHONY: clean +clean: + -rm -f waforth_core.wasm waforth_core.h $(OBJECTS) waforth diff --git a/src/standalone/main.c b/src/standalone/main.c index 2129a74..506e9d5 100644 --- a/src/standalone/main.c +++ b/src/standalone/main.c @@ -1,7 +1,8 @@ -#include "waforth_core.h" -#include "wasm_c_api.h" #include +#include "waforth_core.h" +#include "wasm.h" + #define CORE_TABLE_EXPORT_INDEX 0 #define CORE_MEMORY_EXPORT_INDEX 1 #define CORE_INTERPRET_EXPORT_INDEX 6 @@ -10,6 +11,10 @@ wasm_memory_t *memory; wasm_table_t *table; wasm_store_t *store; +//////////////////////////////////////////////////////////////////////////////// +// Utility +//////////////////////////////////////////////////////////////////////////////// + wasm_trap_t *trap_from_string(const char *s) { wasm_name_t message; wasm_name_new_from_string_nt(&message, s); @@ -18,6 +23,17 @@ wasm_trap_t *trap_from_string(const char *s) { return trap; } +void print_trap(wasm_trap_t *trap) { + wasm_name_t message; + wasm_trap_message(trap, &message); + printf(">> %s\n", message.data); + wasm_name_delete(&message); +} + +//////////////////////////////////////////////////////////////////////////////// +// Callbacks +//////////////////////////////////////////////////////////////////////////////// + wasm_trap_t *emit_cb(const wasm_val_vec_t *args, wasm_val_vec_t *results) { printf("%c", args->data[0].of.i32); return NULL; @@ -29,6 +45,9 @@ wasm_trap_t *read_cb(const wasm_val_vec_t *args, wasm_val_vec_t *results) { size_t len = args->data[1].of.i32; while (!(n = getline(&addr, &len, stdin))) { } + if (n < 0) { + n = 0; + } results->data[0].kind = WASM_I32; results->data[0].of.i32 = n; return NULL; @@ -49,8 +68,14 @@ wasm_trap_t *load_cb(const wasm_val_vec_t *args, wasm_val_vec_t *results) { } wasm_extern_t *externs[] = {wasm_table_as_extern(table), wasm_memory_as_extern(memory)}; wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); - wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); + wasm_trap_t *trap = NULL; + wasm_instance_t *instance = wasm_instance_new(store, module, &imports, &trap); if (!instance) { + printf("> Error instantiating loaded module!\n"); + if (trap) { + print_trap(trap); + wasm_trap_delete(trap); + } return trap_from_string("error instantiating module"); } return NULL; @@ -64,41 +89,9 @@ wasm_trap_t *call_cb(void *env, const wasm_val_vec_t *args, wasm_val_vec_t *resu return trap; } -// void print_frame(wasm_frame_t *frame) { -// printf("> %p @ 0x%zx = %" PRIu32 ".0x%zx\n", wasm_frame_instance(frame), wasm_frame_module_offset(frame), wasm_frame_func_index(frame), -// wasm_frame_func_offset(frame)); -// } - -void print_trap(wasm_trap_t *trap) { - printf("Printing message...\n"); - wasm_name_t message; - wasm_trap_message(trap, &message); - printf("> %s\n", message.data); - - // printf("Printing origin...\n"); - // wasm_frame_t *frame = wasm_trap_origin(trap); - // if (frame) { - // print_frame(frame); - // wasm_frame_delete(frame); - // } else { - // printf("> Empty origin.\n"); - // } - - // printf("Printing trace...\n"); - // wasm_frame_vec_t trace; - // wasm_trap_trace(trap, &trace); - // if (trace.size > 0) { - // for (size_t i = 0; i < trace.size; ++i) { - // print_frame(trace.data[i]); - // } - // } else { - // printf("> Empty trace.\n"); - // } - - // wasm_frame_vec_delete(&trace); - wasm_trap_delete(trap); - wasm_name_delete(&message); -} +//////////////////////////////////////////////////////////////////////////////// +// Main +//////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv_main[]) { int ret = -1; @@ -120,7 +113,7 @@ int main(int argc, char *argv_main[]) { wasm_func_t *read_fn = wasm_func_new(store, read_ft, read_cb); wasm_functype_delete(read_ft); - wasm_functype_t *key_ft = wasm_functype_new_1_0(wasm_valtype_new_i32()); + wasm_functype_t *key_ft = wasm_functype_new_0_1(wasm_valtype_new_i32()); wasm_func_t *key_fn = wasm_func_new(store, key_ft, key_cb); wasm_functype_delete(key_ft); @@ -135,48 +128,65 @@ int main(int argc, char *argv_main[]) { wasm_extern_t *externs[] = {wasm_func_as_extern(emit_fn), wasm_func_as_extern(read_fn), wasm_func_as_extern(key_fn), wasm_func_as_extern(load_fn), wasm_func_as_extern(call_fn)}; wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); - wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL); + wasm_trap_t *trap = NULL; + wasm_instance_t *instance = wasm_instance_new(store, module, &imports, &trap); if (!instance) { - printf("> Error instantiating module!\n"); + printf("error instantiating core module\n"); + if (trap) { + print_trap(trap); + wasm_trap_delete(trap); + } return -1; } wasm_extern_vec_t exports; wasm_instance_exports(instance, &exports); if (exports.size == 0) { - printf("> Error accessing exports!\n"); + printf("error accessing export\n"); return -1; } memory = wasm_extern_as_memory(exports.data[CORE_MEMORY_EXPORT_INDEX]); if (memory == NULL) { - printf("> Error accessing export!\n"); + printf("error accessing `memory` export\n"); return -1; } table = wasm_extern_as_table(exports.data[CORE_TABLE_EXPORT_INDEX]); if (table == NULL) { - printf("> Error accessing export!\n"); + printf("error accessing `table` export\n"); return -1; } const wasm_func_t *interpret_fn = wasm_extern_as_func(exports.data[CORE_INTERPRET_EXPORT_INDEX]); if (interpret_fn == NULL) { - printf("> Error accessing export!\n"); + printf("error accessing `interpret` export\n"); return -1; } - wasm_val_vec_t args = WASM_EMPTY_VEC; - wasm_val_vec_t results = WASM_EMPTY_VEC; - wasm_trap_t *trap = wasm_func_call(interpret_fn, &args, &results); - if (trap) { - printf("> Error calling function!\n"); - print_trap(trap); - return -1; + printf("WAForth\n"); + wasm_val_t as[1] = {WASM_I32_VAL(0)}; + wasm_val_vec_t args = WASM_ARRAY_VEC(as); + wasm_val_t vs[] = {WASM_INIT_VAL}; + wasm_val_vec_t results_vec = WASM_ARRAY_VEC(vs); + while (true) { + trap = wasm_func_call(interpret_fn, &args, &results_vec); + if (trap == NULL) { + // No trap means the input buffer was no longer filled when asked. + // This means the program should exit. + break; + } + wasm_name_t message; + wasm_trap_message(trap, &message); + // `unreachable` is called when we want to reset the call stack, and start the interpreter + // loop again (i.e. when QUIT is called) + if (strstr(message.data, "wasm `unreachable` instruction executed") == NULL) { + printf("error: %s\n", message.data); + } + wasm_name_delete(&message); + wasm_trap_delete(trap); } - printf("Instantiated\n"); - wasm_extern_vec_delete(&exports); wasm_instance_delete(instance); wasm_func_delete(call_fn); @@ -187,6 +197,5 @@ int main(int argc, char *argv_main[]) { wasm_module_delete(module); wasm_store_delete(store); wasm_engine_delete(engine); - printf("Done\n"); return ret; }