wasm_name_t module_name;
wasm_name_t import_name;
wasm_externtype_t *type;
+
+ //
+ // This is only used by imported functions
+ // to specify which slot the function binding
+ // should be placed. When making a functype by
+ // hand, this proably will never be used.
+ int external_func_idx;
};
struct wasm_exporttype_t {
};
struct wasm_trap_t {
+ wasm_message_t msg;
};
struct wasm_foreign_t {
ovm_program_t *program;
bool valid;
+
+ int memory_init_idx;
+ int memory_init_external_idx;
};
struct wasm_func_inner_t {
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);
+int ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count);
+int 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);
void ovm_program_modify_static_int(ovm_program_t *program, int arr, int idx, int new_value);
void ovm_state_delete(ovm_state_t *state);
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);
+void ovm_state_register_set(ovm_state_t *state, i32 idx, ovm_value_t val);
//
//
i32 start_instr;
i32 func_table_arr_idx;
- i32 next_external_func_idx;
i32 highest_value_number;
};
}
static void ovm_code_builder_add_params(ovm_code_builder_t *builder, i32 param_count) {
+ i32 *flipped_params = alloca(param_count * sizeof(i32));
+
+ fori (i, 0, param_count) {
+ flipped_params[i] = POP_VALUE(builder);
+ }
+
fori (i, 0, param_count) {
ovm_instr_t param_instr = {0};
param_instr.full_instr = OVMI_PARAM;
- param_instr.a = POP_VALUE(builder);
+ param_instr.a = flipped_params[param_count - 1 - i];
ovm_program_add_instructions(builder->program, 1, ¶m_instr);
}
// add.i32 %n, %n, %i
instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32);
instrs[1].r = instrs[0].r;
- instrs[1].a = instrs[0].r;
- instrs[1].b = POP_VALUE(builder);
+ instrs[1].a = POP_VALUE(builder);
+ instrs[1].b = instrs[0].r;
// load.x %m, %n
instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_LOAD, ovm_type);
}
ovm_instr_t instrs[3] = {0};
- instrs[2].b = POP_VALUE(builder);
+
+ // TODO: explain the ordering here.
// imm.i32 %n, offset
instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32);
instrs[0].i = offset;
instrs[0].r = NEXT_VALUE(builder);
+ instrs[2].b = POP_VALUE(builder);
+
// add.i32 %n, %n, %i
instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32);
instrs[1].r = instrs[0].r;
- instrs[1].a = instrs[0].r;
- instrs[1].b = POP_VALUE(builder);
+ instrs[1].a = POP_VALUE(builder);
+ instrs[1].b = instrs[0].r;
// store.x %m, %n
instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_STORE, ovm_type);
PUSH_VALUE(builder, cmpxchg_instr.r);
return;
}
+
+ // TODO: explain the ordering here.
ovm_instr_t instrs[3] = {0};
- int value_reg = POP_VALUE(builder);
- int expected_reg = POP_VALUE(builder);
- int addr_reg = POP_VALUE(builder);
-
// imm.i32 %n, offset
instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32);
instrs[0].i = offset;
instrs[0].r = NEXT_VALUE(builder);
+ int value_reg = POP_VALUE(builder);
+ int expected_reg = POP_VALUE(builder);
+ int addr_reg = POP_VALUE(builder);
+
// add.i32 %n, %n, %i
instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32);
instrs[1].r = instrs[0].r;
- instrs[1].a = instrs[0].r;
- instrs[1].b = addr_reg;
+ instrs[1].a = addr_reg;
+ instrs[1].b = instrs[0].r;
// cmpxchg.x %m, %n
instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, ovm_type);
program->store = store;
program->register_count = 0;
+ program->funcs = NULL;
+ program->code = NULL;
+ program->static_integers = NULL;
+ program->static_data = NULL;
bh_arr_new(store->heap_allocator, program->funcs, 16);
bh_arr_new(store->heap_allocator, program->code, 1024);
+ bh_arr_new(store->heap_allocator, program->static_integers, 128);
+ bh_arr_new(store->heap_allocator, program->static_data, 128);
return program;
}
void ovm_program_delete(ovm_program_t *program) {
bh_arr_free(program->funcs);
bh_arr_free(program->code);
+ bh_arr_free(program->static_integers);
+ bh_arr_free(program->static_data);
bh_free(program->store->heap_allocator, program);
}
program->static_integers[array.start_idx + idx] = new_value;
}
-void ovm_program_register_func(ovm_program_t *program, char *name, i32 instr, i32 param_count, i32 value_number_count) {
+int 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.value_number_count = value_number_count;
bh_arr_push(program->funcs, func);
+ return func.id;
}
-void ovm_program_register_external_func(ovm_program_t *program, char *name, i32 param_count, i32 external_func_idx) {
+int 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.external_func_idx = external_func_idx;
bh_arr_push(program->funcs, func);
+ return func.id;
}
void ovm_program_begin_func(ovm_program_t *program, char *name, i32 param_count, i32 value_number_count) {
}
void ovm_program_print_instructions(ovm_program_t *program, i32 start_instr, i32 instr_count) {
- fori (i, start_instr, instr_count) {
+ fori (i, start_instr, start_instr + instr_count) {
//
// 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
}
ovm_instr_t instr = program->code[i];
- printf("%50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d);
+ printf("%6lx %50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", i, ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d);
}
}
void ovm_raw_print_instructions(i32 instr_count, ovm_instr_t *instrs) {
fori (i, 0, instr_count) {
ovm_instr_t instr = instrs[i];
- printf("%50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d);
+ printf("%6lx %50s | r=%02d a=%02d b=%02d i=%d f=%f l=%ld d=%lf\n", i, ovm_instr_name(instr.full_instr), instr.r, instr.a, instr.b, instr.i, instr.f, instr.l, instr.d);
}
}
engine->store = store;
engine->memory_size = 1ull << 32;
- engine->memory = mmap(NULL, engine->memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ engine->memory = mmap(NULL, engine->memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ pthread_mutex_init(&engine->atomic_mutex, NULL);
return engine;
}
state->pc = 0;
state->value_number_offset = 0;
+ state->numbered_values = NULL;
+ state->params = NULL;
+ state->stack_frames = NULL;
+ state->registers = NULL;
bh_arr_new(store->heap_allocator, state->numbered_values, 64);
bh_arr_new(store->heap_allocator, state->params, 16);
bh_arr_new(store->heap_allocator, state->stack_frames, 32);
bh_arr_new(store->heap_allocator, state->registers, program->register_count);
bh_arr_insert_end(state->registers, program->register_count);
+ state->external_funcs = NULL;
bh_arr_new(store->heap_allocator, state->external_funcs, 8);
return state;
bh_arr_set_at(state->external_funcs, idx, external_func);
}
+void ovm_state_register_set(ovm_state_t *state, i32 idx, ovm_value_t val) {
+ if (idx >= bh_arr_length(state->registers)) return;
+
+ state->registers[idx] = val;
+}
//
// Function calling
bool release_mutex_at_end = false;
while (state->pc < bh_arr_length(program->code)) {
+ ovm_program_print_instructions(program, state->pc, 1);
+
//
// Incrementing the program counter here.
// All instructions that compute something relative
#define OVM_LOAD(type_, stype) \
case OVM_TYPED_INSTR(OVMI_LOAD, type_): \
+ assert(VAL(instr.a).type == OVM_TYPE_I32); \
VAL(instr.r).type = type_; \
VAL(instr.r).stype = * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32]; \
break;
#define OVM_STORE(type_, stype) \
case OVM_TYPED_INSTR(OVMI_STORE, type_): \
+ assert(VAL(instr.a).type == OVM_TYPE_I32); \
* (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32] = VAL(instr.b).stype; \
break;
ovm_value_t val = VAL(instr.a);
bh_arr_fastdeleten(state->numbered_values, frame.value_number_count);
+ if (bh_arr_length(state->stack_frames) == 0) {
+ state->value_number_offset = 0;
+ VAL(frame.return_number_value) = val;
+ return;
+ }
+
state->value_number_offset = bh_arr_last(state->stack_frames).value_number_base;
if (frame.return_number_value >= 0) {
VAL(frame.return_number_value) = val;
#define CMPXCHG(otype, ctype) \
- case OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_CMPXCHG, otype): \
- if (VAL(instr.r).ctype == VAL(instr.a).ctype) { \
- VAL(instr.r).ctype = VAL(instr.b).ctype ; \
+ case OVM_TYPED_INSTR(OVMI_CMPXCHG, otype): {\
+ ctype *addr = (ctype *) &((u8 *) engine->memory)[VAL(instr.r).i32]; \
+ if (*addr == VAL(instr.a).ctype) { \
+ *addr = VAL(instr.b).ctype ; \
} \
- break;
+ VAL(instr.r).type = otype; \
+ VAL(instr.r).ctype = *addr; \
+ break; \
+ }
CMPXCHG(OVM_TYPE_I8, i8)
CMPXCHG(OVM_TYPE_I16, i16)
ovm_program_t *program;
};
+typedef struct ovm_wasm_binding ovm_wasm_binding;
+struct ovm_wasm_binding {
+ int param_count;
+ int result_count;
+ wasm_func_t *func;
+};
+
+#define WASM_TO_OVM(w, o) \
+ switch ((w).kind) { \
+ case WASM_I32: \
+ (o).type = OVM_TYPE_I32; \
+ (o).i32 = (w).of.i32; \
+ break; \
+ \
+ case WASM_I64: \
+ (o).type = OVM_TYPE_I64; \
+ (o).i64 = (w).of.i64; \
+ break; \
+ \
+ case WASM_F32: \
+ (o).type = OVM_TYPE_F32; \
+ (o).f32 = (w).of.f32; \
+ break; \
+ \
+ case WASM_F64: \
+ (o).type = OVM_TYPE_F64; \
+ (o).f64 = (w).of.f64; \
+ break; \
+ \
+ default: assert(("invalid wasm value type for conversion", 0)); \
+ }
+
+#define OVM_TO_WASM(o, w) \
+ switch ((o).type) { \
+ case OVM_TYPE_I8: \
+ (w).kind = WASM_I32; \
+ (w).of.i32 = (i32) (o).i8; \
+ break; \
+ \
+ case OVM_TYPE_I16: \
+ (w).kind = WASM_I32; \
+ (w).of.i32 = (i32) (o).i16; \
+ break; \
+ \
+ case OVM_TYPE_I32: \
+ (w).kind = WASM_I32; \
+ (w).of.i32 = (i32) (o).i32; \
+ break; \
+ \
+ case OVM_TYPE_I64: \
+ (w).kind = WASM_I64; \
+ (w).of.i64 = (o).i64; \
+ break; \
+ \
+ case OVM_TYPE_F32: \
+ (w).kind = WASM_F32; \
+ (w).of.f32 = (o).f32; \
+ break; \
+ \
+ case OVM_TYPE_F64: \
+ (w).kind = WASM_F64; \
+ (w).of.f64 = (o).f64; \
+ break; \
+ }
+
static wasm_trap_t *wasm_to_ovm_func_call_binding(void *vbinding, const wasm_val_vec_t *args, wasm_val_vec_t *res) {
wasm_ovm_binding *binding = (wasm_ovm_binding *) vbinding;
ovm_value_t *vals = alloca(sizeof(*vals) * args->size);
fori (i, 0, (int) args->size) {
- switch (args->data[i].kind) {
- case WASM_I32:
- vals[i].type = OVM_TYPE_I32;
- vals[i].i32 = args->data[i].of.i32;
- break;
+ WASM_TO_OVM(args->data[i], vals[i]);
+ }
- case WASM_I64:
- vals[i].type = OVM_TYPE_I64;
- vals[i].i64 = args->data[i].of.i64;
- break;
+ ovm_value_t ovm_res = ovm_func_call(binding->engine, binding->state, binding->program, binding->func_idx, args->size, vals);
+ if (!res || res->size == 0) return NULL;
- case WASM_F32:
- vals[i].type = OVM_TYPE_F32;
- vals[i].f32 = args->data[i].of.f32;
- break;
+ OVM_TO_WASM(ovm_res, res->data[0]);
- case WASM_F64:
- vals[i].type = OVM_TYPE_F64;
- vals[i].f64 = args->data[i].of.f64;
- break;
+ return NULL;
+}
- default: assert(("invalid wasm value type for conversion", 0));
- }
- }
+static void ovm_to_wasm_func_call_binding(void *env, ovm_value_t* params, ovm_value_t *res) {
+ ovm_wasm_binding *binding = (ovm_wasm_binding *) env;
- ovm_value_t ovm_res = ovm_func_call(binding->engine, binding->state, binding->program, binding->func_idx, args->size, vals);
- if (!res || res->size == 0) return NULL;
+ wasm_val_vec_t wasm_params;
+ wasm_params.data = alloca(sizeof(wasm_val_t) * binding->param_count);
+ wasm_params.size = binding->param_count;
- switch (ovm_res.type) {
- case OVM_TYPE_I8:
- res->data[0].kind = WASM_I32;
- res->data[0].of.i32 = (i32) ovm_res.i8;
- break;
-
- case OVM_TYPE_I16:
- res->data[0].kind = WASM_I32;
- res->data[0].of.i32 = (i32) ovm_res.i16;
- break;
-
- case OVM_TYPE_I32:
- res->data[0].kind = WASM_I32;
- res->data[0].of.i32 = (i32) ovm_res.i32;
- break;
-
- case OVM_TYPE_I64:
- res->data[0].kind = WASM_I64;
- res->data[0].of.i64 = ovm_res.i64;
- break;
-
- case OVM_TYPE_F32:
- res->data[0].kind = WASM_F32;
- res->data[0].of.f32 = ovm_res.f32;
- break;
-
- case OVM_TYPE_F64:
- res->data[0].kind = WASM_F64;
- res->data[0].of.f64 = ovm_res.f64;
- break;
+ fori (i, 0, binding->param_count) {
+ OVM_TO_WASM(params[i], wasm_params.data[i]);
}
- return NULL;
+ // asm("int $3");
+
+ wasm_val_vec_t wasm_results;
+ wasm_results.data = alloca(sizeof(wasm_val_t) * binding->result_count);
+ 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);
+}
+
+static void wasm_memory_init(void *env, ovm_value_t* params, ovm_value_t *res) {
+ wasm_instance_t *instr = (wasm_instance_t *) env;
+
+ assert(params[0].type == OVM_TYPE_I32);
+ assert(params[1].type == OVM_TYPE_I32);
+ assert(params[2].type == OVM_TYPE_I32);
+ assert(params[3].type == OVM_TYPE_I32);
+
+ // if (params[0].i32 == 63) asm("int $3");
+
+ printf("Initializing data from: %p\n", instr->module->data_entries[params[3].i32].data);
+ ovm_engine_memory_copy(instr->store->engine->engine, params[0].i32, instr->module->data_entries[params[3].i32].data, params[2].i32);
}
static void prepare_instance(wasm_instance_t *instance, const wasm_extern_vec_t *imports) {
+ ovm_store_t *ovm_store = instance->store->engine->store;
+ ovm_engine_t *ovm_engine = instance->store->engine->engine;
+ ovm_state_t *ovm_state = instance->state;
+ ovm_program_t *ovm_program = instance->module->program;
+
//
// Place imports in their corresponding "bucket"
fori (i, 0, (int) imports->size) {
switch (wasm_extern_kind(imports->data[i])) {
- case WASM_EXTERN_FUNC:
- bh_arr_push(instance->funcs, wasm_extern_as_func(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;
+
+ ovm_wasm_binding *binding = bh_alloc(ovm_store->arena_allocator, sizeof(*binding));
+ binding->param_count = functype->params.size;
+ binding->result_count = functype->results.size;
+ binding->func = func;
+
+ ovm_state_register_external_func(ovm_state, importtype->external_func_idx, ovm_to_wasm_func_call_binding, binding);
break;
+ }
- case WASM_EXTERN_MEMORY:
- bh_arr_push(instance->memories, wasm_extern_as_memory(imports->data[i]));
+ case WASM_EXTERN_MEMORY: {
+ wasm_memory_t *memory = wasm_extern_as_memory(imports->data[i]);
+ bh_arr_push(instance->memories, memory);
+
+ memory->inner.memory.engine = ovm_engine;
break;
+ }
+
+ case WASM_EXTERN_GLOBAL: {
+ wasm_global_t *global = wasm_extern_as_global(imports->data[i]);
+
+ global->inner.global.engine = ovm_engine;
+ global->inner.global.state = ovm_state;
+ global->inner.global.register_index = bh_arr_length(instance->globals);
- case WASM_EXTERN_GLOBAL:
- bh_arr_push(instance->globals, wasm_extern_as_global(imports->data[i]));
+ ovm_value_t val = {0};
+ WASM_TO_OVM(global->inner.global.initial_value, val);
+ ovm_state_register_set(ovm_state, global->inner.global.register_index, val);
+
+ bh_arr_push(instance->globals, global);
break;
+ }
+
+ case WASM_EXTERN_TABLE: {
+ wasm_table_t *table = wasm_extern_as_table(imports->data[i]);
+ table->inner.table.engine = ovm_engine;
+ table->inner.table.program = ovm_program;
+ table->inner.table.static_arr = instance->module->imports.data[i]->type->table.static_arr;
- case WASM_EXTERN_TABLE:
- bh_arr_push(instance->tables, wasm_extern_as_table(imports->data[i]));
+ bh_arr_push(instance->tables, table);
break;
+ }
}
}
+ ovm_state_register_external_func(ovm_state, instance->module->memory_init_external_idx, wasm_memory_init, instance);
+
//
// Create function objects
fori (i, 0, (int) instance->module->functypes.size) {
wasm_ovm_binding *binding = bh_alloc(instance->store->engine->store->arena_allocator, sizeof(*binding));
- binding->engine = instance->store->engine->engine;
+ binding->engine = ovm_engine;
binding->func_idx = bh_arr_length(instance->funcs);
- binding->program = instance->module->program;
- binding->state = instance->state;
+ binding->program = ovm_program;
+ binding->state = ovm_state;
wasm_func_t *func = wasm_func_new_with_env(instance->store, instance->module->functypes.data[i],
wasm_to_ovm_func_call_binding, binding, NULL);
// Create memory objects
fori (i, 0, (int) instance->module->memorytypes.size) {
wasm_memory_t *memory = wasm_memory_new(instance->store, instance->module->memorytypes.data[i]);
- memory->inner.memory.engine = instance->store->engine->engine;
+ memory->inner.memory.engine = ovm_engine;
bh_arr_push(instance->memories, memory);
}
// Create table objects
fori (i, 0, (int) instance->module->tabletypes.size) {
wasm_table_t *table = wasm_table_new(instance->store, instance->module->tabletypes.data[i], NULL);
- table->inner.table.engine = instance->store->engine->engine;
- table->inner.table.program = instance->module->program;
+ table->inner.table.engine = ovm_engine;
+ table->inner.table.program = ovm_program;
table->inner.table.static_arr = instance->module->tabletypes.data[i]->type.table.static_arr;
bh_arr_push(instance->tables, table);
fori (i, 0, (int) instance->module->globaltypes.size) {
wasm_global_t *global = wasm_global_new(instance->store, instance->module->globaltypes.data[i],
&instance->module->globaltypes.data[i]->type.global.initial_value);
- global->inner.global.engine = instance->store->engine->engine;
- global->inner.global.state = instance->state;
+
+ global->inner.global.engine = ovm_engine;
+ global->inner.global.state = ovm_state;
global->inner.global.register_index = bh_arr_length(instance->globals);
+ ovm_value_t val = {0};
+ WASM_TO_OVM(global->inner.global.initial_value, val);
+ ovm_state_register_set(ovm_state, global->inner.global.register_index, val);
+
bh_arr_push(instance->globals, global);
}
struct wasm_data_t *datum = &instance->module->data_entries[i];
if (datum->passive) continue;
- ovm_engine_memory_copy(instance->store->engine->engine, datum->offset, datum->data, datum->length);
+ ovm_engine_memory_copy(ovm_engine, datum->offset, datum->data, datum->length);
+ }
+
+ wasm_extern_vec_new_uninitialized(&instance->exports, instance->module->exports.size);
+ fori (i, 0, (int) instance->module->exports.size) {
+ wasm_exporttype_t *externtype = instance->module->exports.data[i];
+
+ switch (externtype->type->kind) {
+ case WASM_EXTERN_FUNC: {
+ wasm_func_t *func = instance->funcs[externtype->index];
+ instance->exports.data[i] = wasm_func_as_extern(func);
+ break;
+ }
+
+ case WASM_EXTERN_MEMORY: {
+ wasm_memory_t *memory = instance->memories[externtype->index];
+ instance->exports.data[i] = wasm_memory_as_extern(memory);
+ break;
+ }
+
+ case WASM_EXTERN_GLOBAL: {
+ wasm_global_t *global = instance->globals[externtype->index];
+ instance->exports.data[i] = wasm_global_as_extern(global);
+ break;
+ }
+
+ case WASM_EXTERN_TABLE: {
+ wasm_table_t *table = instance->tables[externtype->index];
+ instance->exports.data[i] = wasm_table_as_extern(table);
+ break;
+ }
+ }
}
}
bh_arr_new(store->engine->store->heap_allocator, instance->globals, module->globaltypes.size);
instance->state = ovm_state_new(store->engine->engine, module->program);
-
- // TODO
- instance->exports.size = 0;
- instance->exports.data = NULL;
prepare_instance(instance, imports);
return instance;
}
+void wasm_instance_delete(wasm_instance_t *instance) {
+ bh_arr_free(instance->funcs);
+ bh_arr_free(instance->memories);
+ bh_arr_free(instance->globals);
+ bh_arr_free(instance->tables);
+
+ wasm_extern_vec_delete(&instance->exports);
+ ovm_state_delete(instance->state);
+}
+
+void wasm_instance_exports(const wasm_instance_t *instance, wasm_extern_vec_t *out) {
+ *out = instance->exports;
+}
ctx.module = module;
ctx.program = module->program;
ctx.store = engine->store;
+ ctx.next_external_func_idx = 0;
while (ctx.offset < binary->size) {
parse_section(&ctx);
// TODO: This is not correct when the module imports a global.
// But Onyx does not do this, so I don't care at the moment.
module->program->register_count = module->globaltypes.size;
-
+
return true;
}
return module;
}
+void wasm_module_delete(wasm_module_t *module) {
+ ovm_program_delete(module->program);
+}
+
bool wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary) {
// Hmmm...
return false;
ovm_store_t *store;
int func_table_arr_idx;
+ int next_external_func_idx;
// This will be set/reset for every code (function) entry.
ovm_code_builder_t builder;
module_name.data, module_name.size,
import_name.data, import_name.size);
- int external_func_idx = ctx->builder.next_external_func_idx++;
+ int external_func_idx = ctx->next_external_func_idx++;
+ import->external_func_idx = external_func_idx;
ovm_program_register_external_func(ctx->program, external_func_name, import_type->func.params.size, external_func_idx);
}
int dataidx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
assert(CONSUME_BYTE(ctx) == 0x00);
- ovm_code_builder_drop_value(&ctx->builder);
- ovm_code_builder_drop_value(&ctx->builder);
- ovm_code_builder_drop_value(&ctx->builder);
-
- // TODO: MEMORY INIT INSTRUCTION
+ ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &dataidx);
+ ovm_code_builder_add_call(&ctx->builder, ctx->module->memory_init_idx, 4, false);
break;
}
int entry_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
int *entries = bh_alloc_array(bh_heap_allocator(), int, entry_count);
+
+ int label_stack_count = bh_arr_length(ctx->builder.label_stack);
fori (i, 0, entry_count) {
- entries[i] = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+ entries[i] = ctx->builder.label_stack[label_stack_count - 1 - uleb128_to_uint(ctx->binary.data, &ctx->offset)].idx;
}
int default_entry = uleb128_to_uint(ctx->binary.data, &ctx->offset);
case 0x3F: {
assert(CONSUME_BYTE(ctx) == 0x00);
- int memory_size = 65536;
+ int memory_size = 65535;
ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &memory_size);
break;
}
case 0x40: {
assert(CONSUME_BYTE(ctx) == 0x00);
+ ovm_code_builder_drop_value(&ctx->builder);
+
+ int value = -1;
+ ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &value);
break;
}
unsigned int code_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
assert(ctx->module->functypes.size == code_count);
+ ctx->module->memory_init_external_idx = ctx->next_external_func_idx++;
+
+ // HACK HACK HACK THIS IS SUCH A BAD WAY OF DOING THIS
+ ctx->module->memory_init_idx = bh_arr_length(ctx->program->funcs) + code_count;
+
fori (i, 0, (int) code_count) {
unsigned int code_size = uleb128_to_uint(ctx->binary.data, &ctx->offset);
unsigned int local_sections_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
ovm_program_register_func(ctx->program, func_name, ctx->builder.start_instr, ctx->builder.param_count, ctx->builder.highest_value_number + 1);
ovm_code_builder_free(&ctx->builder);
}
+
+ ovm_program_register_external_func(ctx->program, "__internal_wasm_memory_init", 4, ctx->module->memory_init_external_idx);
}
}
void wasm_store_delete(wasm_store_t *store) {
- free(store);
}
-// TODO
+#include "onyx_wasm.h"
+#include "vm.h"
+
+wasm_trap_t *wasm_trap_new(wasm_store_t *store, const wasm_message_t *msg) {
+ wasm_trap_t *trap = bh_alloc(store->engine->store->arena_allocator, sizeof(*trap));
+ trap->msg = *msg;
+
+ return trap;
+}
+
+void wasm_trap_message(const wasm_trap_t *trap, wasm_message_t *out) {
+ *out = trap->msg;
+}
+
+wasm_frame_t *wasm_trap_origin(const wasm_trap_t *trap) {
+ return NULL;
+}
+
+void wasm_trap_trace(const wasm_trap_t *trap, wasm_frame_vec_t *frames) {
+ frames->size = 0;
+ frames->data = NULL;
+}