`onyx run` supports multi threads
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 22 Nov 2021 15:51:12 +0000 (09:51 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 22 Nov 2021 15:51:12 +0000 (09:51 -0600)
14 files changed:
build.sh
core/io/file.onyx
core/runtime/build_opts.onyx
core/runtime/onyx_run.onyx [new file with mode: 0644]
core/runtime/wasi.onyx
core/std.onyx
core/wasi/clock.onyx
core/wasi/env.onyx
include/astnodes.h
include/small_windows.h
lib/linux_x86_64/include/wasm.h
src/onyx.c
src/wasm_emit.c
src/wasm_runtime.c

index 447e12914ec984a1eb30ab0f1e99d09882bd878e..90e7e8a0fb3218bfc1100368147b28b13742e574 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -43,12 +43,10 @@ else
     TARGET='./bin/onyx'
 fi
 
-if true; then
-    C_FILES="$C_FILES wasm_runtime"
-    FLAGS="$FLAGS -DENABLE_RUN_WITH_WASMER"
-    LIBS="-L$CORE_DIR/lib -lwasmer -Wl,-rpath=$CORE_DIR/lib"
-    INCLUDES="-I$WASMER_INCLUDE_DIR"
-fi
+C_FILES="$C_FILES wasm_runtime"
+FLAGS="$FLAGS -DENABLE_RUN_WITH_WASMER"
+LIBS="-L$CORE_DIR/lib -lwasmer -Wl,-rpath=$CORE_DIR/lib -lpthread"
+INCLUDES="-I$WASMER_INCLUDE_DIR"
 
 mkdir -p "$BUILD_DIR"
 
index 2606355a580d9f20f803ade8b7f4f12a028d8ce2..08b7f052d37eb00caf23db63d2ee3924975a650d 100644 (file)
@@ -1,7 +1,8 @@
 package core.io
 
 #local runtime :: package runtime
-#if runtime.Runtime != runtime.Runtime_Wasi {
+#if runtime.Runtime != runtime.Runtime_Wasi 
+    && runtime.Runtime != runtime.Runtime_Onyx {
     #error "The file system library is currently only available on the WASI runtime, and should only be included if that is the chosen runtime."
 }
 
index 5b60b137aea2a9b7dc506c59623f1165586febb7..483257a5931424242bd2eafaaec241f9a7e37dc5 100644 (file)
@@ -16,6 +16,7 @@ package runtime
 // such as enums. They can only really handle compile time number math and boolean
 // logic.                                               - brendanfh 2020/02/08
 
-Runtime_Wasi   :: 1
-Runtime_Js     :: 2
-Runtime_Custom :: 3
+Runtime_Onyx   :: 1
+Runtime_Wasi   :: 2
+Runtime_Js     :: 3
+Runtime_Custom :: 4
diff --git a/core/runtime/onyx_run.onyx b/core/runtime/onyx_run.onyx
new file mode 100644 (file)
index 0000000..723de5b
--- /dev/null
@@ -0,0 +1,32 @@
+package runtime
+
+#load "core/wasi/wasi"
+#load "core/runtime/common"
+
+use package core
+use package wasi
+
+// The "onyx_run" runtime extends the WASI runtime.
+#load "core/runtime/wasi"
+
+#if Multi_Threading_Enabled {
+    __spawn_thread :: (id: i32, func: (data: rawptr) -> void, data: rawptr) -> bool #foreign "env" "spawn_thread" ---
+    __kill_thread  :: (id: i32) -> i32 #foreign "env" "kill_thread" ---
+
+    #export "_thread_start" (id: i32, func: (data: rawptr) -> void, data: rawptr) {
+        __stack_top = raw_alloc(alloc.heap_allocator, 1 << 20);
+        __thread_initialize();
+
+        context.thread_id = id;
+
+        func(data);
+
+        __flush_stdio();
+    }
+    
+    #export "_thread_exit" (id: i32) {
+        raw_free(alloc.heap_allocator, __tls_base);
+
+        thread.__exited(id);
+    }
+}
index 9ad50535251d95e96698577726f16fc164d62f62..16deca74f00eb3a61e0b019afcfcb52cbfaf079f 100644 (file)
@@ -51,6 +51,3 @@ __exit :: (status: i32) do proc_exit(status);
     __flush_stdio();
 }
 
