$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
struct wasm_exporttype_t {
wasm_name_t *name;
wasm_externtype_t *type;
+ int index;
};
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;
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;
};
};
+
+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; \
} \
\
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) { \
+++ /dev/null
-
-
-.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
-
+++ /dev/null
-#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;
-}
--- /dev/null
+#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;
+}
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;
}
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];
}
}
}
}
+ assert(CONSUME_BYTE(ctx) == 0x0b);
+
ctx->module->globaltypes.data[i] = gt;
}
}
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;
}
}
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) {
// 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);
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;
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.
--- /dev/null
+#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);
+}
+
+++ /dev/null
-
-.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
-
-
--- /dev/null
+
+
+.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
+
--- /dev/null
+
+.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
+
+
--- /dev/null
+
+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