progress towards a completely running test suite
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 6 Jul 2022 15:03:58 +0000 (10:03 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 6 Jul 2022 15:03:58 +0000 (10:03 -0500)
build.sh
include/bh.h
include/onyx_wasm.h
include/vm.h
src/vm/vm.c
src/wasm/instance.c
src/wasm/module_parsing.c.incl
src/wasm/type.c

index e4095d852c2eba224e201e6293ee036675a9d936..160e4565e3a07b4bdb49c758614569f3f8208fcd 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -2,7 +2,7 @@
 
 CC="gcc"
 WARNINGS='-Wimplicit -Wmisleading-indentation -Wparentheses -Wsequence-point -Wreturn-type -Wshift-negative-value -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-function -Wunused-label -Wmaybe-uninitialized -Wsign-compare -Wstrict-overflow -Wduplicated-branches -Wduplicated-cond -Wtrigraphs -Waddress -Wlogical-op'
-FLAGS="-O3"
+FLAGS="-g3"
 LIBS="-pthread"
 INCLUDES="-I include"
 TARGET="libonyx_embedder.so"
index 498ef089139844269d25f43ba4c1a4f4d04a8e0e..55c940894bb0fbe798432a99de7924b1098ba6be 100644 (file)
@@ -27,6 +27,7 @@
     #include <fcntl.h>
     #include <unistd.h>
     #include <dirent.h>
+    #include <pthread.h>
 #endif
 
 #include <stdlib.h>
@@ -276,6 +277,26 @@ BH_DEF BH_ALLOCATOR_PROC(bh_arena_allocator_proc);
 
 
 
+// ATOMIC ARENA ALLOCATOR
+typedef struct bh_atomic_arena {
+    bh_allocator backing;
+    ptr first_arena, current_arena;
+    isize size, arena_size; // in bytes
+
+    pthread_mutex_t mutex;
+} bh_atomic_arena;
+
+typedef struct bh__atomic_arena_internal {
+    ptr next_arena;
+    void* data; // Not actually a pointer, just used for the offset
+} bh__atomic_arena_internal;
+
+BH_DEF void bh_atomic_arena_init(bh_atomic_arena* alloc, bh_allocator backing, isize arena_size);
+BH_DEF void bh_atomic_arena_free(bh_atomic_arena* alloc);
+BH_DEF bh_allocator bh_atomic_arena_allocator(bh_atomic_arena* alloc);
+BH_DEF BH_ALLOCATOR_PROC(bh_atomic_arena_allocator_proc);
+
+
 
 
 // SCRATCH ALLOCATOR
@@ -1101,6 +1122,95 @@ BH_DEF BH_ALLOCATOR_PROC(bh_arena_allocator_proc) {
 }
 
 
+// ATOMIC ARENA ALLOCATOR IMPLEMENTATION
+BH_DEF void bh_atomic_arena_init(bh_atomic_arena* alloc, bh_allocator backing, isize arena_size) {
+    arena_size = bh_max(arena_size, size_of(ptr));
+    ptr data = bh_alloc(backing, arena_size);
+
+    alloc->backing = backing;
+    alloc->arena_size = arena_size;
+    alloc->size = sizeof(ptr);
+    alloc->first_arena = data;
+    alloc->current_arena = data;
+    pthread_mutex_init(&alloc->mutex, NULL);
+
+    ((bh__arena_internal *)(alloc->first_arena))->next_arena = NULL;
+}
+
+BH_DEF void bh_atomic_arena_free(bh_atomic_arena* alloc) {
+    bh__atomic_arena_internal *walker = (bh__atomic_arena_internal *) alloc->first_arena;
+    bh__atomic_arena_internal *trailer = walker;
+    while (walker != NULL) {
+        walker = walker->next_arena;
+        bh_free(alloc->backing, trailer);
+        trailer = walker;
+    }
+
+    alloc->first_arena = NULL;
+    alloc->current_arena = NULL;
+    alloc->arena_size = 0;
+    alloc->size = 0;
+    pthread_mutex_destroy(&alloc->mutex);
+}
+
+BH_DEF bh_allocator bh_atomic_arena_allocator(bh_atomic_arena* alloc) {
+    return (bh_allocator) {
+        .proc = bh_atomic_arena_allocator_proc,
+        .data = alloc,
+    };
+}
+
+BH_DEF BH_ALLOCATOR_PROC(bh_atomic_arena_allocator_proc) {
+    bh_atomic_arena* alloc_arena = (bh_atomic_arena*) data;
+    pthread_mutex_lock(&alloc_arena->mutex);
+
+    ptr retval = NULL;
+
+    switch (action) {
+    case bh_allocator_action_alloc: {
+        bh_align(size, alignment);
+        bh_align(alloc_arena->size, alignment);
+
+        if (size > alloc_arena->arena_size - size_of(ptr)) {
+            // Size too large for the arena
+            break;
+        }
+
+        if (alloc_arena->size + size >= alloc_arena->arena_size) {
+            bh__arena_internal* new_arena = (bh__arena_internal *) bh_alloc(alloc_arena->backing, alloc_arena->arena_size);
+
+            if (new_arena == NULL) {
+                bh_printf_err("Arena Allocator: couldn't allocate new arena");
+                break;
+            }
+
+            new_arena->next_arena = NULL;
+            ((bh__arena_internal *)(alloc_arena->current_arena))->next_arena = new_arena;
+            alloc_arena->current_arena = new_arena;
+            alloc_arena->size = sizeof(ptr);
+        }
+
+        retval = bh_pointer_add(alloc_arena->current_arena, alloc_arena->size);
+        alloc_arena->size += size;
+    } break;
+
+    case bh_allocator_action_resize: {
+        // Do nothing since this is a fixed allocator
+    } break;
+
+    case bh_allocator_action_free: {
+        // Do nothing since this allocator isn't made for freeing memory
+    } break;
+    }
+
+    pthread_mutex_unlock(&alloc_arena->mutex);
+    return retval;
+}
+
+
+
+
+
 
 
 // SCRATCH ALLOCATOR IMPLEMENTATION
@@ -1294,7 +1404,7 @@ BH_DEF i64 leb128_to_int(u8* bytes, i32 *byte_count) {
     }
 
     if ((shift < size) && (byte & 0x40) != 0) {
-        return res | ((~0) << shift);
+        return res | ((~(u64) 0x0) << shift);
     }
     
     return res;
index f5258b49b9fea5caa1bfcf9cfe7a6649b9313ba2..a775dc7f5b84beee21af3de9e273e96ddac8c3e5 100644 (file)
@@ -202,6 +202,7 @@ struct wasm_instance_t {
 };
 
 
+bool wasm_functype_equals(wasm_functype_t *a, wasm_functype_t *b);
 
 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);