-
-__spawn_thread :: (t: i32, func: (data: rawptr) -> void, data: rawptr) -> bool ---
-__kill_thread :: (t: i32) -> i32 ---
index d1daefdf5477bead4834d3b70066f206bb3c120d..936bfca22615414894f7627734d43dcc6256cded 100644 (file)
@@ -37,21 +37,17 @@ package core
 #load "./type_info/helper"
 
 #local runtime :: package runtime
-#if runtime.Runtime == runtime.Runtime_Wasi {
-    #load "./runtime/wasi"
+#if runtime.Runtime == runtime.Runtime_Wasi || runtime.Runtime == runtime.Runtime_Onyx {
     #load "./wasi/wasi"
     #load "./wasi/env"
     #load "./wasi/clock"
     #load "./io/file"
 }
 
-#if runtime.Runtime == runtime.Runtime_Js {
-    #load "./runtime/js"
-}
-
-#if runtime.Runtime != runtime.Runtime_Custom {
-    #load "./stdio"
-}
+#if runtime.Runtime == runtime.Runtime_Onyx   { #load "./runtime/onyx_run" }
+#if runtime.Runtime == runtime.Runtime_Wasi   { #load "./runtime/wasi" }
+#if runtime.Runtime == runtime.Runtime_Js     { #load "./runtime/js" }
+#if runtime.Runtime != runtime.Runtime_Custom { #load "./stdio" }
 
 #if runtime.Multi_Threading_Enabled {
     #load "./intrinsics/atomics"
index 7f1e2b7b172a047adf27d0664ba5ad196bf2981f..e3dd70806a6c769e6800d3ec9403050a8285b076 100644 (file)
@@ -1,7 +1,9 @@
 package core.clock
 
-#if (package runtime).Runtime != (package runtime).Runtime_Wasi {
-    #error "'core.clock' is only available with the 'wasi' runtime.";
+#local runtime :: package runtime
+#if runtime.Runtime != runtime.Runtime_Wasi 
+    && runtime.Runtime != runtime.Runtime_Onyx {
+    #error "'core.clock' is only available with the 'wasi' or 'onyx' runtimes.";
 }
 
 use package wasi
index dfb408d4c5986d469ae6bd084dbce6e3b98453c7..09dfa057d850a83d24da15dec9ae17d438acfc0c 100644 (file)
@@ -1,7 +1,9 @@
 package core.env
 
-#if (package runtime).Runtime != (package runtime).Runtime_Wasi {
-    #error "'core.env' is only available with the 'wasi' runtime.";
+#local runtime :: package runtime
+#if runtime.Runtime != runtime.Runtime_Wasi 
+    && runtime.Runtime != runtime.Runtime_Onyx {
+    #error "'core.env' is only available with the 'wasi' and 'onyx' runtimes.";
 }
 
 
index d3bded15a99a77e974ad2f286aecabd73377baea..8cf6d8228fff9ed9a98e616849606f991d388e54 100644 (file)
@@ -1381,9 +1381,10 @@ enum CompileAction {
 typedef enum Runtime Runtime;
 enum Runtime {
     Runtime_Unknown = 0,
-    Runtime_Wasi    = 1,
-    Runtime_Js      = 2,
-    Runtime_Custom  = 3,
+    Runtime_Onyx    = 1,
+    Runtime_Wasi    = 2,
+    Runtime_Js      = 3,
+    Runtime_Custom  = 4,
 };
 
 
index 22d8f7a42998c93bbfc872a2cfeb15de7b4cde47..2836ad7a3a6c9bbaaeee9959216296cc8966300a 100644 (file)
@@ -274,6 +274,7 @@ GB_DLL_IMPORT HANDLE  WINAPI CreateThread       (SECURITY_ATTRIBUTES *semaphore_
                                                  DWORD creation_flags, DWORD *thread_id);
 GB_DLL_IMPORT DWORD   WINAPI GetThreadId        (HANDLE handle);
 GB_DLL_IMPORT void    WINAPI RaiseException     (DWORD, DWORD, DWORD, ULONG_PTR const *);
+GB_DLL_IMPORT BOOL    WINAPI TerminateThread    (HANDLE hThread, DWORD dwExitCode);
 
 
 GB_DLL_IMPORT BOOL      WINAPI GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buffer, DWORD *return_length);
