closer to converting wasm -> ovm
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 22 Jun 2022 03:13:14 +0000 (22:13 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 22 Jun 2022 03:13:14 +0000 (22:13 -0500)
13 files changed:
build.sh
include/onyx_wasm.h
math.asm [deleted file]
src/cli.c [deleted file]
src/ovm_cli_test.c [new file with mode: 0644]
src/wasm/module.c
src/wasm_cli_test.c [new file with mode: 0644]
test.asm [deleted file]
tests/ovm/math.asm [new file with mode: 0644]
tests/ovm/out.ovm [new file with mode: 0644]
tests/ovm/test.asm [new file with mode: 0644]
tests/wasm/out.wasm [new file with mode: 0644]
tests/wasm/tiny.onyx [new file with mode: 0644]

index cea3591b3492b4e658db1806af4e332800061513..8ebf1016d5a375e9d589db71969d60571017f1d4 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -10,15 +10,24 @@ C_FILES="src/wasm.c src/vm/* src/wasm/*"
 
 $CC $FLAGS $INCLUDES -shared -fPIC -o $TARGET $C_FILES $LIBS $WARNINGS
 
-C_FILES="src/cli.c"
-TARGET=onyx-debug
+
+C_FILES="src/ovm_cli_test.c"
+TARGET=bin/ovm_cli_test
 LIBS="-L$(pwd) -lonyx_embedder -lm -Wl,-rpath=./"
 
 $CC $FLAGS $INCLUDES -o $TARGET $C_FILES $LIBS $WARNINGS
 
+
+C_FILES="src/wasm_cli_test.c"
+TARGET=bin/wasm_cli_test
+LIBS="-L$(pwd) -lonyx_embedder -lm -Wl,-rpath=./"
+
+$CC $FLAGS $INCLUDES -o $TARGET $C_FILES $LIBS $WARNINGS
+
+
 flex -o src/tools/lex.yy.c src/tools/asm.l
 
-TARGET="assembler"
+TARGET="bin/assembler"
 C_FILES="src/tools/assembler.c src/tools/lex.yy.c"
 
 $CC $FLAGS $INCLUDES -o $TARGET $C_FILES $LIBS $WARNINGS
index 971b68fecbd6f7b3b3f6d170e4f4f89da40d0c88..b93dc65a83f2c866bc302e1e3c8637a5adc073fe 100644 (file)
@@ -75,6 +75,7 @@ struct wasm_importtype_t {
 struct wasm_exporttype_t {
     wasm_name_t *name;
     wasm_externtype_t *type;
+    int index;
 };
 
 
@@ -92,6 +93,13 @@ struct wasm_trap_t {
 struct wasm_foreign_t {
 };
 
+struct wasm_data_t {
+    void *data;
+    unsigned int length;
+    unsigned int offset;
+    bool passive;
+};
+
 struct wasm_module_t {
     wasm_store_t *store;
 
@@ -105,8 +113,14 @@ struct wasm_module_t {
     wasm_exporttype_vec_t exports;
 
     int start_func_idx;
+
+    unsigned int elem_count;
     unsigned int *elem_entries; // Array of function indicies
 
+    bool data_count_present;
+    unsigned int data_count;
+    struct wasm_data_t *data_entries;
+
     ovm_program_t *program;
     bool valid;
 };
@@ -154,6 +168,14 @@ struct wasm_instance_t {
 };
 
 
+
+wasm_functype_t   *wasm_module_index_functype(wasm_module_t *module, int index);
+wasm_tabletype_t  *wasm_module_index_tabletype(wasm_module_t *module, int index);
+wasm_globaltype_t *wasm_module_index_globaltype(wasm_module_t *module, int index);
+wasm_memorytype_t *wasm_module_index_memorytype(wasm_module_t *module, int index);
+
+
+
 #define WASM_DECLARE_VEC_IMPL(type, ptr_or_none) \
     void wasm_##type##_vec_new_empty(wasm_##type##_vec_t *out) { \
         out->size = 0; \
@@ -161,12 +183,12 @@ struct wasm_instance_t {
     } \
      \
     void wasm_##type##_vec_new_uninitialized(wasm_##type##_vec_t *out, size_t size) { \
-        out->data = malloc(sizeof(wasm_##type##_t) * size); \
+        out->data = malloc(sizeof(wasm_##type##_t ptr_or_none) * size); \
         out->size = size; \
     } \
      \
     void wasm_##type##_vec_new(wasm_##type##_vec_t *out, size_t size, wasm_##type##_t ptr_or_none const data[]) { \
-        out->data = malloc(sizeof(wasm_##type##_t) * size); \
+        out->data = malloc(sizeof(wasm_##type##_t ptr_or_none) * size); \
         out->size = size; \
      \
         fori (i, 0, (i32) size) { \
diff --git a/math.asm b/math.asm
deleted file mode 100644 (file)
index bacaf30..0000000
--- a/math.asm
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-.native_func print 1
-
-
-.func main 2
-    mov %2, %0
-    mov %3, %1
-    add.i32 %2, %2, %3
-    imm.i32 %3, 10
-    add.i32 %2, %2, %3
-    param %2
-    native_call print
-
diff --git a/src/cli.c b/src/cli.c
deleted file mode 100644 (file)
index 330685e..0000000
--- a/src/cli.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "vm.h"
-
-#include <math.h>
-
-void print_result(void *data, ovm_value_t *params, ovm_value_t *result) {
-    switch (params[0].type) {
-        case OVM_TYPE_I32: printf("Result: %d\n", params[0].i32); break;
-        case OVM_TYPE_F32: printf("Result: %f\n", params[0].f32); break;
-    }
-}
-
-void c_call_1f64(void *data, ovm_value_t *params, ovm_value_t *result) {
-     result->type = OVM_TYPE_F32;
-     result->f32  = (f32) ((f64 (*)(f64)) data)(params[0].f32);
-}
-
-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 },
-        { NULL },
-    };
-
-    ovm_store_t *store = ovm_store_new();
-    ovm_program_t *prog = ovm_program_new(store);
-    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, "./out.ovm");
-    ovm_program_print_instructions(prog, 0, bh_arr_length(prog->code));
-
-    ovm_state_link_native_funcs(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_state_delete(state);
-    ovm_engine_delete(engine);
-    ovm_program_delete(prog);
-    ovm_store_delete(store);
-
-    return 0;
-}
diff --git a/src/ovm_cli_test.c b/src/ovm_cli_test.c
new file mode 100644 (file)
index 0000000..330685e
--- /dev/null
@@ -0,0 +1,50 @@
+#include "vm.h"
+
+#include <math.h>
+
+void print_result(void *data, ovm_value_t *params, ovm_value_t *result) {
+    switch (params[0].type) {
+        case OVM_TYPE_I32: printf("Result: %d\n", params[0].i32); break;
+        case OVM_TYPE_F32: printf("Result: %f\n", params[0].f32); break;
+    }
+}
+
+void c_call_1f64(void *data, ovm_value_t *params, ovm_value_t *result) {
+     result->type = OVM_TYPE_F32;
+     result->f32  = (f32) ((f64 (*)(f64)) data)(params[0].f32);
+}
+
+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 },
+        { NULL },
+    };
+
+    ovm_store_t *store = ovm_store_new();
+    ovm_program_t *prog = ovm_program_new(store);
+    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, "./out.ovm");
+    ovm_program_print_instructions(prog, 0, bh_arr_length(prog->code));
+
+    ovm_state_link_native_funcs(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_state_delete(state);
+    ovm_engine_delete(engine);
+    ovm_program_delete(prog);
+    ovm_store_delete(store);
+
+    return 0;
+}
index c42f9103787292df4b78a4a6195fd528a3230bb3..84c6f7084261f7e778a9b8a688d261642592a4e2 100644 (file)
@@ -95,7 +95,7 @@ static wasm_tabletype_t *parse_tabletype(build_context *ctx) {
     assert(CONSUME_BYTE(ctx) == 0x70); // @ReportError
 
     wasm_limits_t limits = parse_limits(ctx);
-    wasm_tabletype_t *tt = wasm_tabletype_new(wasm_valtype_new(0x70), &limits);
+    wasm_tabletype_t *tt = wasm_tabletype_new(wasm_valtype_new(WASM_FUNCREF), &limits);
     return tt;
 }
 
@@ -155,7 +155,8 @@ static void parse_func_section(build_context *ctx) {
     wasm_functype_vec_new_uninitialized(&ctx->module->functypes, func_count);
 
     fori (i, 0, (int) func_count) {
-        ctx->module->functypes.data[i] = ctx->module->type_section.data[i];
+        unsigned int index = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+        ctx->module->functypes.data[i] = ctx->module->type_section.data[index];
     }
 }
 
@@ -218,6 +219,8 @@ static void parse_global_section(build_context *ctx) {
             }
         }
 
+        assert(CONSUME_BYTE(ctx) == 0x0b);
+
         ctx->module->globaltypes.data[i] = gt;
     }
 }
@@ -234,20 +237,20 @@ static void parse_export_section(build_context *ctx) {
         wasm_byte_vec_new_uninitialized(&export_name, export_name_size);
         fori (n, 0, export_name_size) export_name.data[n] = CONSUME_BYTE(ctx);
 
-        wasm_externtype_t *export_type;
-        switch (CONSUME_BYTE(ctx)) {
-            case 0x00: {
-                unsigned int type_idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
-                export_type = wasm_functype_as_externtype(ctx->module->type_section.data[type_idx]);
-                break;
-            }
+        unsigned int type = CONSUME_BYTE(ctx);
+        unsigned int idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
 
-            case 0x01: export_type = wasm_tabletype_as_externtype(parse_tabletype(ctx)); break;
-            case 0x02: export_type = wasm_memorytype_as_externtype(parse_memorytype(ctx)); break;
-            case 0x03: export_type = wasm_globaltype_as_externtype(parse_globaltype(ctx)); break;
+        wasm_externtype_t *export_type = NULL;
+
+        switch (type) {
+            case 0x00: export_type = wasm_functype_as_externtype(wasm_module_index_functype(ctx->module, idx)); break;
+            case 0x01: export_type = wasm_tabletype_as_externtype(wasm_module_index_tabletype(ctx->module, idx)); break;
+            case 0x02: export_type = wasm_memorytype_as_externtype(wasm_module_index_memorytype(ctx->module, idx)); break;
+            case 0x03: export_type = wasm_globaltype_as_externtype(wasm_module_index_globaltype(ctx->module, idx)); break;
         }
 
         wasm_exporttype_t *export = wasm_exporttype_new(&export_name, export_type);
+        export->index = idx;
         ctx->module->exports.data[i] = export;
     }
 }
@@ -261,18 +264,18 @@ static void parse_elem_section(build_context *ctx) {
     unsigned int section_size = uleb128_to_uint(ctx->binary.data, &ctx->offset);
     unsigned int elem_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
 
-
     // This is going to be a mess...
     // I am only going to handle the case of a single, active, offset-0,
     // element entry. This is all that Onyx uses and will probably ever
     // use.
     assert(elem_count == 1);
-    assert(uleb128_to_uint(ctx->binary.data, &ctx->offset) == 0x00);
-    assert(uleb128_to_uint(ctx->binary.data, &ctx->offset) == 0x40);
-    assert(uleb128_to_uint(ctx->binary.data, &ctx->offset) == 0x00);
-    assert(uleb128_to_uint(ctx->binary.data, &ctx->offset) == 0x0B);
+    assert(CONSUME_BYTE(ctx) == 0x00);
+    assert(CONSUME_BYTE(ctx) == 0x41);
+    assert(CONSUME_BYTE(ctx) == 0x00);
+    assert(CONSUME_BYTE(ctx) == 0x0B);
 
     unsigned int entry_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+    ctx->module->elem_count = entry_count;
     ctx->module->elem_entries = malloc(sizeof(unsigned int) * entry_count);
 
     fori (i, 0, (int) entry_count) {
@@ -286,8 +289,49 @@ static void parse_code_section(build_context *ctx) {
     // TODO
 }
 
-static void parse_data_section(build_context *ctx) {}
-static void parse_data_count_section(build_context *ctx) {}
+static void parse_data_section(build_context *ctx) {
+    unsigned int section_size = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+    unsigned int data_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+
+    if (ctx->module->data_count_present) {
+        assert(ctx->module->data_count == data_count);
+    } else {
+        ctx->module->data_count = data_count;
+    }
+
+    ctx->module->data_entries = malloc(sizeof(struct wasm_data_t) * data_count);
+
+    fori (i, 0, (int) data_count) {
+        char data_type = CONSUME_BYTE(ctx);
+        assert(data_type == 0x00 || data_type == 0x01);
+
+        struct wasm_data_t data_entry;
+        data_entry.data = NULL;
+        data_entry.offset = 0;
+        data_entry.length = 0;
+        data_entry.passive = true;
+
+        if (data_type == 0x00) {
+            assert(CONSUME_BYTE(ctx) == 0x41);
+            data_entry.offset = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+            assert(CONSUME_BYTE(ctx) == 0x0B);
+        }
+
+        data_entry.length = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+        data_entry.data = bh_pointer_add(ctx->binary.data, ctx->offset);
+        ctx->offset += data_entry.length;
+
+        ctx->module->data_entries[i] = data_entry;
+    }
+}
+
+static void parse_data_count_section(build_context *ctx) {
+    unsigned int section_size = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+    unsigned int data_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+
+    ctx->module->data_count_present = true;
+    ctx->module->data_count = data_count;
+}
 
 static void parse_section(build_context *ctx) {
     char section_number = CONSUME_BYTE(ctx);
@@ -316,7 +360,7 @@ static bool module_build(wasm_module_t *module, const wasm_byte_vec_t *binary) {
 
     build_context ctx;
     ctx.binary  = *binary;
-    ctx.offset  = 0;
+    ctx.offset  = 8;  // Skip the magic bytes and version
     ctx.module  = module;
     ctx.program = module->program;
     ctx.store   = engine->store;
@@ -324,11 +368,39 @@ static bool module_build(wasm_module_t *module, const wasm_byte_vec_t *binary) {
     while (ctx.offset < binary->size) {
         parse_section(&ctx);
     }
+
+    module->program->register_count = module->globaltypes.size;
     
     return true;
 }
 
 
+#define WASM_MODULE_INDEX(k1, k2) \
+    wasm_##k1##type_t *wasm_module_index_##k1##type(wasm_module_t *module, int index) { \
+        fori (i, 0, (int) module->imports.size) { \
+            if (module->imports.data[i]->type->kind == k2) { \
+                if (index == 0) { \
+                    return wasm_externtype_as_##k1##type(module->imports.data[i]->type); \
+                } \
+     \
+                index -= 1; \
+            } \
+        } \
+     \
+        if (index < (int) module->k1##types.size) { \
+            return module->k1##types.data[index]; \
+        } \
+     \
+        return NULL; \
+    }
+
+WASM_MODULE_INDEX(func, WASM_EXTERN_FUNC)
+WASM_MODULE_INDEX(memory, WASM_EXTERN_MEMORY)
+WASM_MODULE_INDEX(table, WASM_EXTERN_TABLE)
+WASM_MODULE_INDEX(global, WASM_EXTERN_GLOBAL)
+
+#undef WASM_MODULE_INDEX
+
 
 // Ommitting the "sharable ref" crap that I don't think will
 // ever be needed for a module.
diff --git a/src/wasm_cli_test.c b/src/wasm_cli_test.c
new file mode 100644 (file)
index 0000000..8d2337d
--- /dev/null
@@ -0,0 +1,23 @@
+#include "onyx_wasm.h"
+
+
+int main(int argc, char *argv[]) {
+    wasm_config_t *config = wasm_config_new();
+    wasm_config_enable_debug(config, true);
+
+    wasm_engine_t *engine = wasm_engine_new_with_config(config);
+
+    wasm_store_t *store = wasm_store_new(engine);
+
+    wasm_byte_vec_t wasm_bytes;
+    {
+        bh_file_contents contents = bh_file_read_contents(bh_heap_allocator(), argv[1]);
+
+        wasm_bytes.size = contents.length;
+        wasm_bytes.data = contents.data;
+    }
+
+    wasm_module_t *module = wasm_module_new(store, &wasm_bytes);
+    assert(module);
+}
+
diff --git a/test.asm b/test.asm
deleted file mode 100644 (file)
index 27fc31e..0000000
--- a/test.asm
+++ /dev/null
@@ -1,62 +0,0 @@
-
-.native_func dummy 0
-.native_func print 1
-.native_func sin 1
-
-.register stack_ptr
-
-.func add 2
-    add.i32 %2, %0, %1
-    return.i32 %2
-
-.func count 1
-    imm.i32 %1, 1
-    imm.i32 %2, 5
-
-  loop:
-    param %0
-    native_call print
-    sub.i32 %0, %0, %1
-
-    eq.i32 %3, %0, %2
-    br_z loop, %3
-
-    // br skip
-    imm.i32 %1, 123
-    param %1
-    native_call print
-  skip:
-    return
-
-.func main 0
-    reg.get %10, stack_ptr
-
-    imm.i32 %0, 1
-    imm.i32 %1, 2
-    param %0
-    param %1
-    call.i32 %2, add
-    param %2
-    native_call print
-
-    imm.i32 %3, 10
-    param %3
-    call count
-
-    reg.set stack_ptr, %10
-    return
-
-.func sin_test 0
-    imm.f32 %0, 3.14159265f
-    imm.f32 %1, 0.5f
-    mul.f32 %2, %0, %1
-
-    param %2
-    native_call.f32 %3, sin
-
-    param %3
-    native_call print
-
-    return
-
-
diff --git a/tests/ovm/math.asm b/tests/ovm/math.asm
new file mode 100644 (file)
index 0000000..bacaf30
--- /dev/null
@@ -0,0 +1,14 @@
+
+
+.native_func print 1
+
+
+.func main 2
+    mov %2, %0
+    mov %3, %1
+    add.i32 %2, %2, %3
+    imm.i32 %3, 10
+    add.i32 %2, %2, %3
+    param %2
+    native_call print
+
diff --git a/tests/ovm/out.ovm b/tests/ovm/out.ovm
new file mode 100644 (file)
index 0000000..9f68090
Binary files /dev/null and b/tests/ovm/out.ovm differ
diff --git a/tests/ovm/test.asm b/tests/ovm/test.asm
new file mode 100644 (file)
index 0000000..27fc31e
--- /dev/null
@@ -0,0 +1,62 @@
+
+.native_func dummy 0
+.native_func print 1
+.native_func sin 1
+
+.register stack_ptr
+
+.func add 2
+    add.i32 %2, %0, %1
+    return.i32 %2
+
+.func count 1
+    imm.i32 %1, 1
+    imm.i32 %2, 5
+
+  loop:
+    param %0
+    native_call print
+    sub.i32 %0, %0, %1
+
+    eq.i32 %3, %0, %2
+    br_z loop, %3
+
+    // br skip
+    imm.i32 %1, 123
+    param %1
+    native_call print
+  skip:
+    return
+
+.func main 0
+    reg.get %10, stack_ptr
+
+    imm.i32 %0, 1
+    imm.i32 %1, 2
+    param %0
+    param %1
+    call.i32 %2, add
+    param %2
+    native_call print
+
+    imm.i32 %3, 10
+    param %3
+    call count
+
+    reg.set stack_ptr, %10
+    return
+
+.func sin_test 0
+    imm.f32 %0, 3.14159265f
+    imm.f32 %1, 0.5f
+    mul.f32 %2, %0, %1
+
+    param %2
+    native_call.f32 %3, sin
+
+    param %3
+    native_call print
+
+    return
+
+
diff --git a/tests/wasm/out.wasm b/tests/wasm/out.wasm
new file mode 100644 (file)
index 0000000..2678395
Binary files /dev/null and b/tests/wasm/out.wasm differ
diff --git a/tests/wasm/tiny.onyx b/tests/wasm/tiny.onyx
new file mode 100644 (file)
index 0000000..4b8d6ce
--- /dev/null
@@ -0,0 +1,15 @@
+
+f :: (a, b: i32) -> i32 {
+    return a + b;
+}
+
+g :: (x) => x + 1;
+
+#export "_start" () {
+    a := 10;
+    b := 20;
+    c := f(a, b);
+
+    z: (i32) -> i32 = g;
+    z(10);
+}
\ No newline at end of file