index b69260154333262912931bc8f16930ab05a04354..7583735eb04cb7f2f5f020df58b08c0dbc2c3048 100644 (file)
@@ -27,9 +27,9 @@ typedef struct ovm_static_integer_array_t ovm_static_integer_array_t;
 //
 // Contains storage.
 struct ovm_store_t {
-    bh_allocator heap_allocator;
-    bh_arena     arena;
-    bh_allocator arena_allocator;
+    bh_allocator    heap_allocator;
+    bh_atomic_arena arena;
+    bh_allocator    arena_allocator;
 };
 
 ovm_store_t *ovm_store_new();
@@ -180,7 +180,7 @@ void         ovm_func_delete(ovm_func_t *func);
 
 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);
+ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program);
 
 //
 // Instruction encoding
index 353e2eb5c9f9cc5f59018308382518cc7a459897..30fde47c5673dffb8cbaa63c49233f060bf12216 100644 (file)
@@ -23,14 +23,14 @@ ovm_store_t *ovm_store_new() {
 
     store->heap_allocator = bh_heap_allocator();
 
-    bh_arena_init(&store->arena, store->heap_allocator, 1 << 20);
-    store->arena_allocator = bh_arena_allocator(&store->arena);
+    bh_atomic_arena_init(&store->arena, store->heap_allocator, 1 << 20);
+    store->arena_allocator = bh_atomic_arena_allocator(&store->arena);
 
     return store;
 }
 
 void ovm_store_delete(ovm_store_t *store) {
-    bh_arena_free(&store->arena);
+    bh_atomic_arena_free(&store->arena);
     free(store);
 }
 