index 25e0453a3abbc0142b557d8a71c4d5844e66bfeb..4a7e2c00d7a5e9469d043529b535a87179e3de3b 100644 (file)
@@ -704,12 +704,12 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) {
 #endif
 }
 
-#define WASM_I32_VAL(i) {.kind = WASM_I32, .of = {.i32 = i}}
-#define WASM_I64_VAL(i) {.kind = WASM_I64, .of = {.i64 = i}}
-#define WASM_F32_VAL(z) {.kind = WASM_F32, .of = {.f32 = z}}
-#define WASM_F64_VAL(z) {.kind = WASM_F64, .of = {.f64 = z}}
-#define WASM_REF_VAL(r) {.kind = WASM_ANYREF, .of = {.ref = r}}
-#define WASM_INIT_VAL {.kind = WASM_ANYREF, .of = {.ref = NULL}}
+#define WASM_I32_VAL(i) (wasm_val_t) {.kind = WASM_I32, .of = {.i32 = i}}
+#define WASM_I64_VAL(i) (wasm_val_t) {.kind = WASM_I64, .of = {.i64 = i}}
+#define WASM_F32_VAL(z) (wasm_val_t) {.kind = WASM_F32, .of = {.f32 = z}}
+#define WASM_F64_VAL(z) (wasm_val_t) {.kind = WASM_F64, .of = {.f64 = z}}
+#define WASM_REF_VAL(r) (wasm_val_t) {.kind = WASM_ANYREF, .of = {.ref = r}}
+#define WASM_INIT_VAL (wasm_val_t) {.kind = WASM_ANYREF, .of = {.ref = NULL}}
 
 
 ///////////////////////////////////////////////////////////////////////////////
index 5af0542b3d85ef995e9a9f483f038af04b0283fe..2ded60d7737e4abd46c8fac44abfd0d7655273c4 100644 (file)
@@ -71,7 +71,7 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg
         .use_post_mvp_features   = 1,
         .use_multi_threading     = 0,
 
-        .runtime = Runtime_Wasi,
+        .runtime = Runtime_Onyx,
 
         .files = NULL,
         .target_file = "out.wasm",
@@ -145,11 +145,12 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg
             }
             else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--runtime")) {
                 i += 1;
-                if      (!strcmp(argv[i], "wasi"))   options.runtime = Runtime_Wasi;
+                if      (!strcmp(argv[i], "onyx"))   options.runtime = Runtime_Onyx;
+                else if (!strcmp(argv[i], "wasi"))   options.runtime = Runtime_Wasi;
                 else if (!strcmp(argv[i], "js"))     options.runtime = Runtime_Js;
                 else if (!strcmp(argv[i], "custom")) options.runtime = Runtime_Custom;
                 else {
-                    bh_printf("WARNING: '%s' is not a valid runtime. Defaulting to 'wasi'.\n", argv[i]);
+                    bh_printf("WARNING: '%s' is not a valid runtime. Defaulting to 'onyx'.\n", argv[i]);
                     options.runtime = Runtime_Wasi;
                 }
             }
index eec3e85487d87e741006be716c64543156aa9d31..6a133ba289472ca66053c90270d0f26b6ef4682f 100644 (file)
@@ -3712,23 +3712,22 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
             .kind   = WASM_FOREIGN_MEMORY,
             .min    = 1024,
             .max    = 65536, // NOTE: Why not use all 4 Gigs of memory?
-            .shared = 1,
+            .shared = context.options->runtime != Runtime_Onyx,
 
             .mod    = "onyx",
             .name   = "memory",
         };
 
         bh_arr_push(module.imports, mem_import);
+    }
 
