};
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 {
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;
};
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.
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.
// 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;
};
};
+// 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)
//
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);
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;
}
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);
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);
}
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]);
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))
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))
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);
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);
}
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;
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
// 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);
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--];
#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)
#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)
#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)
#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)
#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):
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");