removed the separation of native and internal functions
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 24 Jun 2022 04:06:30 +0000 (23:06 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 24 Jun 2022 04:06:30 +0000 (23:06 -0500)
include/vm.h
include/vm_codebuilder.h
src/ovm_cli_test.c
src/tools/assembler.c
src/vm/program_loader.c
src/vm/vm.c
src/wasm_cli_test.c
tests/ovm/out.ovm
tests/ovm/test.asm

index e83d73a00ab1947359f68a41e802731f4fe993ba..0321395be9901481e9cbaa1f14029e5e0d5a4ea6 100644 (file)
@@ -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
index 9d5cbe8d37dec7122347189dd3ec26bf7614e4a6..93d18796f38da70c44bf5a78f98e39ee1ce1f59b 100644 (file)
@@ -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
index 3e5a0cadfe8d3c69214cb83f80a26c9596fbba62..98caf1ef2ffdf913c51fda6e412aeec5fdce6188 100644 (file)
@@ -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);
index a27216fb6ff74847dd4c37a43a8d31f7073782e1..2610ffe9b985e1a6d56c20602841ca0cc308be0d 100644 (file)
@@ -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, &register_count, 4); // Endian-dependent
     bh_arr_each(char *, register_name, register_names) {
index a179100972a5f1559e4fbcc2120f8f22f8cedd63..f3162d390f47870b7123837f0a2db08b15f3b0d7 100644 (file)
@@ -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, &param_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, &param_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);
         }
     }
 }
-
index 278cc02536a8075a2c289a84d1d380a26fb2c7ea..fd7bd5512b38bea99c77ca8b2fc6fe763181553f 100644 (file)
@@ -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;
index b72caec9a0f2ad92324443ffa35cb690dfd98404..029d362ddc2e7e870e20ab983fa14d608fcf00a1 100644 (file)
@@ -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);
index 9f68090ad81613a64de68b69153088d5679463d5..208d51a39ba22233904f4543dbe08b13c8111277 100644 (file)
Binary files a/tests/ovm/out.ovm and b/tests/ovm/out.ovm differ
index 27fc31e7f28a31cebf6fcae035c7df5361e7766d..f6d8ffbd8897168b632e81cf34d04879ba4cd465 100644 (file)
@@ -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
 
     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