From 41d1df91deea6316408cc9d8a3bc6564a027f8c4 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 13 Jun 2022 21:57:08 -0500 Subject: [PATCH] small refactoring and more thorough testing --- include/vm.h | 106 +++++++++++------- src/cli.c | 37 ++++-- src/vm/vm.c | 310 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 346 insertions(+), 107 deletions(-) diff --git a/include/vm.h b/include/vm.h index 4005773..e0b7325 100644 --- a/include/vm.h +++ b/include/vm.h @@ -29,7 +29,7 @@ struct ovm_store_t { }; ovm_store_t *ovm_store_new(); -void ovm_Store_delete(ovm_store_t *store); +void ovm_store_delete(ovm_store_t *store); struct ovm_static_data_t { @@ -45,9 +45,8 @@ struct ovm_static_data_t { struct ovm_program_t { ovm_store_t *store; - bh_arr(ovm_func_t *) funcs; + bh_arr(ovm_func_t) funcs; bh_arr(ovm_native_func_t) native_funcs; - bh_arr(ovm_static_data_t) initialized_data; bh_arr(ovm_instr_t) code; }; @@ -55,10 +54,12 @@ struct ovm_program_t { ovm_program_t *ovm_program_new(ovm_store_t *store); void ovm_program_delete(ovm_program_t *program); void ovm_program_add_instructions(ovm_program_t *program, i32 instr_count, ovm_instr_t *instrs); -void ovm_program_register_func(ovm_program_t *program, i32 instr, i32 param_count, i32 value_number_count); -void ovm_program_register_native_func(ovm_program_t *program, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count); void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count); +void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count); +void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count); +void ovm_program_register_native_func(ovm_program_t *program, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data, i32 param_count); + // // Represents the running configuration and static // data needed by the VM. This is for more "global" data. @@ -73,6 +74,7 @@ struct ovm_engine_t { 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); // // Represents ephemeral state / execution context. @@ -113,6 +115,7 @@ 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; + char *name; i32 start_instr; @@ -195,45 +198,62 @@ struct ovm_instr_t { }; }; +// Missing instructions +// - mov +// - load +// - store +// - copy +// - fill + + #define OVMI_NOP 0x00 -#define OVMI_ADD 0x01 // r = a + b -#define OVMI_SUB 0x02 // r = a - b -#define OVMI_MUL 0x03 // r = a * b -#define OVMI_DIV 0x04 // r = a / b -#define OVMI_REM 0x05 // r = a % b - -#define OVMI_AND 0x06 // r = a & b -#define OVMI_OR 0x07 // r = a | b -#define OVMI_XOR 0x08 // r = a ^ b -#define OVMI_NOT 0x09 // r = ~a -#define OVMI_SHL 0x0A // r = a << b -#define OVMI_SHR 0x0B // r = a >> b -#define OVMI_SAR 0x0C // r = a >>> b - -#define OVMI_IMM 0x0D // r = imm a - -#define OVMI_LT 0x20 // r = a < b -#define OVMI_LT_S 0x21 // r = a < b -#define OVMI_LE 0x22 // r = a <= b -#define OVMI_LE_S 0x23 // r = a <= b -#define OVMI_EQ 0x24 // r = a == b -#define OVMI_GE 0x25 // r = a >= b -#define OVMI_GE_S 0x26 // r = a >= b -#define OVMI_GT 0x27 // r = a > b -#define OVMI_GT_S 0x28 // r = a > b -#define OVMI_NE 0x29 // r = a != b - -#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_BR 0x40 // br a -#define OVMI_BR_NZ 0x41 // br a if b != 0 - -#define OVMI_CLZ 0x50 // r = clz(a) -#define OVMI_CTZ 0x51 // r = ctr(a) -#define OVMI_POPCNT 0x52 // r = popcnt(a) +#define OVMI_ADD 0x01 // $r = $a + $b +#define OVMI_SUB 0x02 // $r = $a - $b +#define OVMI_MUL 0x03 // $r = $a * $b +#define OVMI_DIV 0x04 // $r = $a / $b +#define OVMI_REM 0x05 // $r = $a % $b + +#define OVMI_AND 0x06 // $r = $a & $b +#define OVMI_OR 0x07 // $r = $a | $b +#define OVMI_XOR 0x08 // $r = $a ^ $b +#define OVMI_NOT 0x09 // $r = ~$a +#define OVMI_SHL 0x0A // $r = $a << $b +#define OVMI_SHR 0x0B // $r = $a >> $b +#define OVMI_SAR 0x0C // $r = $a >>> $b + +#define OVMI_IMM 0x10 // $r = i/l/f/d +#define OVMI_MOV 0x10 // $r = $a +#define OVMI_LOAD 0x11 // $r = mem[$a] +#define OVMI_STORE 0x12 // mem[$a] = $b +#define OVMI_COPY 0x13 // memcpy($r, $a, $b) +#define OVMI_FILL 0x14 // memset($r, $a, $b) + +#define OVMI_LT 0x20 // $r = $a < $b +#define OVMI_LT_S 0x21 // $r = $a < $b +#define OVMI_LE 0x22 // $r = $a <= $b +#define OVMI_LE_S 0x23 // $r = $a <= $b +#define OVMI_EQ 0x24 // $r = $a == $b +#define OVMI_GE 0x25 // $r = $a >= $b +#define OVMI_GE_S 0x26 // $r = $a >= $b +#define OVMI_GT 0x27 // $r = $a > $b +#define OVMI_GT_S 0x28 // $r = $a > $b +#define OVMI_NE 0x29 // $r = $a != $b + +#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_BR 0x40 // br pc + a // Relative branching +#define OVMI_BR_NZ 0x41 // br pc + a if $b != 0 +#define OVMI_BRI 0x42 // br pc + $a // Relative branching +#define OVMI_BRI_NZ 0x43 // br pc + $a if $b != 0 + +#define OVMI_CLZ 0x50 // $r = clz($a) +#define OVMI_CTZ 0x51 // $r = ctr($a) +#define OVMI_POPCNT 0x52 // $r = popcnt($a) // diff --git a/src/cli.c b/src/cli.c index 0fe3882..ea9a97e 100644 --- a/src/cli.c +++ b/src/cli.c @@ -13,30 +13,42 @@ int main(int argc, char *argv[]) { ovm_program_t *prog = ovm_program_new(store); - static ovm_instr_t instrs[] = { + ovm_instr_t func1_instrs[] = { // { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 0, 10 }, // { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 1, 20 }, // { .full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_F32), 2, 0, 1 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 6, 10 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 7, 1 }, { .full_instr = OVMI_PARAM, 0, 0 }, { .full_instr = OVMI_PARAM, 0, 1 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 5, 1 }, - { .full_instr = OVMI_CALL, 2, 5 }, + { .full_instr = OVMI_CALL, 2, 1 }, { .full_instr = OVMI_PARAM, 0, 2 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 3, 0 }, - { .full_instr = OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32), 4, 3 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_NATIVE_CALL, OVM_TYPE_F32), 4, 0 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_SUB, OVM_TYPE_I32), 6, 6, 7 }, + { .full_instr = OVMI_BR_NZ, 0, -4, 6 }, { .full_instr = OVMI_RETURN, 0, 4 }, + }; - + ovm_instr_t func2_instrs[] = { { .full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_F32), 2, 0, 1 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 3, 0x1000 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_F32), 0, 3, 2 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 4, 0x2000 }, + { .full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32), 5, 4 }, + { .full_instr = OVMI_COPY, 4, 3, 5 }, + + { .full_instr = OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_F32), 2, 4 }, { .full_instr = OVMI_RETURN, 0, 2 }, }; - ovm_program_add_instructions(prog, sizeof(instrs) / sizeof(*instrs), instrs); - ovm_program_register_func(prog, 0, 2, 5); - ovm_program_register_func(prog, 8, 2, 3); + ovm_program_begin_func(prog, "main", 2, 8); + ovm_program_add_instructions(prog, sizeof(func1_instrs) / sizeof(*func1_instrs), func1_instrs); + ovm_program_begin_func(prog, "add", 2, 6); + ovm_program_add_instructions(prog, sizeof(func2_instrs) / sizeof(*func2_instrs), func2_instrs); + ovm_program_register_native_func(prog, print_result, NULL, 1); - ovm_program_print_instructions(prog, 0, sizeof(instrs) / sizeof(*instrs)); + ovm_program_print_instructions(prog, 0, bh_arr_length(prog->code)); ovm_engine_t *engine = ovm_engine_new(store); ovm_state_t *state = ovm_state_new(engine); @@ -49,5 +61,10 @@ int main(int argc, char *argv[]) { ovm_value_t result = ovm_func_call(engine, state, prog, 0, 2, values); printf("%d %f\n", result.type, result.f32); + ovm_state_delete(state); + ovm_engine_delete(engine); + ovm_program_delete(prog); + ovm_store_delete(store); + return 0; } diff --git a/src/vm/vm.c b/src/vm/vm.c index 9465cb5..cf6ec4a 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -29,7 +29,6 @@ ovm_program_t *ovm_program_new(ovm_store_t *store) { bh_arr_new(store->heap_allocator, program->funcs, 16); bh_arr_new(store->heap_allocator, program->native_funcs, 16); - bh_arr_new(store->heap_allocator, program->initialized_data, 16); bh_arr_new(store->heap_allocator, program->code, 1024); @@ -39,19 +38,18 @@ 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->native_funcs); - bh_arr_free(program->initialized_data); bh_arr_free(program->code); bh_free(program->store->heap_allocator, program); } -void ovm_program_register_func(ovm_program_t *program, i32 instr, i32 param_count, i32 value_number_count) { - ovm_func_t *func = bh_alloc_item(program->store->arena_allocator, ovm_func_t); - - func->start_instr = instr; - func->param_count = param_count; - func->value_number_count = value_number_count; - func->id = bh_arr_length(program->funcs); +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.id = bh_arr_length(program->funcs); + func.name = name; + func.start_instr = instr; + func.param_count = param_count; + func.value_number_count = value_number_count; bh_arr_push(program->funcs, func); } @@ -65,6 +63,17 @@ void ovm_program_register_native_func(ovm_program_t *program, void (*func)(void bh_arr_push(program->native_funcs, native_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); + func.name = name; + func.start_instr = bh_arr_length(program->code); + func.param_count = param_count; + func.value_number_count = value_number_count; + + bh_arr_push(program->funcs, func); +} + void ovm_program_add_instructions(ovm_program_t *program, i32 instr_count, ovm_instr_t *instrs) { fori (i, 0, instr_count) { bh_arr_push(program->code, instrs[i]); @@ -78,6 +87,8 @@ static char *ovm_instr_name(i32 full_instr) { static char buf[64]; switch (full_instr) { + C(OVMI_NOP) + C(OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I8)) C(OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I16)) C(OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32)) @@ -153,10 +164,96 @@ static char *ovm_instr_name(i32 full_instr) { C(OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_F32)) C(OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_F64)) + C(OVMI_MOV) + C(OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_LOAD, OVM_TYPE_F64)) + C(OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_STORE, OVM_TYPE_F64)) + C(OVMI_COPY) + C(OVMI_FILL) + + 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)) + C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_LT, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_LE, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_LE_S, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_LE_S, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_LE_S, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_LE_S, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_LE_S, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_LE_S, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_GE_S, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_GT, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_GT, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_GT, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_GT, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_GT, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_GT, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_GT_S, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_GT_S, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_GT_S, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_GT_S, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_GT_S, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_GT_S, OVM_TYPE_F64)) + + C(OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I8)) + C(OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I16)) + C(OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I32)) + C(OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I64)) + C(OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_F32)) + C(OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_F64)) + C(OVMI_PARAM) - C(OVMI_CALL) 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)) @@ -164,6 +261,16 @@ static char *ovm_instr_name(i32 full_instr) { 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_NZ) default: snprintf(buf, 64, "unknown (%d)", full_instr); @@ -173,6 +280,15 @@ 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) { + // + // 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) { + printf("\n[%d]%s:\n", func->id, func->name); + } + } + ovm_instr_t instr = program->code[i]; printf("%48s | 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); } @@ -186,7 +302,7 @@ ovm_engine_t *ovm_engine_new(ovm_store_t *store) { ovm_engine_t *engine = bh_alloc_item(store->heap_allocator, ovm_engine_t); engine->store = store; - engine->memory_size = 1 << 16; + engine->memory_size = 1ull << 32; engine->memory = mmap(NULL, engine->memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); return engine; @@ -199,6 +315,15 @@ void ovm_engine_delete(ovm_engine_t *engine) { bh_free(store->heap_allocator, engine); } +void ovm_engine_memory_copy(ovm_engine_t *engine, i64 target, void *data, i64 size) { + assert(engine); + assert(engine->memory); + assert(data); + assert(size + target < engine->memory_size); + memcpy(((u8 *) engine->memory) + target, data, size); +} + + // // State @@ -232,14 +357,14 @@ void ovm_state_delete(ovm_state_t *state) { // Function calling static void ovm__func_setup_stack_frame(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program, i32 func_idx, i32 result_number) { - ovm_func_t *func = program->funcs[func_idx]; + ovm_func_t *func = &program->funcs[func_idx]; // // Push a stack frame ovm_stack_frame_t frame; frame.func = func; frame.value_number_count = func->value_number_count; - frame.value_number_base = state->value_number_offset + func->value_number_count; + frame.value_number_base = bh_arr_length(state->numbered_values); frame.return_address = state->pc; frame.return_number_value = result_number; bh_arr_push(state->stack_frames, frame); @@ -264,7 +389,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]; } - state->pc = program->funcs[func_idx]->start_instr; + state->pc = program->funcs[func_idx].start_instr; ovm_run_code(engine, state, program); return state->numbered_values[state->value_number_offset--]; @@ -294,7 +419,8 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define OVM_OP(i, t, op, ctype) \ case OVM_TYPED_INSTR(i, t): \ - (VAL(instr.r).ctype = VAL(instr.a).ctype op VAL(instr.b).ctype); \ + VAL(instr.r).type = t; \ + VAL(instr.r).ctype = VAL(instr.a).ctype op VAL(instr.b).ctype; \ break; OVM_OP(OVMI_ADD, OVM_TYPE_I8 , +, i8) @@ -359,7 +485,8 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define OVM_OP(i, t, op, ctype) \ case OVM_TYPED_INSTR(i, t): \ - (VAL(instr.r).ctype = op VAL(instr.a).ctype); \ + VAL(instr.r).type = t; \ + VAL(instr.r).ctype = op VAL(instr.a).ctype; \ break; OVM_OP(OVMI_NOT, OVM_TYPE_I8 , ~, i8) @@ -371,7 +498,8 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #define OVM_OP(i, t, op, ctype, cast_type) \ case OVM_TYPED_INSTR(i, t): \ - (VAL(instr.r).i32 = (i32) ((cast_type) VAL(instr.a).ctype op (cast_type) VAL(instr.b).ctype)); \ + VAL(instr.r).type = OVM_TYPE_I32; \ + VAL(instr.r).i32 = (i32) ((cast_type) VAL(instr.a).ctype op (cast_type) VAL(instr.b).ctype); \ break; OVM_OP(OVMI_LT, OVM_TYPE_I8 , <, i8, u8) @@ -446,9 +574,10 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #undef OVM_OP -#define OVM_IMM(type, dtype, stype) \ - case OVM_TYPED_INSTR(OVMI_IMM, type): \ - (VAL(instr.r).dtype = instr.stype); \ +#define OVM_IMM(t, dtype, stype) \ + case OVM_TYPED_INSTR(OVMI_IMM, t): \ + VAL(instr.r).type = t; \ + VAL(instr.r).dtype = instr.stype; \ break; OVM_IMM(OVM_TYPE_I8, i8, i) @@ -460,39 +589,113 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr #undef OVM_IMM - case OVMI_PARAM: - bh_arr_push(state->params, VAL(instr.a)); + case OVMI_MOV: + VAL(instr.r) = VAL(instr.a); break; - case OVMI_CALL: { - i32 func_idx = VAL(instr.a).i32; - ovm__func_setup_stack_frame(engine, state, program, func_idx, instr.r); - - // - // Apply parameters - ovm_func_t *func = program->funcs[func_idx]; - fori (i, 0, func->param_count) { - VAL(i) = state->params[i]; - } - bh_arr_set_length(state->params, 0); - - state->pc = func->start_instr; +#define OVM_LOAD(type_, stype) \ + case OVM_TYPED_INSTR(OVMI_LOAD, type_): \ + VAL(instr.r).type = type_; \ + VAL(instr.r).stype = * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32]; \ + break; + + OVM_LOAD(OVM_TYPE_I8, i8) + OVM_LOAD(OVM_TYPE_I16, i16) + OVM_LOAD(OVM_TYPE_I32, i32) + OVM_LOAD(OVM_TYPE_I64, i64) + OVM_LOAD(OVM_TYPE_F32, f32) + OVM_LOAD(OVM_TYPE_F64, f64) + +#undef OVM_LOAD + +#define OVM_STORE(type_, stype) \ + case OVM_TYPED_INSTR(OVMI_STORE, type_): \ + * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32] = VAL(instr.b).stype; \ + break; + + OVM_STORE(OVM_TYPE_I8, i8) + OVM_STORE(OVM_TYPE_I16, i16) + OVM_STORE(OVM_TYPE_I32, i32) + OVM_STORE(OVM_TYPE_I64, i64) + OVM_STORE(OVM_TYPE_F32, f32) + OVM_STORE(OVM_TYPE_F64, f64) + +#undef OVM_STORE + + case OVMI_COPY: { + i32 dest = VAL(instr.r).i32; + i32 src = VAL(instr.a).i32; + i32 count = VAL(instr.b).i32; + + u8 *base = engine->memory; + memcpy(&base[dest], &base[src], count); + break; + } + + case OVMI_FILL: { + i32 dest = VAL(instr.r).i32; + i8 byte = VAL(instr.a).i8; + i32 count = VAL(instr.b).i32; + + u8 *base = engine->memory; + memset(&base[dest], byte, count); break; } + case OVMI_PARAM: + bh_arr_push(state->params, VAL(instr.a)); + break; + case OVMI_RETURN: { ovm_stack_frame_t frame = bh_arr_pop(state->stack_frames); ovm_value_t val = VAL(instr.a); bh_arr_fastdeleten(state->numbered_values, frame.value_number_count); - state->value_number_offset = frame.value_number_base; + state->value_number_offset = bh_arr_last(state->stack_frames).value_number_base; VAL(frame.return_number_value) = val; state->pc = frame.return_address; break; } +#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); \ + \ + state->pc = func->start_instr; + + case OVMI_CALL: { + OVM_CALL_CODE(instr.a); + break; + } + + case OVMI_CALLI: { + OVM_CALL_CODE(VAL(instr.a).i32); + break; + } + +#undef OVM_CALL_CODE + +#define OVM_NATIVE_CALL_CODE(func_idx) \ + ovm_native_func_t native_func = program->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 (instr.type != OVM_TYPE_NONE) { \ + 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): @@ -500,28 +703,27 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr 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_func_t native_func = program->native_funcs[VAL(instr.a).i32]; - - ovm_value_t result = {0}; - native_func.native_func(native_func.userdata, state->params, &result); - bh_arr_set_length(state->params, 0); - - if (instr.type != OVM_TYPE_NONE) { - VAL(instr.r) = result; - } - + OVM_NATIVE_CALL_CODE(instr.a); break; } - case OVMI_BR: - state->pc = VAL(instr.a).i32; + 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; + } - case OVMI_BR_NZ: - if (VAL(instr.a).i32 != 0) { - state->pc = VAL(instr.r).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; + case OVMI_BRI_NZ: if (VAL(instr.b).i32 != 0) state->pc += VAL(instr.a).i32; break; default: printf("ERROR:\n"); -- 2.25.1