From: Brendan Hansen Date: Wed, 22 Jun 2022 03:13:14 +0000 (-0500) Subject: closer to converting wasm -> ovm X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2a97c8906ae7e2ffb8da49205564cb3bf9c4250b;p=onyx-embedder.git closer to converting wasm -> ovm --- diff --git a/build.sh b/build.sh index cea3591..8ebf101 100755 --- 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 diff --git a/include/onyx_wasm.h b/include/onyx_wasm.h index 971b68f..b93dc65 100644 --- a/include/onyx_wasm.h +++ b/include/onyx_wasm.h @@ -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 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 index 330685e..0000000 --- a/src/cli.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "vm.h" - -#include - -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 index 0000000..330685e --- /dev/null +++ b/src/ovm_cli_test.c @@ -0,0 +1,50 @@ +#include "vm.h" + +#include + +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/wasm/module.c b/src/wasm/module.c index c42f910..84c6f70 100644 --- a/src/wasm/module.c +++ b/src/wasm/module.c @@ -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 index 0000000..8d2337d --- /dev/null +++ b/src/wasm_cli_test.c @@ -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 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 index 0000000..bacaf30 --- /dev/null +++ b/tests/ovm/math.asm @@ -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 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 index 0000000..27fc31e --- /dev/null +++ b/tests/ovm/test.asm @@ -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 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 index 0000000..4b8d6ce --- /dev/null +++ b/tests/wasm/tiny.onyx @@ -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