-    } else {
-        WasmExport mem_export = {
-            .kind = WASM_FOREIGN_MEMORY,
-            .idx = 0,
-        };
+    WasmExport mem_export = {
+        .kind = WASM_FOREIGN_MEMORY,
+        .idx = 0,
+    };
 
-        bh_table_put(WasmExport, module.exports, "memory", mem_export);
-        module.export_count++;
-    }
+    bh_table_put(WasmExport, module.exports, "memory", mem_export);
+    module.export_count++;
 
     WasmExport func_table_export = {
         .kind = WASM_FOREIGN_TABLE,
index 03bbca289e6ae29fec8a050513136580f20564e7..35b9683d51f34b7b16f69a82fdceaa2edb982e07 100644 (file)
 #include "wasm.h"
 #include "wasmer.h"
 
+#ifdef _BH_LINUX
+    #include <pthread.h>
+    #include <signal.h>
+#endif
+
 #ifndef WASMER_VERSION
     #error "Currently, building the Onyx compiler with built-in execution support requires the Wasmer library to be compiled and linked."
 #endif
 
+static wasm_config_t*    wasm_config;
+static wasi_config_t*    wasi_config;
+static wasi_env_t*       wasi_env;
+static wasm_engine_t*    wasm_engine;
+static wasm_store_t*     wasm_store;
+static wasm_extern_vec_t wasm_imports;
+static wasm_module_t*    wasm_module;
+static wasm_memory_t*    wasm_memory;
+
+b32 wasm_name_equals(const wasm_name_t* name1, const wasm_name_t* name2) {
+    if (name1->size != name2->size) return 0;
+    return !strncmp(name1->data, name2->data, name1->size);
+}
+
+b32 wasm_name_equals_string(const wasm_name_t* name1, const char* name2) {
+    u32 name2_size = strlen(name2);
+    if (name1->size != name2_size) return 0;
+    return !strncmp(name1->data, name2, name1->size);
+}
+
+wasm_extern_t* wasm_extern_lookup_by_name(wasm_module_t* module, wasm_instance_t* instance, const char* name) {
+    i32 name_len = strlen(name);
+
+    i32 idx = -1;
+    wasm_exporttype_vec_t export_types;
+    wasm_module_exports(module, &export_types);
+    fori (i, 0, (i64) export_types.size) {
+        wasm_exporttype_t* export_type = export_types.data[i];
+        const wasm_name_t* export_name = wasm_exporttype_name(export_type);
+
+        if (!strncmp(export_name->data, name, name_len)) {
+            idx = i;
+            break;
+        }
+    }
+
+    if (idx == -1) return NULL;
+
+    wasm_extern_vec_t exports;
+    wasm_instance_exports(instance, &exports);
+
+    return exports.data[idx];
+}
+
+
+typedef struct OnyxThread {
+    i32 id;
+    i32 funcidx;
+    i32 dataptr;
+    wasm_instance_t* instance;
+
+    #ifdef _BH_LINUX
+        pthread_t thread;
+    #endif
+} OnyxThread;
+
+static bh_arr(OnyxThread) threads = NULL;
+
+static void *onyx_run_thread(void *data) {
+    OnyxThread *thread = (OnyxThread *) data;
+
+    wasm_trap_t* traps = NULL;
+    thread->instance = wasm_instance_new(wasm_store, wasm_module, &wasm_imports, &traps);
+
+    wasm_extern_t* start_extern = wasm_extern_lookup_by_name(wasm_module, thread->instance, "_thread_start");
+    wasm_func_t*   start_func   = wasm_extern_as_func(start_extern);
+
+    wasm_extern_t* exit_extern = wasm_extern_lookup_by_name(wasm_module, thread->instance, "_thread_exit");
+    wasm_func_t*   exit_func   = wasm_extern_as_func(exit_extern);
+
+    { // Call the _thread_start procedure
+        wasm_val_t args[]    = { WASM_I32_VAL(thread->id), WASM_I32_VAL(thread->funcidx), WASM_I32_VAL(thread->dataptr) };
+        wasm_val_vec_t results;
+        wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
+
+        wasm_func_call(start_func, &args_array, &results);
+    }
+
+    { // Cal lthe _thread_exit procedure
+        wasm_val_t args[]    = { WASM_I32_VAL(thread->id) };
+        wasm_val_vec_t results;
+        wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
+
+        wasm_func_call(exit_func, &args_array, &results);
+    }
+
+    return NULL;
+}
+
+static wasm_trap_t* onyx_spawn_thread_impl(const wasm_val_vec_t* params, wasm_val_vec_t* results) {
+    bh_arr_insert_end(threads, 1);
+    OnyxThread *thread = &bh_arr_last(threads);
+
+    thread->id      = params->data[0].of.i32;
+    thread->funcidx = params->data[1].of.i32;
+    thread->dataptr = params->data[2].of.i32;
+
+    #ifdef _BH_LINUX
+        pthread_create(&thread->thread, NULL, onyx_run_thread, thread);
+    #endif
+
+    #ifdef _BH_WINDOWS
+        #error "unimplemented"
+    #endif
+
+    results->data[0] = WASM_I32_VAL(1);
+    return NULL;
+}
+
+static wasm_trap_t* onyx_kill_thread_impl(const wasm_val_vec_t* params, wasm_val_vec_t* results) {
+    i32 thread_id = params->data[0].of.i32;
+
+    bh_arr_each(OnyxThread, thread, threads) {
+        if (thread->id == thread_id) {
+            #ifdef _BH_LINUX
+            pthread_kill(thread->thread, SIGKILL);
+            #endif
+
+            results->data[0] = WASM_I32_VAL(1);
+            return NULL;
+        }
+    }
+
+    results->data[0] = WASM_I32_VAL(0);
+    return NULL;
+}
+
+
 void onyx_run_wasm(bh_buffer wasm_bytes) {
-    wasm_config_t*   config = NULL;
-    wasi_config_t*   wasi_config = NULL;
-    wasi_env_t*      wasi_env = NULL;
-    wasm_engine_t*   engine = NULL;
-    wasm_store_t*    store = NULL;
-    wasm_module_t*   module = NULL;
     wasm_instance_t* instance = NULL;
+    wasmer_features_t* features = NULL;
 
-    config = wasm_config_new();
-    if (!config) goto error_handling;
+    wasm_config = wasm_config_new();
+    if (!wasm_config) goto error_handling;
 
     // Prefer the LLVM compile because it is faster. This should be configurable from the command line and/or a top-level directive.
     if (wasmer_is_compiler_available(LLVM)) {
-        wasm_config_set_compiler(config, LLVM);
+        wasm_config_set_compiler(wasm_config, LLVM);
     }
 
+    features = wasmer_features_new();
+    wasmer_features_simd(features, 1);
+    wasmer_features_threads(features, 1);
+    wasmer_features_bulk_memory(features, 1);
+    wasm_config_set_features(wasm_config, features);
+
     wasi_config = wasi_config_new("onyx");
     if (context.options->passthrough_argument_count > 0) {
         fori (i, 0, context.options->passthrough_argument_count) {
@@ -36,45 +170,95 @@ void onyx_run_wasm(bh_buffer wasm_bytes) {
     wasi_env  = wasi_env_new(wasi_config);
     if (!wasi_env) goto error_handling;
 
-    engine = wasm_engine_new_with_config(config);
-    if (!engine) goto error_handling;
+    wasm_engine = wasm_engine_new_with_config(wasm_config);
+    if (!wasm_engine) goto error_handling;
 
-    store  = wasm_store_new(engine);
-    if (!store) goto error_handling;
+    wasm_store  = wasm_store_new(wasm_engine);
+    if (!wasm_store) goto error_handling;
 
     wasm_byte_vec_t wasm_data;
     wasm_data.size = wasm_bytes.length;
     wasm_data.data = wasm_bytes.data;
 
-    module = wasm_module_new(store, &wasm_data);
-    if (!module) goto error_handling;
+    wasm_module = wasm_module_new(wasm_store, &wasm_data);
+    if (!wasm_module) goto error_handling;
 
-    wasm_extern_vec_t imports = WASM_EMPTY_VEC;
-    wasi_get_imports(store, module, wasi_env, &imports);
+    wasmer_named_extern_vec_t wasi_imports;
+    wasi_get_unordered_imports(wasm_store, wasm_module, wasi_env, &wasi_imports);
 
-    wasm_trap_t* traps = NULL;
+    wasm_importtype_vec_t module_imports;    // @Free
+    wasm_module_imports(wasm_module, &module_imports);
 
-    instance = wasm_instance_new(store, module, &imports, &traps);
-    if (!instance) goto error_handling;
+    wasm_imports = (wasm_extern_vec_t) WASM_EMPTY_VEC;
+    wasm_extern_vec_new_uninitialized(&wasm_imports, module_imports.size); // @Free
 
-    // Find the start function
-    i32 start_function_idx = -1;
-    wasm_exporttype_vec_t export_types;
-    wasm_module_exports(module, &export_types);
-    fori (i, 0, (i64) export_types.size) {
-        wasm_exporttype_t* export_type = export_types.data[i];
-        const wasm_name_t* export_name = wasm_exporttype_name(export_type);
-        
-        if (!strncmp(export_name->data, "_start", 6)) {
-            start_function_idx = i;
-            break;
+    fori (i, 0, (i32) module_imports.size) {
+        const wasm_name_t* module_name = wasm_importtype_module(module_imports.data[i]);
+        const wasm_name_t* import_name = wasm_importtype_name(module_imports.data[i]);
+
+        wasm_extern_t* import = NULL;
+
+        // First try WASI
+        fori (j, 0, (i32) wasi_imports.size) {
+            const wasm_name_t* wasi_module_name = wasmer_named_extern_module(wasi_imports.data[j]);
+            const wasm_name_t* wasi_import_name = wasmer_named_extern_name(wasi_imports.data[j]);
+            if (wasm_name_equals(module_name, wasi_module_name) && wasm_name_equals(import_name, wasi_import_name)) {
+                import = (wasm_extern_t *) wasmer_named_extern_unwrap(wasi_imports.data[j]);
+                goto import_found;
+            }
+        }
+
+        if (wasm_name_equals_string(module_name, "onyx")) {
+            if (wasm_name_equals_string(import_name, "memory")) {
+                if (wasm_memory == NULL) {
+                    wasm_limits_t limits = { 1024, 65536 };
+                    wasm_memorytype_t* memory_type = wasm_memorytype_new(&limits);
+                    wasm_memory = wasm_memory_new(wasm_store, memory_type);
+                }
+
+                import = wasm_memory_as_extern(wasm_memory);
+                goto import_found;
+            }
+        }
+
+        if (wasm_name_equals_string(module_name, "env")) {
+            if (wasm_name_equals_string(import_name, "spawn_thread")) {
+                wasm_functype_t* func_type = wasm_functype_new_3_1(
+                    wasm_valtype_new_i32(), wasm_valtype_new_i32(), wasm_valtype_new_i32(),
+                    wasm_valtype_new_i32());
+
+                wasm_func_t* wasm_func = wasm_func_new(wasm_store, func_type, onyx_spawn_thread_impl);
+                import = wasm_func_as_extern(wasm_func);
+                goto import_found;
+            }
+
+            if (wasm_name_equals_string(import_name, "kill_thread")) {
+                wasm_functype_t* func_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32());
+
+                wasm_func_t* wasm_func = wasm_func_new(wasm_store, func_type, onyx_kill_thread_impl);
+                import = wasm_func_as_extern(wasm_func);
+                goto import_found;
+            }
         }
+
+        goto bad_import;
+
+    import_found:
+        wasm_imports.data[i] = import;
+        continue;
+
+
+    bad_import:
+        bh_printf("Couldn't find import %b.%b.\n", module_name->data, module_name->size, import_name->data, import_name->size);
+        return;
     }
 
-    wasm_extern_vec_t exports;
-    wasm_instance_exports(instance, &exports);
+    wasm_trap_t* traps = NULL;
+
+    instance = wasm_instance_new(wasm_store, wasm_module, &wasm_imports, &traps);
+    if (!instance) goto error_handling;
 
-    wasm_extern_t* start_extern = exports.data[start_function_idx];
+    wasm_extern_t* start_extern = wasm_extern_lookup_by_name(wasm_module, instance, "_start");
     wasm_func_t*   start_func   = wasm_extern_as_func(start_extern);
 
     wasm_val_vec_t args;
@@ -87,11 +271,15 @@ void onyx_run_wasm(bh_buffer wasm_bytes) {
 
 error_handling:
     bh_printf("An error occured trying to run the WASM module...\n");
+    i32 len = wasmer_last_error_length();
+    char *buf = alloca(len + 1);
+    wasmer_last_error_message(buf, len);
+    bh_printf("%b\n", buf, len);
 
 cleanup:
     if (instance)    wasm_instance_delete(instance);
-    if (module)      wasm_module_delete(module);
-    if (store)       wasm_store_delete(store);
-    if (engine)      wasm_engine_delete(engine);
+    if (wasm_module) wasm_module_delete(wasm_module);
+    if (wasm_store)  wasm_store_delete(wasm_store);
+    if (wasm_engine) wasm_engine_delete(wasm_engine);
     return;
-}
\ No newline at end of file
+}