From: Brendan Hansen Date: Mon, 27 Jun 2022 03:38:26 +0000 (-0500) Subject: getting close to a full test X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=1959f9d3394366392f389bda64611732693c1129;p=onyx-embedder.git getting close to a full test --- diff --git a/include/onyx_wasm.h b/include/onyx_wasm.h index eae8c3d..d2e8bab 100644 --- a/include/onyx_wasm.h +++ b/include/onyx_wasm.h @@ -45,6 +45,8 @@ struct wasm_globaltype_inner_t { struct wasm_tabletype_inner_t { wasm_valtype_t *element; wasm_limits_t limits; + + i32 static_arr; }; struct wasm_memorytype_inner_t { @@ -126,29 +128,41 @@ struct wasm_module_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; @@ -163,7 +177,16 @@ struct wasm_table_t { wasm_extern_t inner; }; 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; }; diff --git a/src/vm/vm.c b/src/vm/vm.c index 7084ac3..5b058e9 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -495,22 +495,37 @@ static inline void ovm__func_setup_stack_frame(ovm_engine_t *engine, ovm_state_t } 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) { diff --git a/src/wasm/extern.c b/src/wasm/extern.c index 0a1b5d4..22bc6e9 100644 --- a/src/wasm/extern.c +++ b/src/wasm/extern.c @@ -10,7 +10,7 @@ wasm_externkind_t wasm_extern_kind(const wasm_extern_t* ext) { } 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; } diff --git a/src/wasm/func.c b/src/wasm/func.c index e69de29..bd5f6b1 100644 --- a/src/wasm/func.c +++ b/src/wasm/func.c @@ -0,0 +1,61 @@ + +#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; + } +} diff --git a/src/wasm/global.c b/src/wasm/global.c index e69de29..1dee022 100644 --- a/src/wasm/global.c +++ b/src/wasm/global.c @@ -0,0 +1,29 @@ + +#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)); +} + diff --git a/src/wasm/instance.c b/src/wasm/instance.c index e69de29..f9d249d 100644 --- a/src/wasm/instance.c +++ b/src/wasm/instance.c @@ -0,0 +1,192 @@ + + +#include "onyx_wasm.h" +#include "vm.h" +#include + +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; +} + diff --git a/src/wasm/memory.c b/src/wasm/memory.c index e69de29..04722e6 100644 --- a/src/wasm/memory.c +++ b/src/wasm/memory.c @@ -0,0 +1,42 @@ + +#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; +} diff --git a/src/wasm/module.c b/src/wasm/module.c index e62bd32..c430570 100644 --- a/src/wasm/module.c +++ b/src/wasm/module.c @@ -20,6 +20,8 @@ static bool module_build(wasm_module_t *module, const wasm_byte_vec_t *binary) { 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; @@ -58,7 +60,7 @@ WASM_MODULE_INDEX(global, WASM_EXTERN_GLOBAL) 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); diff --git a/src/wasm/module_parsing.c.incl b/src/wasm/module_parsing.c.incl index 1b4e7dd..d37d6e2 100644 --- a/src/wasm/module_parsing.c.incl +++ b/src/wasm/module_parsing.c.incl @@ -305,6 +305,9 @@ static void parse_elem_section(build_context *ctx) { } 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) { @@ -905,7 +908,7 @@ static void parse_code_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); diff --git a/src/wasm/store.c b/src/wasm/store.c index 0f30cf6..07a3bc1 100644 --- a/src/wasm/store.c +++ b/src/wasm/store.c @@ -3,7 +3,7 @@ #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; } diff --git a/src/wasm/table.c b/src/wasm/table.c index 0ade447..6110df2 100644 --- a/src/wasm/table.c +++ b/src/wasm/table.c @@ -1,2 +1,16 @@ -// 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; +} +