@@ -466,7 +466,7 @@ void ovm_engine_memory_copy(ovm_engine_t *engine, i64 target, void *data, i64 si
 // Should there be another mechanism for this? or is this the most concise way?
 ovm_state_t *ovm_state_new(ovm_engine_t *engine, ovm_program_t *program) {
     ovm_store_t *store = engine->store;
-    ovm_state_t *state = bh_alloc_item(store->heap_allocator, ovm_state_t);
+    ovm_state_t *state = bh_alloc_item(store->arena_allocator, ovm_state_t);
 
     state->store = store;
     state->pc = 0;
@@ -496,8 +496,6 @@ void ovm_state_delete(ovm_state_t *state) {
     bh_arr_free(state->stack_frames);
     bh_arr_free(state->registers);
     bh_arr_free(state->external_funcs);
-
-    bh_free(store->heap_allocator, state);
 }
 
 void ovm_state_register_external_func(ovm_state_t *state, i32 idx, void (*func)(void *, ovm_value_t *, ovm_value_t *), void *data) {
@@ -549,7 +547,12 @@ static inline ovm_stack_frame_t ovm__func_teardown_stack_frame(ovm_engine_t *eng
     ovm_stack_frame_t frame = bh_arr_pop(state->stack_frames);
     bh_arr_fastdeleten(state->numbered_values, frame.value_number_count);
 
-    state->value_number_offset = bh_arr_last(state->stack_frames).value_number_base;
+    if (bh_arr_length(state->stack_frames) == 0) {
+        state->value_number_offset = 0;
+    } else {
+        state->value_number_offset = bh_arr_last(state->stack_frames).value_number_base;
+    }
+
     return frame;
 }
 
@@ -559,9 +562,6 @@ ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_
 
     switch (func.kind) {
         case OVM_FUNC_INTERNAL: {
-            bh_arr_insert_end(state->numbered_values, 1);
-            state->value_number_offset += 1;
-
             ovm__func_setup_stack_frame(engine, state, program, func_idx, 0);
 
             fori (i, 0, param_count) {
@@ -569,10 +569,9 @@ ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_
             }
 
             state->pc = func.start_instr;
-            ovm_run_code(engine, state, program);
+            ovm_value_t result = ovm_run_code(engine, state, program);
 
-            state->value_number_offset -= 1;
-            return bh_arr_pop(state->numbered_values);
+            return result;
         }
 
         case OVM_FUNC_EXTERNAL: {
@@ -580,8 +579,7 @@ ovm_value_t ovm_func_call(ovm_engine_t *engine, ovm_state_t *state, ovm_program_
 
             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_fastdeleten(state->params, func.param_count);
+            external_func.native_func(external_func.userdata, params, &result);
 
             ovm__func_teardown_stack_frame(engine, state, program);
             return result;
@@ -634,7 +632,7 @@ static inline double __ovm_copysign(a, b) double a, b; {
 }
 
 
-void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program) {
+ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *program) {
     assert(engine);
     assert(state);
     assert(program);
@@ -722,25 +720,25 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr
             OVM_OP(OVMI_REM_S, OVM_TYPE_I32, %, i32)
             OVM_OP(OVMI_REM_S, OVM_TYPE_I64, %, i64)
 
-            OVM_OP(OVMI_AND, OVM_TYPE_I8 , &, i8)
-            OVM_OP(OVMI_AND, OVM_TYPE_I16, &, i16)
-            OVM_OP(OVMI_AND, OVM_TYPE_I32, &, i32)
-            OVM_OP(OVMI_AND, OVM_TYPE_I64, &, i64)
+            OVM_OP(OVMI_AND, OVM_TYPE_I8 , &, u8)
+            OVM_OP(OVMI_AND, OVM_TYPE_I16, &, u16)
+            OVM_OP(OVMI_AND, OVM_TYPE_I32, &, u32)
+            OVM_OP(OVMI_AND, OVM_TYPE_I64, &, u64)
 
-            OVM_OP(OVMI_OR, OVM_TYPE_I8 , |, i8)
-            OVM_OP(OVMI_OR, OVM_TYPE_I16, |, i16)
-            OVM_OP(OVMI_OR, OVM_TYPE_I32, |, i32)
-            OVM_OP(OVMI_OR, OVM_TYPE_I64, |, i64)
+            OVM_OP(OVMI_OR, OVM_TYPE_I8 , |, u8)
+            OVM_OP(OVMI_OR, OVM_TYPE_I16, |, u16)
+            OVM_OP(OVMI_OR, OVM_TYPE_I32, |, u32)
+            OVM_OP(OVMI_OR, OVM_TYPE_I64, |, u64)
 
-            OVM_OP(OVMI_XOR, OVM_TYPE_I8 , ^, i8)
-            OVM_OP(OVMI_XOR, OVM_TYPE_I16, ^, i16)
-            OVM_OP(OVMI_XOR, OVM_TYPE_I32, ^, i32)
-            OVM_OP(OVMI_XOR, OVM_TYPE_I64, ^, i64)
+            OVM_OP(OVMI_XOR, OVM_TYPE_I8 , ^, u8)
+            OVM_OP(OVMI_XOR, OVM_TYPE_I16, ^, u16)
+            OVM_OP(OVMI_XOR, OVM_TYPE_I32, ^, u32)
+            OVM_OP(OVMI_XOR, OVM_TYPE_I64, ^, u64)
 
-            OVM_OP(OVMI_SHL, OVM_TYPE_I8 , <<, i8)
-            OVM_OP(OVMI_SHL, OVM_TYPE_I16, <<, i16)
-            OVM_OP(OVMI_SHL, OVM_TYPE_I32, <<, i32)
-            OVM_OP(OVMI_SHL, OVM_TYPE_I64, <<, i64)
+            OVM_OP(OVMI_SHL, OVM_TYPE_I8 , <<, u8)
+            OVM_OP(OVMI_SHL, OVM_TYPE_I16, <<, u16)
+            OVM_OP(OVMI_SHL, OVM_TYPE_I32, <<, u32)
+            OVM_OP(OVMI_SHL, OVM_TYPE_I64, <<, u64)
 
             OVM_OP(OVMI_SHR, OVM_TYPE_I8 , >>, u8)
             OVM_OP(OVMI_SHR, OVM_TYPE_I16, >>, u16)
@@ -975,12 +973,12 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr
             }
 
             case OVMI_REG_GET: {
-                VAL(instr.r) = ovm_state_register_get(state, instr.a);
+                VAL(instr.r) = state->registers[instr.a];
                 break;
             }
 
             case OVMI_REG_SET: {
-                ovm_state_register_set(state, instr.r, VAL(instr.a));
+                state->registers[instr.r] = VAL(instr.a);
                 break;
             }
 
@@ -999,17 +997,17 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr
                 ovm_value_t val = VAL(instr.a);
                 ovm_stack_frame_t frame = ovm__func_teardown_stack_frame(engine, state, program); 
 
-                if (frame.return_number_value >= 0) {
-                    VAL(frame.return_number_value) = val;
-                }
-
                 if (bh_arr_length(state->stack_frames) == 0) {
-                    return;
+                    return val;
                 }
 
                 ovm_func_t *new_func = bh_arr_last(state->stack_frames).func;
                 if (new_func->kind == OVM_FUNC_EXTERNAL) {
-                    return;
+                    return val;
+                }
+
+                if (frame.return_number_value >= 0) {
+                    VAL(frame.return_number_value) = val;
                 }
 
                 // printf("Returning from %s to %s: ", frame.func->name, bh_arr_last(state->stack_frames).func->name); 
@@ -1023,10 +1021,10 @@ 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_t *func = &program->funcs[fidx]; \
+            i32 extra_params = bh_arr_length(state->params) - func->param_count; \
             if (func->kind == OVM_FUNC_INTERNAL) { \
                 ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \
  \
-                i32 extra_params = bh_arr_length(state->params) - func->param_count; \
                 fori (i, 0, func->param_count) { \
                     VAL(i) = state->params[i + extra_params]; \
                 } \
@@ -1034,13 +1032,11 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr
  \
                 state->pc = func->start_instr; \
             } else { \
-                ovm__func_setup_stack_frame(engine, state, program, fidx, 0); \
- \
-                i32 extra_params = bh_arr_length(state->params) - func->param_count; \
+                ovm__func_setup_stack_frame(engine, state, program, fidx, instr.r); \
  \
                 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 + extra_params, &result); \
+                external_func.native_func(external_func.userdata, &state->params[extra_params], &result); \
                 bh_arr_fastdeleten(state->params, func->param_count); \
  \
                 ovm__func_teardown_stack_frame(engine, state, program); \
@@ -1178,5 +1174,7 @@ void ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t *progr
             release_mutex_at_end = false;
         }
     }
+
+    return ((ovm_value_t) {0});
 }
 
index 0f5ebcdc6096dfe01cbe974d5e296f83b91d32d0..3300a7f475b829377296af2ee6cab93a061d2a9f 100644 (file)
@@ -77,6 +77,10 @@ struct ovm_wasm_binding {
             (w).kind = WASM_F64; \
             (w).of.f64 = (o).f64; \
             break; \
+ \
+        default: \
+            printf("INVALID: %d\n", (o).type); \
+            assert(("invalid ovm value type for conversion", 0)); \
     } }
 
 static wasm_trap_t *wasm_to_ovm_func_call_binding(void *vbinding, const wasm_val_vec_t *args, wasm_val_vec_t *res) {
@@ -106,14 +110,18 @@ static void ovm_to_wasm_func_call_binding(void *env, ovm_value_t* params, ovm_va
         OVM_TO_WASM(params[i], wasm_params.data[i]);
     }
 
+    wasm_val_t return_value;
     wasm_val_vec_t wasm_results;
-    wasm_results.data = alloca(sizeof(wasm_val_t) * binding->result_count);
+    wasm_results.data = &return_value;
     wasm_results.size = binding->result_count;
 
     wasm_trap_t *trap = wasm_func_call(binding->func, &wasm_params, &wasm_results);
     assert(!trap);
 
-    if (binding->result_count > 0) WASM_TO_OVM(wasm_results.data[0], *res);
+    if (binding->result_count > 0) {
+        assert(wasm_results.data[0].kind == binding->func->inner.type->func.results.data[0]->kind);
+        WASM_TO_OVM(return_value, *res);
+    }
 }
 
 static void wasm_memory_init(void *env, ovm_value_t* params, ovm_value_t *res) {
@@ -136,14 +144,20 @@ static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t
     //
     // Place imports in their corresponding "bucket"
     fori (i, 0, (int) imports->size) {
+        assert(instance->module->imports.data[i]->type->kind == imports->data[i]->type->kind);
+
         switch (wasm_extern_kind(imports->data[i])) {
             case WASM_EXTERN_FUNC: {
-                wasm_func_t *func = wasm_extern_as_func(imports->data[i]);
-                bh_arr_push(instance->funcs, func);
-
                 wasm_importtype_t *importtype = instance->module->imports.data[i];
                 struct wasm_functype_inner_t *functype = &importtype->type->func;
 
+                if (!wasm_functype_equals(wasm_externtype_as_functype(importtype->type), wasm_externtype_as_functype(imports->data[i]->type))) {
+                    assert(("MISMATCHED FUNCTION TYPE", 0));
+                }
+
+                wasm_func_t *func = wasm_extern_as_func(imports->data[i]);
+                bh_arr_push(instance->funcs, func);
+
                 ovm_wasm_binding *binding = bh_alloc(ovm_store->arena_allocator, sizeof(*binding));
                 binding->param_count  = functype->params.size;
                 binding->result_count = functype->results.size;
@@ -287,7 +301,7 @@ static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t
 wasm_instance_t *wasm_instance_new(wasm_store_t *store, const wasm_module_t *module,
     const wasm_extern_vec_t *imports, wasm_trap_t **trap) {
 
-    wasm_instance_t *instance = bh_alloc(store->engine->store->arena_allocator, sizeof(*instance));
+    wasm_instance_t *instance = bh_alloc(store->engine->store->heap_allocator, sizeof(*instance));
     instance->store = store;
     instance->module = module;
 
@@ -317,6 +331,7 @@ void wasm_instance_delete(wasm_instance_t *instance) {
 
     wasm_extern_vec_delete(&instance->exports);
     ovm_state_delete(instance->state);
+    bh_free(instance->store->engine->store->heap_allocator, instance);
 }
 
 void wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) {
index 48af61b62beac35746a3ebdc26c150de6f10b549..2b095480c4f49277c12f18a6a65002d6d005f897 100644 (file)
@@ -143,7 +143,7 @@ static void parse_import_section(build_context *ctx) {
         wasm_byte_vec_new_uninitialized(&import_name, import_name_size);
         fori (n, 0, import_name_size) import_name.data[n] = CONSUME_BYTE(ctx);
 
-        wasm_externtype_t *import_type;
+        wasm_externtype_t *import_type = NULL;
         switch (CONSUME_BYTE(ctx)) {
             case 0x00: {
                 unsigned int type_idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
index 37fa859a484a96f368ce466d9be3a96f75faf643..ba3449740d9e218da6d734993eca387df992c1b1 100644 (file)
@@ -66,6 +66,21 @@ const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t *functype)
     return &functype->type.func.results;
 }
 
+bool wasm_functype_equals(wasm_functype_t *a, wasm_functype_t *b) {
+    if (a->type.func.params.size != b->type.func.params.size) return false;
+    if (a->type.func.results.size != b->type.func.results.size) return false;
+
+    fori (i, 0, (int) a->type.func.params.size) {
+        if (a->type.func.params.data[i]->kind != b->type.func.params.data[i]->kind) return false;
+    }
+
+    fori (i, 0, (int) a->type.func.results.size) {
+        if (a->type.func.results.data[i]->kind != b->type.func.results.data[i]->kind) return false;
+    }
+
+    return true;
+}
+
 WASM_DECLARE_VEC_IMPL(functype, *)