FLAGS="$FLAGS -DENABLE_RUN_WITH_WASMER"
-if [ "$USE_DYNCALL" = "1" ]; then
+if [ "$USE_DYNCALL" = "1" ] && [ "$RUNTIME_LIBRARY" = "ovmwasm" ]; then
LIBS="$LIBS ../shared/lib/linux_$ARCH/lib/libdyncall_s.a ../shared/lib/linux_$ARCH/lib/libdyncallback_s.a"
FLAGS="$FLAGS -DUSE_DYNCALL"
fi
#ifdef USE_DYNCALL
+//
+// This code implements the ability to use `dyncall:some_library.so` as the
+// module import name to dynamically load a shared library at runtime.
+//
+
typedef struct DynCallContext {
void (*func)();
char types[64];
return wasm_func;
}
+
+//
+// This code implements the ability to wrap a wasm function in a callback
+// that can be handed to a library that expects a C function.
+//
+
+typedef struct DynCallbackContext {
+ wasm_func_t *wasm_func;
+ char *sig;
+} DynCallbackContext;
+
+static DCsigchar __wasm_dyncallback(DCCallback *cb, DCArgs *args, DCValue *result, void *userdata) {
+ DynCallbackContext *ctx = userdata;
+ int arg_count = bh_str_last_index_of(ctx->sig, ')');
+
+ wasm_val_vec_t wasm_args;
+ wasm_val_vec_new_uninitialized(&wasm_args, arg_count);
+
+ for (int i = 0; i < arg_count; i++) {
+ switch (ctx->sig[i]) {
+ case 'B': wasm_args.data[i] = WASM_I32_VAL(dcbArgBool(args)); break;
+ case 'c': wasm_args.data[i] = WASM_I32_VAL(dcbArgChar(args)); break;
+ case 'C': wasm_args.data[i] = WASM_I32_VAL(dcbArgUChar(args)); break;
+ case 's': wasm_args.data[i] = WASM_I32_VAL(dcbArgShort(args)); break;
+ case 'S': wasm_args.data[i] = WASM_I32_VAL(dcbArgUShort(args)); break;
+ case 'i': wasm_args.data[i] = WASM_I32_VAL(dcbArgInt(args)); break;
+ case 'I': wasm_args.data[i] = WASM_I32_VAL(dcbArgUInt(args)); break;
+ case 'j': wasm_args.data[i] = WASM_I64_VAL(dcbArgLong(args)); break;
+ case 'J': wasm_args.data[i] = WASM_I64_VAL(dcbArgULong(args)); break;
+ case 'l': wasm_args.data[i] = WASM_I64_VAL(dcbArgLongLong(args)); break;
+ case 'L': wasm_args.data[i] = WASM_I64_VAL(dcbArgULongLong(args)); break;
+ case 'f': wasm_args.data[i] = WASM_F32_VAL(dcbArgFloat(args)); break;
+ case 'd': wasm_args.data[i] = WASM_F64_VAL(dcbArgDouble(args)); break;
+ case 'p': wasm_args.data[i] = WASM_I64_VAL((uintptr_t) dcbArgPointer(args)); break;
+ }
+ }
+
+ wasm_val_vec_t wasm_results;
+ wasm_val_vec_new_uninitialized(&wasm_results, 1);
+
+ wasm_func_call(ctx->wasm_func, &wasm_args, &wasm_results);
+
+ switch (ctx->sig[arg_count + 1]) {
+ case 'B': result->B = wasm_results.data[0].of.i32; break;
+ case 'c': result->c = wasm_results.data[0].of.i32; break;
+ case 'C': result->C = wasm_results.data[0].of.i32; break;
+ case 's': result->s = wasm_results.data[0].of.i32; break;
+ case 'S': result->S = wasm_results.data[0].of.i32; break;
+ case 'i': result->i = wasm_results.data[0].of.i32; break;
+ case 'I': result->I = wasm_results.data[0].of.i32; break;
+ case 'j': result->j = wasm_results.data[0].of.i64; break;
+ case 'J': result->J = wasm_results.data[0].of.i64; break;
+ case 'l': result->l = wasm_results.data[0].of.i64; break;
+ case 'L': result->L = wasm_results.data[0].of.i64; break;
+ case 'f': result->f = wasm_results.data[0].of.f32; break;
+ case 'd': result->d = wasm_results.data[0].of.f64; break;
+ case 'p': result->p = (void *) wasm_results.data[0].of.i64; break;
+ }
+
+ wasm_val_vec_delete(&wasm_args);
+ wasm_val_vec_delete(&wasm_results);
+
+ return ctx->sig[arg_count + 1];
+}
+
+static void (* wasm_func_from_idx(wasm_table_t *func_table, unsigned int index, char *signature))(void) {
+ wasm_ref_t *func_ref = wasm_table_get(func_table, index);
+ assert(func_ref); // TODO: Switch to trap
+
+ wasm_func_t *func = wasm_ref_as_func(func_ref);
+
+ DynCallbackContext *dcc = bh_alloc_item(bh_heap_allocator(), DynCallbackContext);
+ dcc->wasm_func = func;
+ dcc->sig = signature;
+
+ return (void (*)()) dcbNewCallback(signature, &__wasm_dyncallback, dcc);
+}
+
#endif // USE_DYNCALL
static void onyx_print_trap(wasm_trap_t* trap) {
wasm_runtime.wasm_imports = wasm_imports;
wasm_runtime.wasm_memory = wasm_memory;
wasm_runtime.wasm_instance = wasm_instance;
+ wasm_runtime.wasm_func_table = wasm_extern_as_table(
+ wasm_extern_lookup_by_name(wasm_module, wasm_instance, "__indirect_function_table")
+ );
+
+#ifdef USE_DYNCALL
+ wasm_runtime.wasm_func_from_idx = wasm_func_from_idx;
+#endif
wasm_runtime.argc = argc;
wasm_runtime.argv = argv;
use runtime
+customize :: struct {
+ symbol_name: str;
+}
+
#if #defined (runtime.Generated_Foreign_Info) {
use core {package, *}
}
-customize :: struct {
- symbol_name: str;
-}
-
Cast_Mapping :: struct {
type: type_expr;
name: str;
param_num := 0;
for method_info.parameter_types {
- if get_type_info(it).kind == .Slice {
+ it_info := it->info();
+
+ if it_info.kind == .Slice {
io.write_format(&callw, "ONYX_PTR(P({}, i32)), P({}, i32)", param_num, param_num + 1);
param_num += 1;
} elseif is_pointer(it) {
io.write_format(&callw, "ONYX_PTR(P({}, i32))", param_num);
+
+ } elseif it_info.kind == .Function {
+ call_signature := make(dyn_str);
+ defer delete(&call_signature);
+
+ func_info := it_info->as_function();
+ for p: func_info.parameter_types {
+ map_to_dyncall(p, &call_signature);
+ }
+
+ string.append(&call_signature, ")");
+ map_to_dyncall(func_info.return_type, &call_signature);
+
+ io.write_format(&callw, "(void *) runtime->wasm_func_from_idx(runtime->wasm_func_table, P({}, i32), \"{}\")", param_num, cast(str) call_signature);
+
+ map_to_dyncall :: (t: type_expr, call_signature: &dyn_str) {
+ p := t;
+ switch i := t->info(); i.kind {
+ case .Distinct {
+ p = i->as_distinct().base_type;
+ }
+ }
+
+ switch p {
+ case void do string.append(call_signature, "v");
+ case bool do string.append(call_signature, "B");
+ case i8 do string.append(call_signature, "c");
+ case u8 do string.append(call_signature, "C");
+ case i16 do string.append(call_signature, "s");
+ case u16 do string.append(call_signature, "S");
+ case i32 do string.append(call_signature, "i");
+ case u32 do string.append(call_signature, "I");
+ case i64 do string.append(call_signature, "l");
+ case u64 do string.append(call_signature, "L");
+ case f32 do string.append(call_signature, "f");
+ case f64 do string.append(call_signature, "d");
+ case #default {
+ if is_pointer(p) {
+ string.append(call_signature, "p");
+ } else {
+ assert(false, tprintf("Unsupported type in function pointer: {}", p));
+ }
+ }
+ }
+ }
} else {
matched := false;
case .Multi_Pointer do return "ptr";
case .Array do return "ptr";
- case .Function do assert(false, "Passing functions between wasm and c is not yet supported.");
+ case .Function do return "i32"; // assert(false, "Passing functions between wasm and c is not yet supported.");
case .Slice do assert(false, "Passing a slice from c to wasm is not yet supported.");
case .Enum do return type_to_wasm_type((cast(&Type_Info_Enum) param_info).backing_type);
case .Distinct do return type_to_wasm_type((cast(&Type_Info_Distinct) param_info).base_type);
case .Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
case .Multi_Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
- case .Function do assert(false, "Passing functions between wasm and c is not yet supported.");
+ case .Function do return "WASM_I32, WASM_I32, WASM_I32"; // assert(false, "Passing functions between wasm and c is not yet supported.");
case .Array do return "WASM_I32";
case .Slice do return "WASM_I32,WASM_I32";
case .Enum do return type_encoding((cast(&Type_Info_Enum) param_info).backing_type);
// Runtime Objects
+enum wasm_ref_stored_obj_t {
+ wasm_ref_stored_obj_unknown,
+ wasm_ref_stored_obj_func,
+};
+
struct wasm_ref_t {
+ enum wasm_ref_stored_obj_t stored_obj;
+
+ union {
+ struct wasm_func_t *func;
+ };
};
struct wasm_frame_t {
struct wasm_table_inner_t {
ovm_program_t *program;
ovm_engine_t *engine;
+ struct wasm_instance_t *instance;
int static_arr;
wasm_extern_t* wasm_table_as_extern(wasm_table_t* ext) { return (wasm_extern_t *) ext; }
wasm_extern_t* wasm_memory_as_extern(wasm_memory_t* ext) { return (wasm_extern_t *) ext; }
-wasm_func_t* wasm_extern_as_func(wasm_extern_t* ext) { return ext->type->kind == WASM_EXTERN_FUNC ? (wasm_func_t *) ext : NULL; }
-wasm_global_t* wasm_extern_as_global(wasm_extern_t* ext) { return ext->type->kind == WASM_EXTERN_GLOBAL ? (wasm_global_t *) ext : NULL; }
-wasm_table_t* wasm_extern_as_table(wasm_extern_t* ext) { return ext->type->kind == WASM_EXTERN_TABLE ? (wasm_table_t *) ext : NULL; }
-wasm_memory_t* wasm_extern_as_memory(wasm_extern_t* ext) { return ext->type->kind == WASM_EXTERN_MEMORY ? (wasm_memory_t *) ext : NULL; }
+wasm_func_t* wasm_extern_as_func(wasm_extern_t* ext) { return (ext && ext->type->kind == WASM_EXTERN_FUNC) ? (wasm_func_t *) ext : NULL; }
+wasm_global_t* wasm_extern_as_global(wasm_extern_t* ext) { return (ext && ext->type->kind == WASM_EXTERN_GLOBAL) ? (wasm_global_t *) ext : NULL; }
+wasm_table_t* wasm_extern_as_table(wasm_extern_t* ext) { return (ext && ext->type->kind == WASM_EXTERN_TABLE) ? (wasm_table_t *) ext : NULL; }
+wasm_memory_t* wasm_extern_as_memory(wasm_extern_t* ext) { return (ext && ext->type->kind == WASM_EXTERN_MEMORY) ? (wasm_memory_t *) ext : NULL; }
const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t* ext) { return (const wasm_extern_t *) ext; }
const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t* ext) { return (const wasm_extern_t *) ext; }
wasm_table_t *table = wasm_table_new(instance->store, instance->module->tabletypes.data[i], NULL);
table->inner.table.engine = ovm_engine;
table->inner.table.program = ovm_program;
+ table->inner.table.instance = instance;
table->inner.table.static_arr = instance->module->tabletypes.data[i]->type.table.static_arr;
bh_arr_push(instance->tables, table);
-// TODO
+#include "ovm_wasm.h"
+#include "vm.h"
+
+wasm_func_t *wasm_ref_as_func(wasm_ref_t *ref) {
+ if (ref->stored_obj == wasm_ref_stored_obj_func) {
+ return ref->func;
+ }
+
+ return NULL;
+}
+
+const wasm_func_t *wasm_ref_as_func_const(const wasm_ref_t *ref) {
+ if (ref->stored_obj == wasm_ref_stored_obj_func) {
+ return (const wasm_func_t *) ref->func;
+ }
+
+ return NULL;
+}
+
return (wasm_tabletype_t *) table->inner.table.type;
}
+wasm_ref_t *wasm_table_get(const wasm_table_t *table, unsigned int index) {
+ const struct wasm_table_inner_t *tab = &table->inner.table;
+ ovm_program_t *program = tab->program;
+ ovm_engine_t *engine = tab->engine;
+
+ // TODO bounds checking
+ wasm_func_t *func = tab->instance->funcs[
+ program->static_integers[program->static_data[tab->static_arr].start_idx + index]
+ ];
+
+ wasm_ref_t *new_ref = bh_alloc(engine->store->arena_allocator, sizeof(*new_ref));
+ new_ref->stored_obj = wasm_ref_stored_obj_func;
+ new_ref->func = func;
+
+ return new_ref;
+}
\ No newline at end of file
wasm_memory_t* wasm_memory;
wasm_engine_t *wasm_engine;
wasm_extern_vec_t wasm_imports;
+ wasm_table_t *wasm_func_table;
int argc;
char **argv;
- // HACK HACK HACK
- // There should need to be this much stuff in here, but because Wasmer doesn't ship a "wasmerdll.lib"
+ // There shouldn't need to be this much stuff in here, but because Wasmer doesn't ship a "wasmerdll.lib"
// file for windows, it is impossible for it to link successfully against the function provided in onyx.exe.
// Therefore, we must serve as the linker and do this manually. Hopefully that library file will be
// shipped soon so this can go away...
void (*onyx_print_trap)(wasm_trap_t* trap);
wasm_store_t *(*wasm_store_new)(wasm_engine_t *engine);
void (*wasm_store_delete)(wasm_store_t *store);
+
+ // This is only set when using the OVMwasm runtime, as Wasmer's C-api does not allow
+ // for this function to exist, yet.
+ void (*(*wasm_func_from_idx)(wasm_table_t *table, unsigned int index, char *signature))(void);
} OnyxRuntime;
OnyxRuntime* runtime;