From: Brendan Hansen Date: Tue, 28 Jun 2022 03:39:53 +0000 (-0500) Subject: very very close to a full run of hello world X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=d005639aa919c2a8a7bace3fd857a40c55a78624;p=onyx-embedder.git very very close to a full run of hello world --- diff --git a/include/onyx_wasm.h b/include/onyx_wasm.h index d2e8bab..f5258b4 100644 --- a/include/onyx_wasm.h +++ b/include/onyx_wasm.h @@ -72,6 +72,13 @@ struct wasm_importtype_t { wasm_name_t module_name; wasm_name_t import_name; wasm_externtype_t *type; + + // + // This is only used by imported functions + // to specify which slot the function binding + // should be placed. When making a functype by + // hand, this proably will never be used. + int external_func_idx; }; struct wasm_exporttype_t { @@ -90,6 +97,7 @@ struct wasm_frame_t { }; struct wasm_trap_t { + wasm_message_t msg; }; struct wasm_foreign_t { @@ -125,6 +133,9 @@ struct wasm_module_t { ovm_program_t *program; bool valid; + + int memory_init_idx; + int memory_init_external_idx; }; struct wasm_func_inner_t { diff --git a/include/vm.h b/include/vm.h index 080ae04..7eef740 100644 --- a/include/vm.h +++ b/include/vm.h @@ -71,8 +71,8 @@ void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 void ovm_raw_print_instructions(i32 instr_count, ovm_instr_t *instrs); int ovm_program_register_static_ints(ovm_program_t *program, int len, int *data); -void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count); -void ovm_program_register_external_func(ovm_program_t *program, char *name, i32 param_count, i32 external_func_idx); +int ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count); +int ovm_program_register_external_func(ovm_program_t *program, char *name, i32 param_count, i32 external_func_idx); void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count); void ovm_program_modify_static_int(ovm_program_t *program, int arr, int idx, int new_value); @@ -124,6 +124,7 @@ ovm_state_t *ovm_state_new(ovm_engine_t *engine, ovm_program_t *program); void ovm_state_delete(ovm_state_t *state); void ovm_state_link_external_funcs(ovm_program_t *program, ovm_state_t *state, ovm_linkable_func_t *funcs); void ovm_state_register_external_func(ovm_state_t *state, i32 idx, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data); +void ovm_state_register_set(ovm_state_t *state, i32 idx, ovm_value_t val); // // diff --git a/include/vm_codebuilder.h b/include/vm_codebuilder.h index c3c2d7e..b8f9a0b 100644 --- a/include/vm_codebuilder.h +++ b/include/vm_codebuilder.h @@ -24,7 +24,6 @@ struct ovm_code_builder_t { i32 start_instr; i32 func_table_arr_idx; - i32 next_external_func_idx; i32 highest_value_number; }; diff --git a/src/vm/code_builder.c b/src/vm/code_builder.c index b6b1be7..955ef99 100644 --- a/src/vm/code_builder.c +++ b/src/vm/code_builder.c @@ -188,10 +188,16 @@ void ovm_code_builder_add_return(ovm_code_builder_t *builder) { } static void ovm_code_builder_add_params(ovm_code_builder_t *builder, i32 param_count) { + i32 *flipped_params = alloca(param_count * sizeof(i32)); + + fori (i, 0, param_count) { + flipped_params[i] = POP_VALUE(builder); + } + fori (i, 0, param_count) { ovm_instr_t param_instr = {0}; param_instr.full_instr = OVMI_PARAM; - param_instr.a = POP_VALUE(builder); + param_instr.a = flipped_params[param_count - 1 - i]; ovm_program_add_instructions(builder->program, 1, ¶m_instr); } @@ -316,8 +322,8 @@ void ovm_code_builder_add_load(ovm_code_builder_t *builder, u32 ovm_type, i32 of // add.i32 %n, %n, %i instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32); instrs[1].r = instrs[0].r; - instrs[1].a = instrs[0].r; - instrs[1].b = POP_VALUE(builder); + instrs[1].a = POP_VALUE(builder); + instrs[1].b = instrs[0].r; // load.x %m, %n instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_LOAD, ovm_type); @@ -341,18 +347,21 @@ void ovm_code_builder_add_store(ovm_code_builder_t *builder, u32 ovm_type, i32 o } ovm_instr_t instrs[3] = {0}; - instrs[2].b = POP_VALUE(builder); + + // TODO: explain the ordering here. // imm.i32 %n, offset instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32); instrs[0].i = offset; instrs[0].r = NEXT_VALUE(builder); + instrs[2].b = POP_VALUE(builder); + // add.i32 %n, %n, %i instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32); instrs[1].r = instrs[0].r; - instrs[1].a = instrs[0].r; - instrs[1].b = POP_VALUE(builder); + instrs[1].a = POP_VALUE(builder); + instrs[1].b = instrs[0].r; // store.x %m, %n instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_STORE, ovm_type); @@ -374,22 +383,24 @@ void ovm_code_builder_add_cmpxchg(ovm_code_builder_t *builder, u32 ovm_type, i32 PUSH_VALUE(builder, cmpxchg_instr.r); return; } + + // TODO: explain the ordering here. ovm_instr_t instrs[3] = {0}; - int value_reg = POP_VALUE(builder); - int expected_reg = POP_VALUE(builder); - int addr_reg = POP_VALUE(builder); - // imm.i32 %n, offset instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32); instrs[0].i = offset; instrs[0].r = NEXT_VALUE(builder); + int value_reg = POP_VALUE(builder); + int expected_reg = POP_VALUE(builder); + int addr_reg = POP_VALUE(builder); + // add.i32 %n, %n, %i instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32); instrs[1].r = instrs[0].r; - instrs[1].a = instrs[0].r; - instrs[1].b = addr_reg; + instrs[1].a = addr_reg; + instrs[1].b = instrs[0].r; // cmpxchg.x %m, %n instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, ovm_type); diff --git a/src/vm/vm.c b/src/vm/vm.c index 5b058e9..37f539b 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -31,8 +31,14 @@ ovm_program_t *ovm_program_new(ovm_store_t *store) { program->store = store; program->register_count = 0; + program->funcs = NULL; + program->code = NULL; + program->static_integers = NULL; + program->static_data = NULL; bh_arr_new(store->heap_allocator, program->funcs, 16); bh_arr_new(store->heap_allocator, program->code, 1024); + bh_arr_new(store->heap_allocator, program->static_integers, 128); + bh_arr_new(store->heap_allocator, program->static_data, 128); return program; } @@ -40,6 +46,8 @@ ovm_program_t *ovm_program_new(ovm_store_t *store) { void ovm_program_delete(ovm_program_t *program) { bh_arr_free(program->funcs); bh_arr_free(program->code); + bh_arr_free(program->static_integers); + bh_arr_free(program->static_data); bh_free(program->store->heap_allocator, program); } @@ -67,7 +75,7 @@ void ovm_program_modify_static_int(ovm_program_t *program, int arr, int idx, int program->static_integers[array.start_idx + idx] = new_value; } -void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count) { +int ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count) { ovm_func_t func; func.kind = OVM_FUNC_INTERNAL; func.id = bh_arr_length(program->funcs); @@ -77,9 +85,10 @@ void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i3 func.value_number_count = value_number_count; bh_arr_push(program->funcs, func); + return func.id; } -void ovm_program_register_external_func(ovm_program_t *program, char *name, i32 param_count, i32 external_func_idx) { +int ovm_program_register_external_func(ovm_program_t *program, char *name, i32 param_count, i32 external_func_idx) { ovm_func_t func; func.kind = OVM_FUNC_EXTERNAL; func.id = bh_arr_length(program->funcs); @@ -88,6 +97,7 @@ void ovm_program_register_external_func(ovm_program_t *program, char *name, i32 func.external_func_idx = external_func_idx; bh_arr_push(program->funcs, func); + return func.id; } void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count) { @@ -374,7 +384,7 @@ static char *ovm_instr_name(i32 full_instr) { } void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count) { - fori (i, start_instr, instr_count) { + fori (i, start_instr, start_instr + instr_count) { // // Horribly inefficient way of checking to see if this instruction // is the start of a function, but for now, it'll do. -brendanfh 06/13/2022 @@ -385,14 +395,14 @@ void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 } ovm_instr_t instr = program->code[i]; - printf("%50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); + printf("%6lx %50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", i, ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); } } void ovm_raw_print_instructions(i32 instr_count, ovm_instr_t *instrs) { fori (i, 0, instr_count) { ovm_instr_t instr = instrs[i]; - printf("%50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); + printf("%6lx %50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", i, ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d); } } @@ -403,7 +413,8 @@ ovm_engine_t *ovm_engine_new(ovm_store_t *store) { engine->store = store; engine->memory_size = 1ull << 32; - engine->memory = mmap(NULL, engine->memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + engine->memory = mmap(NULL, engine->memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + pthread_mutex_init(&engine->atomic_mutex, NULL); return engine; } @@ -438,12 +449,17 @@ ovm_state_t *ovm_state_new(ovm_engine_t *engine, ovm_program_t *program) { state->pc = 0; state->value_number_offset = 0; + state->numbered_values = NULL; + state->params = NULL; + state->stack_frames = NULL; + state->registers = NULL; bh_arr_new(store->heap_allocator, state->numbered_values, 64); bh_arr_new(store->heap_allocator, state->params, 16); bh_arr_new(store->heap_allocator, state->stack_frames, 32); bh_arr_new(store->heap_allocator, state->registers, program->register_count); bh_arr_insert_end(state->registers, program->register_count); + state->external_funcs = NULL; bh_arr_new(store->heap_allocator, state->external_funcs, 8); return state; @@ -468,6 +484,11 @@ void ovm_state_register_external_func(ovm_state_t *state, i32 idx, void (*func)( bh_arr_set_at(state->external_funcs, idx, external_func); } +void ovm_state_register_set(ovm_state_t *state, i32 idx, ovm_value_t val) { + if (idx >= bh_arr_length(state->registers)) return; + + state->registers[idx] = val; +} // // Function calling @@ -582,6 +603,8 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr bool release_mutex_at_end = false; while (state->pc < bh_arr_length(program->code)) { + ovm_program_print_instructions(program, state->pc, 1); + // // Incrementing the program counter here. // All instructions that compute something relative @@ -828,6 +851,7 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define OVM_LOAD(type_, stype) \ case OVM_TYPED_INSTR(OVMI_LOAD, type_): \ + assert(VAL(instr.a).type == OVM_TYPE_I32); \ VAL(instr.r).type = type_; \ VAL(instr.r).stype = * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32]; \ break; @@ -843,6 +867,7 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define OVM_STORE(type_, stype) \ case OVM_TYPED_INSTR(OVMI_STORE, type_): \ + assert(VAL(instr.a).type == OVM_TYPE_I32); \ * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32] = VAL(instr.b).stype; \ break; @@ -901,6 +926,12 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr ovm_value_t val = VAL(instr.a); bh_arr_fastdeleten(state->numbered_values, frame.value_number_count); + if (bh_arr_length(state->stack_frames) == 0) { + state->value_number_offset = 0; + VAL(frame.return_number_value) = val; + return; + } + state->value_number_offset = bh_arr_last(state->stack_frames).value_number_base; if (frame.return_number_value >= 0) { VAL(frame.return_number_value) = val; @@ -1020,11 +1051,15 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define CMPXCHG(otype, ctype) \ - case OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, otype): \ - if (VAL(instr.r).ctype == VAL(instr.a).ctype) { \ - VAL(instr.r).ctype = VAL(instr.b).ctype ; \ + case OVM_TYPED_INSTR(OVMI_CMPXCHG, otype): {\ + ctype *addr = (ctype *) &((u8 *) engine->memory)[VAL(instr.r).i32]; \ + if (*addr == VAL(instr.a).ctype) { \ + *addr = VAL(instr.b).ctype ; \ } \ - break; + VAL(instr.r).type = otype; \ + VAL(instr.r).ctype = *addr; \ + break; \ + } CMPXCHG(OVM_TYPE_I8, i8) CMPXCHG(OVM_TYPE_I16, i16) diff --git a/src/wasm/instance.c b/src/wasm/instance.c index f9d249d..4ab07c8 100644 --- a/src/wasm/instance.c +++ b/src/wasm/instance.c @@ -12,105 +12,195 @@ struct wasm_ovm_binding { ovm_program_t *program; }; +typedef struct ovm_wasm_binding ovm_wasm_binding; +struct ovm_wasm_binding { + int param_count; + int result_count; + wasm_func_t *func; +}; + +#define WASM_TO_OVM(w, o) \ + switch ((w).kind) { \ + case WASM_I32: \ + (o).type = OVM_TYPE_I32; \ + (o).i32 = (w).of.i32; \ + break; \ + \ + case WASM_I64: \ + (o).type = OVM_TYPE_I64; \ + (o).i64 = (w).of.i64; \ + break; \ + \ + case WASM_F32: \ + (o).type = OVM_TYPE_F32; \ + (o).f32 = (w).of.f32; \ + break; \ + \ + case WASM_F64: \ + (o).type = OVM_TYPE_F64; \ + (o).f64 = (w).of.f64; \ + break; \ + \ + default: assert(("invalid wasm value type for conversion", 0)); \ + } + +#define OVM_TO_WASM(o, w) \ + switch ((o).type) { \ + case OVM_TYPE_I8: \ + (w).kind = WASM_I32; \ + (w).of.i32 = (i32) (o).i8; \ + break; \ + \ + case OVM_TYPE_I16: \ + (w).kind = WASM_I32; \ + (w).of.i32 = (i32) (o).i16; \ + break; \ + \ + case OVM_TYPE_I32: \ + (w).kind = WASM_I32; \ + (w).of.i32 = (i32) (o).i32; \ + break; \ + \ + case OVM_TYPE_I64: \ + (w).kind = WASM_I64; \ + (w).of.i64 = (o).i64; \ + break; \ + \ + case OVM_TYPE_F32: \ + (w).kind = WASM_F32; \ + (w).of.f32 = (o).f32; \ + break; \ + \ + case OVM_TYPE_F64: \ + (w).kind = WASM_F64; \ + (w).of.f64 = (o).f64; \ + break; \ + } + 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; + WASM_TO_OVM(args->data[i], vals[i]); + } - case WASM_I64: - vals[i].type = OVM_TYPE_I64; - vals[i].i64 = args->data[i].of.i64; - break; + 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; - case WASM_F32: - vals[i].type = OVM_TYPE_F32; - vals[i].f32 = args->data[i].of.f32; - break; + OVM_TO_WASM(ovm_res, res->data[0]); - case WASM_F64: - vals[i].type = OVM_TYPE_F64; - vals[i].f64 = args->data[i].of.f64; - break; + return NULL; +} - default: assert(("invalid wasm value type for conversion", 0)); - } - } +static void ovm_to_wasm_func_call_binding(void *env, ovm_value_t* params, ovm_value_t *res) { + ovm_wasm_binding *binding = (ovm_wasm_binding *) env; - 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; + wasm_val_vec_t wasm_params; + wasm_params.data = alloca(sizeof(wasm_val_t) * binding->param_count); + wasm_params.size = binding->param_count; - 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; + fori (i, 0, binding->param_count) { + OVM_TO_WASM(params[i], wasm_params.data[i]); } - return NULL; + // asm("int $3"); + + wasm_val_vec_t wasm_results; + wasm_results.data = alloca(sizeof(wasm_val_t) * binding->result_count); + wasm_results.size = binding->result_count; + + wasm_trap_t *trap = wasm_func_call(binding->func, &wasm_params, &wasm_results); + assert(!trap); + + if (binding->result_count > 0) WASM_TO_OVM(wasm_results.data[0], *res); +} + +static void wasm_memory_init(void *env, ovm_value_t* params, ovm_value_t *res) { + wasm_instance_t *instr = (wasm_instance_t *) env; + + assert(params[0].type == OVM_TYPE_I32); + assert(params[1].type == OVM_TYPE_I32); + assert(params[2].type == OVM_TYPE_I32); + assert(params[3].type == OVM_TYPE_I32); + + // if (params[0].i32 == 63) asm("int $3"); + + printf("Initializing data from: %p\n", instr->module->data_entries[params[3].i32].data); + ovm_engine_memory_copy(instr->store->engine->engine, params[0].i32, instr->module->data_entries[params[3].i32].data, params[2].i32); } static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t *imports) { + ovm_store_t *ovm_store = instance->store->engine->store; + ovm_engine_t *ovm_engine = instance->store->engine->engine; + ovm_state_t *ovm_state = instance->state; + ovm_program_t *ovm_program = instance->module->program; + // // 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])); + case WASM_EXTERN_FUNC: { + wasm_func_t *func = wasm_extern_as_func(imports->data[i]); + bh_arr_push(instance->funcs, func); + + wasm_importtype_t *importtype = instance->module->imports.data[i]; + struct wasm_functype_inner_t *functype = &importtype->type->func; + + ovm_wasm_binding *binding = bh_alloc(ovm_store->arena_allocator, sizeof(*binding)); + binding->param_count = functype->params.size; + binding->result_count = functype->results.size; + binding->func = func; + + ovm_state_register_external_func(ovm_state, importtype->external_func_idx, ovm_to_wasm_func_call_binding, binding); break; + } - case WASM_EXTERN_MEMORY: - bh_arr_push(instance->memories, wasm_extern_as_memory(imports->data[i])); + case WASM_EXTERN_MEMORY: { + wasm_memory_t *memory = wasm_extern_as_memory(imports->data[i]); + bh_arr_push(instance->memories, memory); + + memory->inner.memory.engine = ovm_engine; break; + } + + case WASM_EXTERN_GLOBAL: { + wasm_global_t *global = wasm_extern_as_global(imports->data[i]); + + global->inner.global.engine = ovm_engine; + global->inner.global.state = ovm_state; + global->inner.global.register_index = bh_arr_length(instance->globals); - case WASM_EXTERN_GLOBAL: - bh_arr_push(instance->globals, wasm_extern_as_global(imports->data[i])); + ovm_value_t val = {0}; + WASM_TO_OVM(global->inner.global.initial_value, val); + ovm_state_register_set(ovm_state, global->inner.global.register_index, val); + + bh_arr_push(instance->globals, global); break; + } + + case WASM_EXTERN_TABLE: { + wasm_table_t *table = wasm_extern_as_table(imports->data[i]); + table->inner.table.engine = ovm_engine; + table->inner.table.program = ovm_program; + table->inner.table.static_arr = instance->module->imports.data[i]->type->table.static_arr; - case WASM_EXTERN_TABLE: - bh_arr_push(instance->tables, wasm_extern_as_table(imports->data[i])); + bh_arr_push(instance->tables, table); break; + } } } + ovm_state_register_external_func(ovm_state, instance->module->memory_init_external_idx, wasm_memory_init, instance); + // // 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->engine = ovm_engine; binding->func_idx = bh_arr_length(instance->funcs); - binding->program = instance->module->program; - binding->state = instance->state; + binding->program = ovm_program; + binding->state = ovm_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); @@ -122,7 +212,7 @@ static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t // 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; + memory->inner.memory.engine = ovm_engine; bh_arr_push(instance->memories, memory); } @@ -131,8 +221,8 @@ static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t // 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.engine = ovm_engine; + table->inner.table.program = ovm_program; table->inner.table.static_arr = instance->module->tabletypes.data[i]->type.table.static_arr; bh_arr_push(instance->tables, table); @@ -143,10 +233,15 @@ static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t 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.engine = ovm_engine; + global->inner.global.state = ovm_state; global->inner.global.register_index = bh_arr_length(instance->globals); + ovm_value_t val = {0}; + WASM_TO_OVM(global->inner.global.initial_value, val); + ovm_state_register_set(ovm_state, global->inner.global.register_index, val); + bh_arr_push(instance->globals, global); } @@ -157,7 +252,38 @@ static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t 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); + ovm_engine_memory_copy(ovm_engine, datum->offset, datum->data, datum->length); + } + + wasm_extern_vec_new_uninitialized(&instance->exports, instance->module->exports.size); + fori (i, 0, (int) instance->module->exports.size) { + wasm_exporttype_t *externtype = instance->module->exports.data[i]; + + switch (externtype->type->kind) { + case WASM_EXTERN_FUNC: { + wasm_func_t *func = instance->funcs[externtype->index]; + instance->exports.data[i] = wasm_func_as_extern(func); + break; + } + + case WASM_EXTERN_MEMORY: { + wasm_memory_t *memory = instance->memories[externtype->index]; + instance->exports.data[i] = wasm_memory_as_extern(memory); + break; + } + + case WASM_EXTERN_GLOBAL: { + wasm_global_t *global = instance->globals[externtype->index]; + instance->exports.data[i] = wasm_global_as_extern(global); + break; + } + + case WASM_EXTERN_TABLE: { + wasm_table_t *table = instance->tables[externtype->index]; + instance->exports.data[i] = wasm_table_as_extern(table); + break; + } + } } } @@ -178,10 +304,6 @@ wasm_instance_t *wasm_instance_new(wasm_store_t *store, const wasm_module_t *mod 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); @@ -190,3 +312,16 @@ wasm_instance_t *wasm_instance_new(wasm_store_t *store, const wasm_module_t *mod return instance; } +void wasm_instance_delete(wasm_instance_t *instance) { + bh_arr_free(instance->funcs); + bh_arr_free(instance->memories); + bh_arr_free(instance->globals); + bh_arr_free(instance->tables); + + wasm_extern_vec_delete(&instance->exports); + ovm_state_delete(instance->state); +} + +void wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) { + *out = instance->exports; +} diff --git a/src/wasm/module.c b/src/wasm/module.c index c430570..70c4848 100644 --- a/src/wasm/module.c +++ b/src/wasm/module.c @@ -15,6 +15,7 @@ static bool module_build(wasm_module_t *module, const wasm_byte_vec_t *binary) { ctx.module = module; ctx.program = module->program; ctx.store = engine->store; + ctx.next_external_func_idx = 0; while (ctx.offset < binary->size) { parse_section(&ctx); @@ -23,7 +24,7 @@ static bool module_build(wasm_module_t *module, const wasm_byte_vec_t *binary) { // 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; } @@ -67,6 +68,10 @@ wasm_module_t *wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binar return module; } +void wasm_module_delete(wasm_module_t *module) { + ovm_program_delete(module->program); +} + bool wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary) { // Hmmm... return false; diff --git a/src/wasm/module_parsing.c.incl b/src/wasm/module_parsing.c.incl index d37d6e2..5f411a9 100644 --- a/src/wasm/module_parsing.c.incl +++ b/src/wasm/module_parsing.c.incl @@ -19,6 +19,7 @@ struct build_context { ovm_store_t *store; int func_table_arr_idx; + int next_external_func_idx; // This will be set/reset for every code (function) entry. ovm_code_builder_t builder; @@ -163,7 +164,8 @@ static void parse_import_section(build_context *ctx) { module_name.data, module_name.size, import_name.data, import_name.size); - int external_func_idx = ctx->builder.next_external_func_idx++; + int external_func_idx = ctx->next_external_func_idx++; + import->external_func_idx = external_func_idx; ovm_program_register_external_func(ctx->program, external_func_name, import_type->func.params.size, external_func_idx); } @@ -420,11 +422,8 @@ static void parse_fc_instruction(build_context *ctx) { int dataidx = uleb128_to_uint(ctx->binary.data, &ctx->offset); assert(CONSUME_BYTE(ctx) == 0x00); - ovm_code_builder_drop_value(&ctx->builder); - ovm_code_builder_drop_value(&ctx->builder); - ovm_code_builder_drop_value(&ctx->builder); - - // TODO: MEMORY INIT INSTRUCTION + ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &dataidx); + ovm_code_builder_add_call(&ctx->builder, ctx->module->memory_init_idx, 4, false); break; } @@ -583,8 +582,10 @@ static void parse_instruction(build_context *ctx) { int entry_count = uleb128_to_uint(ctx->binary.data, &ctx->offset); int *entries = bh_alloc_array(bh_heap_allocator(), int, entry_count); + + int label_stack_count = bh_arr_length(ctx->builder.label_stack); fori (i, 0, entry_count) { - entries[i] = uleb128_to_uint(ctx->binary.data, &ctx->offset); + entries[i] = ctx->builder.label_stack[label_stack_count - 1 - uleb128_to_uint(ctx->binary.data, &ctx->offset)].idx; } int default_entry = uleb128_to_uint(ctx->binary.data, &ctx->offset); @@ -707,13 +708,17 @@ static void parse_instruction(build_context *ctx) { case 0x3F: { assert(CONSUME_BYTE(ctx) == 0x00); - int memory_size = 65536; + int memory_size = 65535; ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &memory_size); break; } case 0x40: { assert(CONSUME_BYTE(ctx) == 0x00); + ovm_code_builder_drop_value(&ctx->builder); + + int value = -1; + ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &value); break; } @@ -909,6 +914,11 @@ static void parse_code_section(build_context *ctx) { unsigned int code_count = uleb128_to_uint(ctx->binary.data, &ctx->offset); assert(ctx->module->functypes.size == code_count); + ctx->module->memory_init_external_idx = ctx->next_external_func_idx++; + + // HACK HACK HACK THIS IS SUCH A BAD WAY OF DOING THIS + ctx->module->memory_init_idx = bh_arr_length(ctx->program->funcs) + 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); @@ -936,6 +946,8 @@ static void parse_code_section(build_context *ctx) { ovm_program_register_func(ctx->program, func_name, ctx->builder.start_instr, ctx->builder.param_count, ctx->builder.highest_value_number + 1); ovm_code_builder_free(&ctx->builder); } + + ovm_program_register_external_func(ctx->program, "__internal_wasm_memory_init", 4, ctx->module->memory_init_external_idx); } diff --git a/src/wasm/store.c b/src/wasm/store.c index 07a3bc1..0f805b7 100644 --- a/src/wasm/store.c +++ b/src/wasm/store.c @@ -9,6 +9,5 @@ wasm_store_t *wasm_store_new(wasm_engine_t *engine) { } void wasm_store_delete(wasm_store_t *store) { - free(store); } diff --git a/src/wasm/trap.c b/src/wasm/trap.c index 0ade447..7909867 100644 --- a/src/wasm/trap.c +++ b/src/wasm/trap.c @@ -1,2 +1,23 @@ -// TODO +#include "onyx_wasm.h" +#include "vm.h" + +wasm_trap_t *wasm_trap_new(wasm_store_t *store, const wasm_message_t *msg) { + wasm_trap_t *trap = bh_alloc(store->engine->store->arena_allocator, sizeof(*trap)); + trap->msg = *msg; + + return trap; +} + +void wasm_trap_message(const wasm_trap_t *trap, wasm_message_t *out) { + *out = trap->msg; +} + +wasm_frame_t *wasm_trap_origin(const wasm_trap_t *trap) { + return NULL; +} + +void wasm_trap_trace(const wasm_trap_t *trap, wasm_frame_vec_t *frames) { + frames->size = 0; + frames->data = NULL; +}