From 2b0210c8fc9fa4200c867f2aafcb063c4aea4aa1 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Thu, 23 Jun 2022 23:06:30 -0500 Subject: [PATCH] removed the separation of native and internal functions --- include/vm.h | 66 ++++++++++++++------ include/vm_codebuilder.h | 13 +++- src/ovm_cli_test.c | 19 +++--- src/tools/assembler.c | 73 ++++++++++------------ src/vm/program_loader.c | 45 +++++++------- src/vm/vm.c | 130 ++++++++++++++++++--------------------- src/wasm_cli_test.c | 6 +- tests/ovm/out.ovm | Bin 674 -> 722 bytes tests/ovm/test.asm | 14 +++-- 9 files changed, 200 insertions(+), 166 deletions(-) diff --git a/include/vm.h b/include/vm.h index e83d73a..0321395 100644 --- a/include/vm.h +++ b/include/vm.h @@ -13,11 +13,14 @@ typedef struct ovm_engine_t ovm_engine_t; typedef struct ovm_program_t ovm_program_t; typedef struct ovm_state_t ovm_state_t; typedef struct ovm_stack_frame_t ovm_stack_frame_t; +typedef enum ovm_func_kind_t ovm_func_kind_t; typedef struct ovm_func_t ovm_func_t; -typedef struct ovm_native_func_t ovm_native_func_t; +typedef struct ovm_external_func_t ovm_external_func_t; +typedef struct ovm_linkable_func_t ovm_linkable_func_t; typedef struct ovm_value_t ovm_value_t; typedef struct ovm_instr_t ovm_instr_t; typedef struct ovm_static_data_t ovm_static_data_t; +typedef struct ovm_static_integer_array_t ovm_static_integer_array_t; // @@ -38,6 +41,11 @@ struct ovm_static_data_t { i64 length; }; +struct ovm_static_integer_array_t { + i32 start_idx; + i32 len; +}; + // // Represents a program that is runnable by the // VM. It can be constructed incrementally as needed. @@ -46,6 +54,11 @@ struct ovm_program_t { bh_arr(ovm_instr_t) code; bh_arr(ovm_func_t) funcs; + // + // TODO: Document these, and rename them. + bh_arr(i32) static_integers; + bh_arr(ovm_static_integer_array_t) static_data; + i32 register_count; ovm_store_t *store; }; @@ -56,7 +69,9 @@ void ovm_program_add_instructions(ovm_program_t *program, i32 instr_count, ovm_i void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count); 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); void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count); // @@ -75,8 +90,7 @@ ovm_engine_t *ovm_engine_new(ovm_store_t *store); void ovm_engine_delete(ovm_engine_t *engine); void ovm_engine_memory_copy(ovm_engine_t *engine, i64 target, void *data, i64 size); -bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, - ovm_state_t *state, char *filename); +bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, char *filename); // // Represents ephemeral state / execution context. @@ -99,14 +113,13 @@ struct ovm_state_t { // up with the specifications needed by WASM. In theory, different // running instances of the program *could* have different // native functions linked. - bh_arr(ovm_native_func_t) native_funcs; + bh_arr(ovm_external_func_t) external_funcs; }; 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_native_funcs(ovm_state_t *state, ovm_native_func_t *funcs); -void ovm_state_register_native_func(ovm_state_t *state, char *name, - void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count); +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); // // @@ -123,31 +136,45 @@ struct ovm_stack_frame_t { // // Represents a function that can be executed on the VM. // +enum ovm_func_kind_t { + OVM_FUNC_INTERNAL, + OVM_FUNC_EXTERNAL +}; + struct ovm_func_t { // // This ID is used as the index into the `funcs` member on ovm_program_t // to reference this function. It is only here for debugging and posterity. i32 id; + ovm_func_kind_t kind; char *name; + i32 param_count; + + union { + struct { + i32 start_instr; + i32 value_number_count; + }; + + i32 external_func_idx; + }; +}; - i32 start_instr; +struct ovm_external_func_t { + void (*native_func)(void *userdata, ovm_value_t* params, ovm_value_t* result); + void *userdata; +}; +struct ovm_linkable_func_t { + char *name; i32 param_count; - i32 value_number_count; + ovm_external_func_t func; }; ovm_func_t *ovm_func_new(); ovm_instr_t *ovm_func_add_instruction(ovm_func_t *func, ovm_instr_kind_t instr, ovm_valtype_t type); void ovm_func_delete(ovm_func_t *func); -struct ovm_native_func_t { - char *name; - i32 param_count; - - void (*native_func)(void *userdata, ovm_value_t* params, ovm_value_t* result); - void *userdata; -}; - 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); void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program); @@ -231,6 +258,7 @@ struct ovm_instr_t { #define OVMI_FILL 0x14 // memset(%r, %a, %b) #define OVMI_REG_GET 0x15 // %r = #a #define OVMI_REG_SET 0x16 // #r = %a +#define OVMI_IDX_ARR 0x17 // %r = (a)[%b] #define OVMI_LT 0x20 // %r = %a < %b #define OVMI_LT_S 0x21 // %r = %a < %b @@ -246,9 +274,7 @@ struct ovm_instr_t { #define OVMI_PARAM 0x30 // push %a #define OVMI_RETURN 0x31 // return %a #define OVMI_CALL 0x32 // %r = a(...) -#define OVMI_NATIVE_CALL 0x33 // %r = a(...) -#define OVMI_CALLI 0x34 // %r = %a(...) -#define OVMI_NATIVE_CALLI 0x35 // %r = %a(...) +#define OVMI_CALLI 0x33 // %r = %a(...) #define OVMI_BR 0x40 // br pc + a // Relative branching #define OVMI_BR_Z 0x41 // br pc + a if %b == 0 diff --git a/include/vm_codebuilder.h b/include/vm_codebuilder.h index 9d5cbe8..93d1879 100644 --- a/include/vm_codebuilder.h +++ b/include/vm_codebuilder.h @@ -25,6 +25,7 @@ struct ovm_code_builder_t { }; enum label_kind_t { + label_kind_func, label_kind_block, label_kind_loop, }; @@ -44,6 +45,16 @@ ovm_code_builder_t ovm_code_builder_new(ovm_program_t *program, i32 param_count, void ovm_code_builder_free(ovm_code_builder_t *builder); void ovm_code_builder_add_binop(ovm_code_builder_t *builder, u32 instr); void ovm_code_builder_add_imm(ovm_code_builder_t *builder, u32 ovm_type, void *imm); - +void ovm_code_builder_add_branch(ovm_code_builder_t *builder, i32 instr_delta); +void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx); +void ovm_code_builder_add_return(ovm_code_builder_t *builder); +void ovm_code_builder_add_call(ovm_code_builder_t *builder, i32 param_count); +void ovm_code_builder_add_indirect_call(ovm_code_builder_t *builder, i32 param_count); +void ovm_code_builder_drop_value(ovm_code_builder_t *builder); +void ovm_code_builder_add_local_get(ovm_code_builder_t *builder, i32 local_idx); +void ovm_code_builder_add_local_set(ovm_code_builder_t *builder, i32 local_idx); +void ovm_code_builder_add_register_get(ovm_code_builder_t *builder, i32 local_idx); +void ovm_code_builder_add_register_set(ovm_code_builder_t *builder, i32 local_idx); +void ovm_code_builder_add_load(ovm_code_builder_t *builder, u32 ovm_type, i32 offset); #endif diff --git a/src/ovm_cli_test.c b/src/ovm_cli_test.c index 3e5a0ca..98caf1e 100644 --- a/src/ovm_cli_test.c +++ b/src/ovm_cli_test.c @@ -16,10 +16,10 @@ void c_call_1f64(void *data, ovm_value_t *params, ovm_value_t *result) { int main(int argc, char *argv[]) { - static ovm_native_func_t native_funcs[] = { - { "dummy", 0, print_result, NULL }, - { "print", 1, print_result, NULL }, - { "sin", 1, c_call_1f64, sin }, + static ovm_linkable_func_t native_funcs[] = { + { "dummy", 0, { print_result, NULL } }, + { "print", 1, { print_result, NULL } }, + { "sin", 1, { c_call_1f64, sin } }, { NULL }, }; @@ -28,18 +28,21 @@ int main(int argc, char *argv[]) { ovm_engine_t *engine = ovm_engine_new(store); ovm_state_t *state = ovm_state_new(engine, prog); - ovm_program_load_from_file(prog, engine, state, argv[1]); + ovm_program_load_from_file(prog, engine, argv[1]); ovm_program_print_instructions(prog, 0, bh_arr_length(prog->code)); - ovm_state_link_native_funcs(state, native_funcs); + static int func_table[] = { 0, 1, 6 }; + ovm_program_register_static_ints(prog, 3, func_table); + + ovm_state_link_external_funcs(prog, state, native_funcs); state->pc = 0; ovm_value_t values[] = { { .type = OVM_TYPE_I32, .i32 = 1 }, { .type = OVM_TYPE_I32, .i32 = 2 }, }; - ovm_value_t result = ovm_func_call(engine, state, prog, 2, 0, values); - printf("%d %d\n", result.type, result.i32); + ovm_value_t result = ovm_func_call(engine, state, prog, 5, 0, values); + // printf("%d %d\n", result.type, result.i32); ovm_state_delete(state); ovm_engine_delete(engine); diff --git a/src/tools/assembler.c b/src/tools/assembler.c index a27216f..2610ffe 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -27,7 +27,6 @@ // Things to output to the binary static bh_arr(ovm_instr_t) instrs; static bh_arr(ovm_func_t) funcs; -static bh_arr(ovm_native_func_t) native_funcs; static bh_arr(char *) register_names; @@ -53,7 +52,7 @@ static bh_arr(active_label_t) active_labels; typedef enum operand_type_t { - op_none, op_reg, op_imm, op_sym + op_none, op_reg, op_imm, op_sym, op_neg_one } operand_type_t; struct instruction_mapping_t { @@ -131,6 +130,8 @@ static struct instruction_mapping_t instr_map[] = { { "reg.get", OVMI_REG_GET, op_reg, op_sym }, { "reg.set", OVMI_REG_SET, op_sym, op_reg }, + { "idxarr", OVMI_IDX_ARR, op_reg, op_imm, op_reg }, + { "param", OVMI_PARAM, op_none, op_reg }, { "br", OVMI_BR, op_none, op_sym }, { "bri", OVMI_BRI, op_none, op_reg }, @@ -147,7 +148,7 @@ static struct instruction_mapping_t instr_map[] = { { "return.f32", OVMI_RETURN, op_none, op_reg }, { "return.f64", OVMI_RETURN, op_none, op_reg }, - { "call", OVMI_CALL, op_none, op_sym }, + { "call", OVMI_CALL, op_neg_one, op_sym }, { "call.i8", OVMI_CALL, op_reg, op_sym }, { "call.i16", OVMI_CALL, op_reg, op_sym }, { "call.i32", OVMI_CALL, op_reg, op_sym }, @@ -155,7 +156,7 @@ static struct instruction_mapping_t instr_map[] = { { "call.f32", OVMI_CALL, op_reg, op_sym }, { "call.f64", OVMI_CALL, op_reg, op_sym }, - { "calli", OVMI_CALLI, op_reg, op_reg }, + { "calli", OVMI_CALLI, op_neg_one, op_reg }, { "calli.i8", OVMI_CALLI, op_reg, op_reg }, { "calli.i16", OVMI_CALLI, op_reg, op_reg }, { "calli.i32", OVMI_CALLI, op_reg, op_reg }, @@ -163,23 +164,6 @@ static struct instruction_mapping_t instr_map[] = { { "calli.f32", OVMI_CALLI, op_reg, op_reg }, { "calli.f64", OVMI_CALLI, op_reg, op_reg }, - { "native_call", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_NONE), op_none, op_sym }, - { "native_call.i8", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I8), op_reg , op_sym }, - { "native_call.i16", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I16), op_reg , op_sym }, - { "native_call.i32", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I32), op_reg , op_sym }, - { "native_call.i64", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I64), op_reg , op_sym }, - { "native_call.f32", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32), op_reg , op_sym }, - { "native_call.f64", OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F64), op_reg , op_sym }, - - { "native_calli", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_NONE), op_none, op_reg }, - { "native_calli.i8", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I8), op_reg , op_reg }, - { "native_calli.i16", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I16), op_reg , op_reg }, - { "native_calli.i32", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I32), op_reg , op_reg }, - { "native_calli.i64", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I64), op_reg , op_reg }, - { "native_calli.f32", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F32), op_reg , op_reg }, - { "native_calli.f64", OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F64), op_reg , op_reg }, - - { "cvt.i8.i16", OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I16), op_reg, op_reg }, { "cvt.i8.i32", OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I32), op_reg, op_reg }, { "cvt.i8.i64", OVM_TYPED_INSTR(OVMI_CVT_I8, OVM_TYPE_I64), op_reg, op_reg }, @@ -223,7 +207,7 @@ void parse_immediate(ovm_instr_t *instr) { token_t token = asm_lexer_next_token(); u32 type = OVM_INSTR_TYPE(*instr); - if (type == OVM_TYPE_I32 || type == OVM_TYPE_I16 || type == OVM_TYPE_I8) { + if (type == OVM_TYPE_I32 || type == OVM_TYPE_I16 || type == OVM_TYPE_I8 || type == OVM_TYPE_NONE) { EXPECT_TOKEN(token, token_integer); instr->i = atoi(token.text); } @@ -261,7 +245,6 @@ void parse_symbol(u32 instr_offset, ovm_instr_t *instr) { break; case OVMI_CALL: - case OVMI_NATIVE_CALL: bh_arr_push(call_patches, patch); break; @@ -315,6 +298,10 @@ void parse_instruction() { parse_symbol(bh_arr_length(instrs), &instr); \ token = asm_lexer_peek_token(); \ break; \ + \ + case op_neg_one: \ + instr.reg = -1; \ + break; \ } \ if (token.type == token_comma) { \ asm_lexer_next_token(); \ @@ -384,6 +371,7 @@ void parse_command() { EXPECT_TOKEN(param_token, token_integer); ovm_func_t f; + f.kind = OVM_FUNC_INTERNAL; f.start_instr = bh_arr_length(instrs); f.name = name_token.text; f.param_count = atoi(param_token.text); @@ -398,10 +386,11 @@ void parse_command() { token_t param_token = asm_lexer_next_token(); EXPECT_TOKEN(param_token, token_integer); - ovm_native_func_t f; + ovm_func_t f; + f.kind = OVM_FUNC_EXTERNAL; f.name = name_token.text; f.param_count = atoi(param_token.text); - bh_arr_push(native_funcs, f); + bh_arr_push(funcs, f); return; } @@ -448,7 +437,13 @@ void parse(char *input_file) { bh_file_close(&file); } +static int sort_funcs(a, b) ovm_func_t *a, *b; { + return b->kind - a->kind; +} + void patch() { + qsort(funcs, bh_arr_length(funcs), sizeof(*funcs), sort_funcs); + bh_arr_each(patch_t, patch, call_patches) { ovm_instr_t *instr = &instrs[patch->instr_offset]; @@ -460,13 +455,6 @@ void patch() { break; } } - } else if (patch->instr == OVMI_NATIVE_CALL) { - bh_arr_each(ovm_native_func_t, func, native_funcs) { - if (!strcmp(func->name, patch->name)) { - func_idx = func - native_funcs; - break; - } - } } assert(func_idx != -1); @@ -515,17 +503,16 @@ void write_file(char *output_file) { i32 data_count = 0; bh_file_write(&file, &data_count, 4); // Endian-dependent - i32 func_count = bh_arr_length(funcs); - bh_file_write(&file, &func_count, 4); // Endian-dependent + i32 func_count = 0; + i32 native_func_count = 0; bh_arr_each(ovm_func_t, func, funcs) { - bh_file_write(&file, &func->start_instr, 4); // Endian-dependent - bh_file_write(&file, &func->param_count, 4); // Endian-dependent - bh_file_write(&file, &func->value_number_count, 4); // Endian-dependent + if (func->kind == OVM_FUNC_INTERNAL) func_count += 1; + if (func->kind == OVM_FUNC_EXTERNAL) native_func_count += 1; } - i32 native_func_count = bh_arr_length(native_funcs); bh_file_write(&file, &native_func_count, 4); // Endian-dependent - bh_arr_each(ovm_native_func_t, func, native_funcs) { + bh_arr_each(ovm_func_t, func, funcs) { + if (func->kind == OVM_FUNC_INTERNAL) continue; bh_file_write(&file, &func->param_count, 4); // Endian-dependent i32 name_length = strlen(func->name) + 1; // Including null-terminator @@ -533,6 +520,14 @@ void write_file(char *output_file) { bh_file_write(&file, func->name, name_length); } + bh_file_write(&file, &func_count, 4); // Endian-dependent + bh_arr_each(ovm_func_t, func, funcs) { + if (func->kind == OVM_FUNC_EXTERNAL) continue; + bh_file_write(&file, &func->start_instr, 4); // Endian-dependent + bh_file_write(&file, &func->param_count, 4); // Endian-dependent + bh_file_write(&file, &func->value_number_count, 4); // Endian-dependent + } + i32 register_count = bh_arr_length(register_names); bh_file_write(&file, ®ister_count, 4); // Endian-dependent bh_arr_each(char *, register_name, register_names) { diff --git a/src/vm/program_loader.c b/src/vm/program_loader.c index a179100..f3162d3 100644 --- a/src/vm/program_loader.c +++ b/src/vm/program_loader.c @@ -15,7 +15,7 @@ // // ALSO, I wish this didn't have to take a state... but because native_funcs are stored // on the state, this is also the best I got... -bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, ovm_state_t *state, char *filename) { +bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, char *filename) { bh_file file; bh_file_error error = bh_file_open(&file, filename); if (error != BH_FILE_ERROR_NONE) { @@ -57,31 +57,32 @@ bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, ov } // - // Func section + // Native link section // + i32 next_external_func_idx = 0; bh_file_read(&file, &entry_count, sizeof(i32)); fori (i, 0, entry_count) { - i32 start_instr, param_count, value_number_count; - bh_file_read(&file, &start_instr, sizeof(i32)); + i32 param_count, name_len; bh_file_read(&file, ¶m_count, sizeof(i32)); - bh_file_read(&file, &value_number_count, sizeof(i32)); + bh_file_read(&file, &name_len, sizeof(i32)); - ovm_program_register_func(program, "LOADED", start_instr, param_count, value_number_count); + char *name_buf = bh_alloc_array(program->store->arena_allocator, char, name_len); + bh_file_read(&file, name_buf, name_len); + + ovm_program_register_external_func(program, name_buf, param_count, next_external_func_idx++); } // - // Native link section + // Func section // bh_file_read(&file, &entry_count, sizeof(i32)); fori (i, 0, entry_count) { - i32 param_count, name_len; + i32 start_instr, param_count, value_number_count; + bh_file_read(&file, &start_instr, sizeof(i32)); bh_file_read(&file, ¶m_count, sizeof(i32)); - bh_file_read(&file, &name_len, sizeof(i32)); - - char *name_buf = bh_alloc_array(program->store->arena_allocator, char, name_len); - bh_file_read(&file, name_buf, name_len); + bh_file_read(&file, &value_number_count, sizeof(i32)); - ovm_state_register_native_func(state, name_buf, NULL, NULL, param_count); + ovm_program_register_func(program, "LOADED", start_instr, param_count, value_number_count); } // @@ -103,25 +104,23 @@ bool ovm_program_load_from_file(ovm_program_t *program, ovm_engine_t *engine, ov return true; } -void ovm_state_link_native_funcs(ovm_state_t *state, ovm_native_func_t *funcs) { - bh_arr_each(ovm_native_func_t, nf, state->native_funcs) { - if (nf->native_func || nf->userdata) continue; +void ovm_state_link_external_funcs(ovm_program_t *program, ovm_state_t *state, ovm_linkable_func_t *funcs) { + bh_arr_each(ovm_func_t, f, program->funcs) { + if (f->kind == OVM_FUNC_INTERNAL) continue; - ovm_native_func_t *func = funcs; + ovm_linkable_func_t *func = funcs; while (func->name) { - if (!strcmp(nf->name, func->name) && nf->param_count == func->param_count) { - nf->native_func = func->native_func; - nf->userdata = func->userdata; + if (!strcmp(f->name, func->name) && f->param_count == func->param_count) { + ovm_state_register_external_func(state, f->external_func_idx, func->func.native_func, func->func.userdata); break; } func++; } - if (!nf->native_func) { - fprintf(stderr, "Failed to link to native function '%s'.\n", nf->name); + if (!state->external_funcs[f->external_func_idx].native_func) { + fprintf(stderr, "Failed to link to native function '%s'.\n", f->name); exit(1); } } } - diff --git a/src/vm/vm.c b/src/vm/vm.c index 278cc02..fd7bd55 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -41,8 +41,23 @@ void ovm_program_delete(ovm_program_t *program) { bh_free(program->store->heap_allocator, program); } +int ovm_program_register_static_ints(ovm_program_t *program, int len, int *data) { + ovm_static_integer_array_t new_entry; + new_entry.start_idx = bh_arr_length(program->static_integers); + new_entry.len = len; + + bh_arr_insert_end(program->static_integers, len); + fori (i, 0, (int) len) { + program->static_integers[i + new_entry.start_idx] = data[i]; + } + + bh_arr_push(program->static_data, new_entry); + return bh_arr_length(program->static_data) - 1; +} + void 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); func.name = name; func.start_instr = instr; @@ -52,6 +67,17 @@ void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i3 bh_arr_push(program->funcs, func); } +void 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); + func.name = name; + func.param_count = param_count; + func.external_func_idx = external_func_idx; + + bh_arr_push(program->funcs, func); +} + void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count) { ovm_func_t func; func.id = bh_arr_length(program->funcs); @@ -172,6 +198,8 @@ static char *ovm_instr_name(i32 full_instr) { C(OVMI_REG_GET) C(OVMI_REG_SET) + C(OVMI_IDX_ARR) + C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I8)) C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I16)) C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I32)) @@ -246,20 +274,6 @@ static char *ovm_instr_name(i32 full_instr) { C(OVMI_RETURN) C(OVMI_CALL) C(OVMI_CALLI) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_NONE)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I8)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I16)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I32)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I64)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F64)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_NONE)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I8)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I16)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I32)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I64)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F32)) - C(OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F64)) C(OVMI_BR) C(OVMI_BR_Z) @@ -308,7 +322,7 @@ void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 // 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 bh_arr_each(ovm_func_t, func, program->funcs) { - if (i == func->start_instr) { + if (i == func->start_instr && func->kind == OVM_FUNC_INTERNAL) { printf("\n[%d]%s:\n", func->id, func->name); } } @@ -373,6 +387,8 @@ ovm_state_t *ovm_state_new(ovm_engine_t *engine, ovm_program_t *program) { bh_arr_new(store->heap_allocator, state->registers, program->register_count); bh_arr_insert_end(state->registers, program->register_count); + bh_arr_new(store->heap_allocator, state->external_funcs, 8); + return state; } @@ -387,16 +403,12 @@ void ovm_state_delete(ovm_state_t *state) { bh_free(store->heap_allocator, state); } -void ovm_state_register_native_func(ovm_state_t *state, char *name, - void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count) { +void ovm_state_register_external_func(ovm_state_t *state, i32 idx, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data) { + ovm_external_func_t external_func; + external_func.native_func = func; + external_func.userdata = data; - ovm_native_func_t native_func; - native_func.name = name; - native_func.param_count = param_count; - native_func.native_func = func; - native_func.userdata = data; - - bh_arr_push(state->native_funcs, native_func); + bh_arr_set_at(state->external_funcs, idx, external_func); } @@ -436,6 +448,7 @@ ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_ 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); @@ -700,6 +713,12 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr break; } + case OVMI_IDX_ARR: { + VAL(instr.r).type = OVM_TYPE_I32; + VAL(instr.r).i32 = program->static_integers[program->static_data[instr.a].start_idx + VAL(instr.b).i32]; + break; + } + case OVMI_PARAM: bh_arr_push(state->params, VAL(instr.a)); break; @@ -721,16 +740,26 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define OVM_CALL_CODE(func_idx) \ i32 fidx = func_idx; \ - ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \ - \ ovm_func_t *func = &program->funcs[fidx]; \ - assert(func->param_count == bh_arr_length(state->params)); \ - fori (i, 0, func->param_count) { \ - VAL(i) = state->params[i]; \ - } \ - bh_arr_set_length(state->params, 0); \ + if (func->kind == OVM_FUNC_INTERNAL) { \ + ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \ + \ + assert(func->param_count == bh_arr_length(state->params)); \ + fori (i, 0, func->param_count) { \ + VAL(i) = state->params[i]; \ + } \ + bh_arr_set_length(state->params, 0); \ \ - state->pc = func->start_instr; + state->pc = func->start_instr; \ + } else { \ + 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); \ + if (instr.r >= 0) { \ + VAL(instr.r) = result; \ + } \ + } case OVMI_CALL: { OVM_CALL_CODE(instr.a); @@ -744,43 +773,6 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #undef OVM_CALL_CODE -#define OVM_NATIVE_CALL_CODE(func_idx) \ - ovm_native_func_t native_func = state->native_funcs[func_idx]; \ - assert(native_func.param_count == bh_arr_length(state->params)); \ - \ - ovm_value_t result = {0}; \ - native_func.native_func(native_func.userdata, state->params, &result); \ - bh_arr_set_length(state->params, 0); \ - \ - if (OVM_INSTR_TYPE(instr) != OVM_TYPE_NONE) { \ - assert(OVM_INSTR_TYPE(instr) == result.type); \ - VAL(instr.r) = result; \ - } - - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_NONE): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I8): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I16): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I32): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_I64): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F64): { - OVM_NATIVE_CALL_CODE(instr.a); - break; - } - - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_NONE): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I8): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I16): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I32): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_I64): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F32): - case OVM_TYPED_INSTR(OVMI_NATIVE_CALLI, OVM_TYPE_F64): { - OVM_NATIVE_CALL_CODE(VAL(instr.a).i32); - break; - } - -#undef OVM_NATIVE_CALL_CODE - case OVMI_BR: state->pc += instr.a; break; case OVMI_BRI: state->pc += VAL(instr.a).i32; break; case OVMI_BR_NZ: if (VAL(instr.b).i32 != 0) state->pc += instr.a; break; diff --git a/src/wasm_cli_test.c b/src/wasm_cli_test.c index b72caec..029d362 100644 --- a/src/wasm_cli_test.c +++ b/src/wasm_cli_test.c @@ -1,8 +1,12 @@ -#include "onyx_wasm.h" +#include "bh.h" +#include "wasm.h" int main(int argc, char *argv[]) { wasm_config_t *config = wasm_config_new(); + + // TODO: Add this to public header + void wasm_config_enable_debug(wasm_config_t *, bool); wasm_config_enable_debug(config, true); wasm_engine_t *engine = wasm_engine_new_with_config(config); diff --git a/tests/ovm/out.ovm b/tests/ovm/out.ovm index 9f68090ad81613a64de68b69153088d5679463d5..208d51a39ba22233904f4543dbe08b13c8111277 100644 GIT binary patch delta 218 zcmZ3)dWn_OKg`#Yfq{Whbs}dlhY^tV9|$IE5JnwS zkVY1$ga88rGe{Fmp*WBYlLLtx12I_rt2Kg`#Yfq{WhX(DGZhcS=^0uxgr5bPrblSLQ>1ehRF3@|m5Ll|{fL1K)P zw=$-)0EJm6D=^6@!{iyE>J6bZ5;eJ-Nt06wD!@EBmPua-q?!wei%Sxdv*Qa&iWmSu C*b^@R diff --git a/tests/ovm/test.asm b/tests/ovm/test.asm index 27fc31e..f6d8ffb 100644 --- a/tests/ovm/test.asm +++ b/tests/ovm/test.asm @@ -15,7 +15,7 @@ loop: param %0 - native_call print + call print sub.i32 %0, %0, %1 eq.i32 %3, %0, %2 @@ -24,7 +24,7 @@ // br skip imm.i32 %1, 123 param %1 - native_call print + call print skip: return @@ -37,12 +37,16 @@ param %1 call.i32 %2, add param %2 - native_call print + call print imm.i32 %3, 10 param %3 call count + imm.i32 %3, 2 + idxarr %4, 0, %3 + calli %4 + reg.set stack_ptr, %10 return @@ -52,10 +56,10 @@ mul.f32 %2, %0, %1 param %2 - native_call.f32 %3, sin + call.f32 %3, sin param %3 - native_call print + call print return -- 2.25.1