struct wasm_tabletype_inner_t {
wasm_valtype_t *element;
wasm_limits_t limits;
+
+ i32 static_arr;
};
struct wasm_memorytype_inner_t {
};
struct wasm_func_inner_t {
- wasm_instance_t *instance;
- i32 func_idx;
+ bool env_present;
+ void *env;
+ void (*func_ptr)();
+ void (*finalizer)(void *);
- wasm_functype_t *type;
+ const wasm_functype_t *type;
};
struct wasm_global_inner_t {
- wasm_instance_t *instance;
int register_index;
+ ovm_state_t *state;
+ ovm_engine_t *engine;
+
+ wasm_val_t initial_value;
- wasm_globaltype_t *type;
+ const wasm_globaltype_t *type;
};
struct wasm_table_inner_t {
- wasm_tabletype_t *type;
+ ovm_program_t *program;
+ ovm_engine_t *engine;
+
+ i32 static_arr;
+
+ const wasm_tabletype_t *type;
};
struct wasm_memory_inner_t {
- wasm_memorytype_t *type;
+ ovm_engine_t* engine;
+
+ const wasm_memorytype_t *type;
};
struct wasm_extern_t {
- wasm_externtype_t *type;
+ const wasm_externtype_t *type;
union {
struct wasm_func_inner_t func;
struct wasm_global_inner_t global;
struct wasm_memory_t { wasm_extern_t inner; };
struct wasm_instance_t {
- wasm_module_t *module;
+ const wasm_module_t *module;
+ wasm_store_t *store;
+
+ bh_arr(wasm_func_t *) funcs;
+ bh_arr(wasm_memory_t *) memories;
+ bh_arr(wasm_table_t *) tables;
+ bh_arr(wasm_global_t *) globals;
+
+ wasm_extern_vec_t exports;
+
ovm_state_t *state;
};
}
ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program, i32 func_idx, i32 param_count, ovm_value_t *params) {
- bh_arr_insert_end(state->numbered_values, 1);
- state->value_number_offset += 1;
+ ovm_func_t func = program->funcs[func_idx];
- state->pc = 0x7fffffff;
- ovm__func_setup_stack_frame(engine, state, program, func_idx, 0);
+ switch (func.kind) {
+ case OVM_FUNC_INTERNAL: {
+ bh_arr_insert_end(state->numbered_values, 1);
+ state->value_number_offset += 1;
- fori (i, 0, param_count) {
- state->numbered_values[i + state->value_number_offset] = params[i];
- }
+ ovm__func_setup_stack_frame(engine, state, program, func_idx, 0);
+
+ fori (i, 0, param_count) {
+ state->numbered_values[i + state->value_number_offset] = params[i];
+ }
- assert(program->funcs[func_idx].kind == OVM_FUNC_INTERNAL);
- state->pc = program->funcs[func_idx].start_instr;
- ovm_run_code(engine, state, program);
+ state->pc = func.start_instr;
+ ovm_run_code(engine, state, program);
+
+ state->value_number_offset -= 1;
+ return bh_arr_pop(state->numbered_values);
+ }
- state->value_number_offset -= 1;
- return bh_arr_pop(state->numbered_values);
+ case OVM_FUNC_EXTERNAL: {
+ ovm_value_t result = {0};
+ ovm_external_func_t external_func = state->external_funcs[func.external_func_idx];
+ external_func.native_func(external_func.userdata, state->params, &result);
+
+ bh_arr_set_length(state->params, 0);
+ return result;
+ }
+
+ default: return (ovm_value_t) {};
+ }
}
static inline double __ovm_abs(double f) {
}
wasm_externtype_t* wasm_extern_type(const wasm_extern_t* ext) {
- return ext->type;
+ return (wasm_externtype_t *) ext->type;
}
wasm_extern_t* wasm_func_as_extern(wasm_func_t* ext) { return (wasm_extern_t *) ext; }
+
+#include "onyx_wasm.h"
+#include "vm.h"
+
+wasm_func_t *wasm_func_new(wasm_store_t *store, const wasm_functype_t *type, wasm_func_callback_t callback) {
+ wasm_func_t *func = bh_alloc(store->engine->store->arena_allocator, sizeof(*func));
+ func->inner.type = wasm_functype_as_externtype_const(type);
+ func->inner.func.type = type;
+ func->inner.func.env_present = false;
+ func->inner.func.env = NULL;
+ func->inner.func.func_ptr = (void (*)()) callback;
+ func->inner.func.finalizer = NULL;
+
+ return func;
+}
+
+wasm_func_t *wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *type,
+ wasm_func_callback_with_env_t callback, void *env, void (*finalizer)(void *)) {
+
+ wasm_func_t *func = bh_alloc(store->engine->store->arena_allocator, sizeof(*func));
+ func->inner.type = wasm_functype_as_externtype_const(type);
+ func->inner.func.type = type;
+ func->inner.func.env_present = true;
+ func->inner.func.env = env;
+ func->inner.func.func_ptr = (void (*)()) callback;
+ func->inner.func.finalizer = finalizer;
+
+ return func;
+}
+
+wasm_functype_t *wasm_func_type(const wasm_func_t *func) {
+ return (wasm_functype_t *) func->inner.func.type;
+}
+
+size_t wasm_func_param_arity(const wasm_func_t *func) {
+ // Wow this is gross...
+ return func->inner.func.type->type.func.params.size;
+}
+
+size_t wasm_func_result_arity(const wasm_func_t *func) {
+ // Wow this is gross...
+ return func->inner.func.type->type.func.results.size;
+}
+
+wasm_trap_t *wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *args, wasm_val_vec_t *results) {
+ if (func->inner.func.env_present) {
+ wasm_func_callback_with_env_t cb = (wasm_func_callback_with_env_t) func->inner.func.func_ptr;
+ wasm_trap_t *trap = cb(func->inner.func.env, args, results);
+
+ if (func->inner.func.finalizer) {
+ func->inner.func.finalizer(func->inner.func.env);
+ }
+
+ return trap;
+
+ } else {
+ wasm_func_callback_t cb = (wasm_func_callback_t) func->inner.func.func_ptr;
+ wasm_trap_t *trap = cb(args, results);
+ return trap;
+ }
+}
+
+#include "onyx_wasm.h"
+#include "vm.h"
+
+wasm_global_t *wasm_global_new(wasm_store_t *store, const wasm_globaltype_t *type, const wasm_val_t *initial) {
+ wasm_global_t *global = bh_alloc(store->engine->store->arena_allocator, sizeof(*global));
+ global->inner.type = wasm_globaltype_as_externtype_const(type);
+ global->inner.global.register_index = -1;
+ global->inner.global.engine = NULL;
+
+ if (initial) {
+ global->inner.global.initial_value = *initial;
+ }
+
+ return global;
+}
+
+wasm_globaltype_t *wasm_global_type(const wasm_global_t *global) {
+ return (wasm_globaltype_t *) global->inner.global.type;
+}
+
+void wasm_global_get(const wasm_global_t *global, wasm_val_t *value) {
+ assert(("unimplemented", 0));
+}
+
+void wasm_global_set(wasm_global_t *global, const wasm_val_t *value) {
+ assert(("unimplemented", 0));
+}
+
+
+
+#include "onyx_wasm.h"
+#include "vm.h"
+#include <alloca.h>
+
+typedef struct wasm_ovm_binding wasm_ovm_binding;
+struct wasm_ovm_binding {
+ int func_idx;
+ ovm_engine_t *engine;
+ ovm_state_t *state;
+ ovm_program_t *program;
+};
+
+static wasm_trap_t *wasm_to_ovm_func_call_binding(void *vbinding, const wasm_val_vec_t *args, wasm_val_vec_t *res) {
+ wasm_ovm_binding *binding = (wasm_ovm_binding *) vbinding;
+
+ ovm_value_t *vals = alloca(sizeof(*vals) * args->size);
+ fori (i, 0, (int) args->size) {
+ switch (args->data[i].kind) {
+ case WASM_I32:
+ vals[i].type = OVM_TYPE_I32;
+ vals[i].i32 = args->data[i].of.i32;
+ break;
+
+ case WASM_I64:
+ vals[i].type = OVM_TYPE_I64;
+ vals[i].i64 = args->data[i].of.i64;
+ break;
+
+ case WASM_F32:
+ vals[i].type = OVM_TYPE_F32;
+ vals[i].f32 = args->data[i].of.f32;
+ break;
+
+ case WASM_F64:
+ vals[i].type = OVM_TYPE_F64;
+ vals[i].f64 = args->data[i].of.f64;
+ break;
+
+ default: assert(("invalid wasm value type for conversion", 0));
+ }
+ }
+
+ ovm_value_t ovm_res = ovm_func_call(binding->engine, binding->state, binding->program, binding->func_idx, args->size, vals);
+ if (!res || res->size == 0) return NULL;
+
+ switch (ovm_res.type) {
+ case OVM_TYPE_I8:
+ res->data[0].kind = WASM_I32;
+ res->data[0].of.i32 = (i32) ovm_res.i8;
+ break;
+
+ case OVM_TYPE_I16:
+ res->data[0].kind = WASM_I32;
+ res->data[0].of.i32 = (i32) ovm_res.i16;
+ break;
+
+ case OVM_TYPE_I32:
+ res->data[0].kind = WASM_I32;
+ res->data[0].of.i32 = (i32) ovm_res.i32;
+ break;
+
+ case OVM_TYPE_I64:
+ res->data[0].kind = WASM_I64;
+ res->data[0].of.i64 = ovm_res.i64;
+ break;
+
+ case OVM_TYPE_F32:
+ res->data[0].kind = WASM_F32;
+ res->data[0].of.f32 = ovm_res.f32;
+ break;
+
+ case OVM_TYPE_F64:
+ res->data[0].kind = WASM_F64;
+ res->data[0].of.f64 = ovm_res.f64;
+ break;
+ }
+
+ return NULL;
+}
+
+static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t *imports) {
+ //
+ // Place imports in their corresponding "bucket"
+ fori (i, 0, (int) imports->size) {
+ switch (wasm_extern_kind(imports->data[i])) {
+ case WASM_EXTERN_FUNC:
+ bh_arr_push(instance->funcs, wasm_extern_as_func(imports->data[i]));
+ break;
+
+ case WASM_EXTERN_MEMORY:
+ bh_arr_push(instance->memories, wasm_extern_as_memory(imports->data[i]));
+ break;
+
+ case WASM_EXTERN_GLOBAL:
+ bh_arr_push(instance->globals, wasm_extern_as_global(imports->data[i]));
+ break;
+
+ case WASM_EXTERN_TABLE:
+ bh_arr_push(instance->tables, wasm_extern_as_table(imports->data[i]));
+ break;
+ }
+ }
+
+ //
+ // Create function objects
+ fori (i, 0, (int) instance->module->functypes.size) {
+ wasm_ovm_binding *binding = bh_alloc(instance->store->engine->store->arena_allocator, sizeof(*binding));
+ binding->engine = instance->store->engine->engine;
+ binding->func_idx = bh_arr_length(instance->funcs);
+ binding->program = instance->module->program;
+ binding->state = instance->state;
+
+ wasm_func_t *func = wasm_func_new_with_env(instance->store, instance->module->functypes.data[i],
+ wasm_to_ovm_func_call_binding, binding, NULL);
+
+ bh_arr_push(instance->funcs, func);
+ }
+
+ //
+ // Create memory objects
+ fori (i, 0, (int) instance->module->memorytypes.size) {
+ wasm_memory_t *memory = wasm_memory_new(instance->store, instance->module->memorytypes.data[i]);
+ memory->inner.memory.engine = instance->store->engine->engine;
+
+ bh_arr_push(instance->memories, memory);
+ }
+
+ //
+ // Create table objects
+ fori (i, 0, (int) instance->module->tabletypes.size) {
+ wasm_table_t *table = wasm_table_new(instance->store, instance->module->tabletypes.data[i], NULL);
+ table->inner.table.engine = instance->store->engine->engine;
+ table->inner.table.program = instance->module->program;
+ table->inner.table.static_arr = instance->module->tabletypes.data[i]->type.table.static_arr;
+
+ bh_arr_push(instance->tables, table);
+ }
+
+ //
+ // Create global objects
+ fori (i, 0, (int) instance->module->globaltypes.size) {
+ wasm_global_t *global = wasm_global_new(instance->store, instance->module->globaltypes.data[i],
+ &instance->module->globaltypes.data[i]->type.global.initial_value);
+ global->inner.global.engine = instance->store->engine->engine;
+ global->inner.global.state = instance->state;
+ global->inner.global.register_index = bh_arr_length(instance->globals);
+
+ bh_arr_push(instance->globals, global);
+ }
+
+
+ //
+ // Initialize all non-passive data segments
+ fori (i, 0, (int) instance->module->data_count) {
+ struct wasm_data_t *datum = &instance->module->data_entries[i];
+ if (datum->passive) continue;
+
+ ovm_engine_memory_copy(instance->store->engine->engine, datum->offset, datum->data, datum->length);
+ }
+}
+
+wasm_instance_t *wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
+ const wasm_extern_vec_t *imports, wasm_trap_t **trap) {
+
+ wasm_instance_t *instance = bh_alloc(store->engine->store->arena_allocator, sizeof(*instance));
+ instance->store = store;
+ instance->module = module;
+
+ instance->funcs = NULL;
+ instance->memories = NULL;
+ instance->tables = NULL;
+ instance->globals = NULL;
+ bh_arr_new(store->engine->store->heap_allocator, instance->funcs, module->functypes.size);
+ bh_arr_new(store->engine->store->heap_allocator, instance->memories, 1);
+ bh_arr_new(store->engine->store->heap_allocator, instance->tables, 1);
+ bh_arr_new(store->engine->store->heap_allocator, instance->globals, module->globaltypes.size);
+
+ instance->state = ovm_state_new(store->engine->engine, module->program);
+
+ // TODO
+ instance->exports.size = 0;
+ instance->exports.data = NULL;
+
+ prepare_instance(instance, imports);
+
+ if (trap) *trap = NULL;
+
+ return instance;
+}
+
+
+#include "onyx_wasm.h"
+#include "vm.h"
+
+wasm_memory_t *wasm_memory_new(wasm_store_t *store, const wasm_memorytype_t *type) {
+ wasm_memory_t *memory = bh_alloc(store->engine->store->arena_allocator, sizeof(*store));
+ memory->inner.type = wasm_memorytype_as_externtype_const(type);
+ memory->inner.memory.type = type;
+ memory->inner.memory.engine = NULL;
+
+ return memory;
+}
+
+wasm_memorytype_t *wasm_memory_type(const wasm_memory_t *memory) {
+ return (wasm_memorytype_t *) memory->inner.memory.type;
+}
+
+byte_t *wasm_memory_data(wasm_memory_t *memory) {
+ assert(memory && memory->inner.memory.engine);
+ return memory->inner.memory.engine->memory;
+}
+
+size_t wasm_memory_data_size(const wasm_memory_t *memory) {
+ assert(memory && memory->inner.memory.engine);
+ return memory->inner.memory.engine->memory_size;
+}
+
+wasm_memory_pages_t wasm_memory_size(const wasm_memory_t *memory) {
+ assert(memory && memory->inner.memory.engine);
+ return memory->inner.memory.engine->memory_size / MEMORY_PAGE_SIZE;
+}
+
+bool wasm_memory_grow(wasm_memory_t *memory, wasm_memory_pages_t pages) {
+ //
+ // This will always fail, as initially the VM is created with
+ // a 4GiB mmap, so growing it will not be an option. If that
+ // changes and a dynamically allocated solution is used, then
+ // this can change. I don't see that changing however, as I will
+ // never need to use this on 32-bit systems, and that would be the
+ // only case that I would not like to try to mmap 4 gigs.
+ return false;
+}
parse_section(&ctx);
}
+ // TODO: This is not correct when the module imports a global.
+ // But Onyx does not do this, so I don't care at the moment.
module->program->register_count = module->globaltypes.size;
return true;
wasm_module_t *wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) {
- wasm_module_t *module = malloc(sizeof(*module));
+ wasm_module_t *module = bh_alloc(store->engine->store->arena_allocator, sizeof(*module));
module->store = store;
bool success = module_build(module, binary);
}
ctx->func_table_arr_idx = ovm_program_register_static_ints(ctx->program, entry_count, ctx->module->elem_entries);
+
+ assert(ctx->module->tabletypes.size == 1);
+ ctx->module->tabletypes.data[0]->type.table.static_arr = ctx->func_table_arr_idx;
}
static void parse_data_section(build_context *ctx) {
unsigned int section_size = uleb128_to_uint(ctx->binary.data, &ctx->offset);
unsigned int code_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
assert(ctx->module->functypes.size == code_count);
-
+
fori (i, 0, (int) code_count) {
unsigned int code_size = uleb128_to_uint(ctx->binary.data, &ctx->offset);
unsigned int local_sections_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
#include "vm.h"
wasm_store_t *wasm_store_new(wasm_engine_t *engine) {
- wasm_store_t *store = malloc(sizeof(wasm_store_t));
+ wasm_store_t *store = bh_alloc(engine->store->arena_allocator, sizeof(wasm_store_t));
store->engine = engine;
return store;
}
-// TODO
+#include "onyx_wasm.h"
+#include "vm.h"
+
+wasm_table_t *wasm_table_new(wasm_store_t *store, const wasm_tabletype_t *type, wasm_ref_t *init) {
+ wasm_table_t *table = bh_alloc(store->engine->store->arena_allocator, sizeof(*table));
+ table->inner.type = wasm_tabletype_as_externtype_const(type);
+ table->inner.table.type = type;
+
+ return table;
+}
+
+wasm_tabletype_t *wasm_table_type(const wasm_table_t *table) {
+ return (wasm_tabletype_t *) table->inner.table.type;
+}
+