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;
//
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.
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;
};
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);
//
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.
// 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);
//
//
//
// 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);
#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
#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
};
enum label_kind_t {
+ label_kind_func,
label_kind_block,
label_kind_loop,
};
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
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 },
};
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);
// 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;
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 {
{ "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 },
{ "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 },
{ "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 },
{ "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 },
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);
}
break;
case OVMI_CALL:
- case OVMI_NATIVE_CALL:
bh_arr_push(call_patches, patch);
break;
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(); \
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);
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;
}
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];
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);
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
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) {
//
// 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) {
}
//
- // 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);
}
//
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);
}
}
}
-
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;
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);
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))
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)
// 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);
}
}
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;
}
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);
}
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);
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;
#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);
#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;
-#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);
loop:
param %0
- native_call print
+ call print
sub.i32 %0, %0, %1
eq.i32 %3, %0, %2
// br skip
imm.i32 %1, 123
param %1
- native_call print
+ call print
skip:
return
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
mul.f32 %2, %0, %1
param %2
- native_call.f32 %3, sin
+ call.f32 %3, sin
param %3
- native_call print
+ call print
return