protoverse

A metaverse protocol
git clone git://jb55.com/protoverse
Log | Files | Refs | README | LICENSE

commit d403d6c74134e0b1fac6bfe5c4dc8fd44ef529ac
parent bd10754520fbf6254303bf1624047d24a59cadc3
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 19 Jul 2021 14:26:55 -0700

initial module instance

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/cursor.h | 9---------
Msrc/wasm.c | 292++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/wasm.h | 29++++++++++++++++++++---------
3 files changed, 152 insertions(+), 178 deletions(-)

diff --git a/src/cursor.h b/src/cursor.h @@ -47,15 +47,6 @@ static inline void make_array(struct array *a, u8* start, u8 *end, unsigned int a->elem_size = elem_size; } -static inline unsigned char *array_index(struct array *a, int ind) -{ - u8 *p = a->cur.start + a->elem_size * ind; - if (unlikely(p >= a->cur.end)) { - return NULL; - } - return p; -} - static inline int cursor_eof(struct cursor *c) { return c->p == c->end; diff --git a/src/wasm.c b/src/wasm.c @@ -149,36 +149,6 @@ static INLINE int cursor_pop_i32(struct cursor *stack, int *i) return 1; } -static INLINE int is_number_type(enum valtype vt) -{ - switch (vt) { - case val_i32: - case val_i64: - case val_f32: - case val_f64: - return 1; - case val_ref_null: - case val_ref_func: - case val_ref_extern: - return 0; - } - - return 0; -} - -static INLINE int cursor_pop_number(struct cursor *stack, struct val *val) -{ - if (unlikely(!cursor_popval(stack, val))) { - return 0; - } - - if (unlikely(!is_number_type(val->type))) { - return 0; - } - - return 1; -} - static INLINE int stack_pop_i32(struct wasm_interp *interp, int *i) { return cursor_pop_i32(&interp->stack, i); @@ -204,16 +174,11 @@ static INLINE int stack_pop_valtype(struct wasm_interp *interp, return cursor_pop_valtype(&interp->stack, type, val); } -static INLINE int stack_pop_number(struct wasm_interp *interp, struct val *val) -{ - return cursor_pop_number(&interp->stack, val); -} - static void print_val(struct val *val) { switch (val->type) { case val_i32: printf("%d", val->num.i32); break; - case val_i64: printf("%lu", val->num.i64); break; + case val_i64: printf("%llu", val->num.i64); break; case val_f32: printf("%f", val->num.f32); break; case val_f64: printf("%f", val->num.f64); break; @@ -1508,6 +1473,7 @@ static INLINE void make_const_expr_parser(struct wasm_parser *p, parser->errs = &p->errs; } +/* static INLINE int eval_const_expr(struct expr *expr, struct errors *errs, struct cursor *stack) { @@ -1520,6 +1486,8 @@ static INLINE int eval_const_expr(struct expr *expr, struct errors *errs, return parse_const_expr(&parser, &expr_out); } +*/ + static int parse_global(struct wasm_parser *p, struct global *global) @@ -2160,11 +2128,6 @@ static int parse_section(struct wasm_parser *p) return 1; } -static INLINE int functions_count(struct module *module) -{ - return module->num_funcs; -} - static struct builtin *builtin_func(int ind) { if (unlikely(ind < 0 || ind >= NUM_BUILTINS)) { @@ -2424,32 +2387,6 @@ static INLINE void make_i32_val(struct val *val, int v) val->num.i32 = v; } -static INLINE int interp_gt(struct wasm_interp *interp, enum valtype vt, int sign) -{ - struct val lhs, rhs, c; - (void)sign; - - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, vt))) { - return interp_error(interp, "gt_u prep"); - } - - switch (vt) { - case val_i32: - c.num.i32 = sign? (signed int)lhs.num.i32 > (signed int)rhs.num.i32 - : (unsigned int)lhs.num.i32 > (unsigned int)rhs.num.i32; - break; - case val_i64: - c.num.i64 = sign? (int64_t)lhs.num.i64 > (int64_t)rhs.num.i64 - : (uint64_t)lhs.num.i64 > (uint64_t)rhs.num.i64; - break; - default: - return interp_error(interp, "todo: interp_gt %s", - valtype_name(vt)); - } - - return stack_pushval(interp, &c); -} - static INLINE int interp_i32_lt_s(struct wasm_interp *interp) { struct val lhs, rhs, c; @@ -2566,7 +2503,7 @@ static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *f static INLINE int call_builtin_func(struct wasm_interp *interp, struct builtin *builtin, int fn) { - struct callframe callframe = {0}; + struct callframe callframe = {}; /* update current function and push it to the callframe as well */ callframe.fn = fn; @@ -2739,9 +2676,10 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect return interp_error(interp, "no table section"); } - if (unlikely(call->tableidx >= interp->num_tables)) { + if (unlikely(call->tableidx >= interp->module_inst.num_tables)) { return interp_error(interp, "invalid table index %d (max %d)", - call->tableidx, interp->num_tables-1); + call->tableidx, + interp->module_inst.num_tables-1); } if (unlikely(call->typeidx >= @@ -2751,7 +2689,7 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect interp->module->type_section.num_functypes); } - table = &interp->tables[call->tableidx]; + table = &interp->module_inst.tables[call->tableidx]; type = &interp->module->type_section.functypes[call->typeidx]; if (unlikely(table->reftype != funcref)) { @@ -2827,9 +2765,9 @@ static int parse_blocktype(struct cursor *cur, struct errors *errs, struct block return 1; } -static INLINE struct label *index_label(struct array *a, int fn, int ind) +static INLINE struct label *index_label(struct cursor *a, int fn, int ind) { - return (struct label*)array_index(a, (MAX_LABELS * fn) + ind); + return index_cursor(a, ((MAX_LABELS * fn) + ind), sizeof(struct label)); } static INLINE u32 label_instr_pos(struct label *label) @@ -2924,7 +2862,7 @@ static int pop_label_checkpoint(struct wasm_interp *interp) static INLINE u16 *func_num_labels(struct wasm_interp *interp, int fn) { - u16 *num = (u16*)array_index(&interp->num_labels, fn); + u16 *num = index_cursor(&interp->num_labels, fn, sizeof(u16)); assert(num); assert(*num <= MAX_LABELS); return num; @@ -2941,7 +2879,7 @@ static int find_label(struct wasm_interp *interp, int fn, u32 instr_pos) return interp_error(interp, "index label"); for (i = 0; i < *num_labels; label++) { - assert((u8*)label < interp->labels.cur.end); + assert((u8*)label < interp->labels.end); if (label_instr_pos(label) == instr_pos) return i; i++; @@ -3019,7 +2957,7 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe *label = NULL; - fns = functions_count(interp->module); + fns = interp->module->num_funcs; frame = top_callframe(&interp->callframes); if (unlikely(!frame)) { @@ -3078,11 +3016,6 @@ static int interp_jump(struct wasm_interp *interp, int jmp) return 1; } -static INLINE int jump_to_label(struct wasm_interp *interp, struct label *label) -{ - return interp_jump(interp, label->jump); -} - static int pop_label_and_jump(struct wasm_interp *interp, struct label *label, int times) { int i; @@ -3585,21 +3518,19 @@ static INLINE int interp_br_if(struct wasm_interp *interp, int ind) static INLINE u8 *global_init_state(struct wasm_interp *interp, int ind) { - u8 *p; - - if (unlikely(!(p = index_cursor(&interp->global_init, ind, 1)))) { + if (ind >= interp->module_inst.num_globals) { interp_error(interp, "global ind %d oob", ind); return NULL; } - return p; + return &interp->module_inst.globals_init[ind]; } static struct val *get_global(struct wasm_interp *interp, int ind) { struct globalsec *globsec; struct global *global; - struct val *val; + struct global_inst *global_inst; u8 *init; if (unlikely(!was_section_parsed(interp->module, section_global))) { @@ -3610,13 +3541,14 @@ static struct val *get_global(struct wasm_interp *interp, int ind) globsec = &interp->module->global_section; - if (unlikely(!(val = index_cursor(&interp->globals, ind, sizeof(*val))))) { - interp_error(interp, - "invalid global index %d (max %d)", - ind, globsec->num_globals-1); + if (unlikely(ind >= interp->module_inst.num_globals)) { + interp_error(interp, "invalid global index %d (max %d)", ind, + globsec->num_globals-1); return NULL; } + global_inst = &interp->module_inst.globals[ind]; + if (unlikely(!(init = global_init_state(interp, ind)))) { interp_error(interp, "couldn't get global init state for global %d", ind); @@ -3625,18 +3557,18 @@ static struct val *get_global(struct wasm_interp *interp, int ind) /* global is already initialized, return it */ if (*init == 1) { - return val; + return &global_inst->val; } /* initialize global then return it */ global = &interp->module->global_section.globals[ind]; /* copy initialized global from module to global instance */ - memcpy(val, &global->val, sizeof(*val)); + memcpy(&global_inst->val, &global->val, sizeof(global_inst->val)); *init = 1; - return val; + return &global_inst->val; } static int interp_global_get(struct wasm_interp *interp, int ind) @@ -3933,6 +3865,7 @@ static int interp_i32_shl(struct wasm_interp *interp) return stack_pushval(interp, &c); } +#ifdef DEBUG static void print_linestack(struct cursor *stack) { struct val *val; @@ -4183,6 +4116,7 @@ static const char *show_instr(struct instr *instr) cursor_push_byte(&buf, 0); return buffer; } +#endif static int interp_extend(struct wasm_interp *interp, enum valtype to, enum valtype from, int sign) @@ -4405,9 +4339,8 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, // if we hit the end of a loop, continue at the start if (resolver && resolver->start_tag == i_loop) { - if (unlikely(!(label = - index_label(&interp->labels, frame->fn, - resolver->label)))) { + if (unlikely(!(label = index_label(&interp->labels, frame->fn, + resolver->label)))) { return interp_error(interp, "no loop label?"); } @@ -4494,11 +4427,6 @@ static int find_start_function(struct module *module) return find_function(module, "_start"); } -static INLINE int array_alloc(struct cursor *mem, struct array *a, int elems) -{ - return cursor_slice(mem, &a->cur, elems * a->elem_size); -} - void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t arena_size) { u8 *mem; @@ -4529,19 +4457,6 @@ static int count_fn_locals(struct func *func) return num_locals; } -static int calculate_locals_size(struct module *module) -{ - int i, locals_size = 0; - struct func *func; - - for (i = 0; i < module->num_funcs; i++) { - func = &module->funcs[i]; - locals_size += count_fn_locals(func) * sizeof(struct val); - } - - return locals_size; -} - static int calculate_tables_size(struct module *module) { int i, num_tables, size; @@ -4565,15 +4480,18 @@ static int alloc_tables(struct wasm_interp *interp) struct table_inst *inst; int i; - interp->num_tables = interp->module->table_section.num_tables; - if (!(interp->tables = cursor_alloc(&interp->mem, interp->num_tables * - sizeof(struct table_inst)))) { + interp->module_inst.num_tables = + interp->module->table_section.num_tables; + + if (!(interp->module_inst.tables = + cursor_alloc(&interp->mem, interp->module_inst.num_tables * + sizeof(struct table_inst)))) { return interp_error(interp, "couldn't alloc table instances"); } - for (i = 0; i < interp->num_tables; i++) { + for (i = 0; i < interp->module_inst.num_tables; i++) { t = &interp->module->table_section.tables[i]; - inst = &(interp->tables[i]); + inst = &interp->module_inst.tables[i]; inst->reftype = t->reftype; inst->num_refs = t->limits.min; size = sizeof(struct refval) * t->limits.min; @@ -4587,10 +4505,26 @@ static int alloc_tables(struct wasm_interp *interp) return 1; } + +static int calculate_locals_size(struct module *module) +{ + int i, locals_size = 0; + struct func *func; + + for (i = 0; i < module->num_funcs; i++) { + func = &module->funcs[i]; + locals_size += count_fn_locals(func) * sizeof(struct val); + } + + debug("locals size %d\n", locals_size); + + return locals_size; +} + static int alloc_locals(struct module *module, struct cursor *mem, struct errors *errs) { - int i, num_locals; + int i, num_locals, size; struct func *func; for (i = 0; i < module->num_funcs; i++) { @@ -4600,7 +4534,9 @@ static int alloc_locals(struct module *module, struct cursor *mem, func->locals = (struct local*)mem->p; func->num_locals = num_locals; - if (!cursor_alloc(mem, num_locals * sizeof(struct val))) { + size = num_locals * sizeof(struct val); + + if (!cursor_alloc(mem, size)) { return note_error(errs, mem, "could not alloc locals for %s", func->name); @@ -4612,9 +4548,9 @@ static int alloc_locals(struct module *module, struct cursor *mem, int wasm_interp_init(struct wasm_interp *interp, struct module *module) { - unsigned char *mem, *heap; + unsigned char *mem, *heap, *start; - unsigned int ok, fns, errors_size, stack_size, locals_size, offsets_size, + unsigned int ok, fns, errors_size, stack_size, locals_size, callframes_size, resolver_size, labels_size, num_labels_size, labels_capacity, num_labels_elemsize, memsize, memory_pages_size, resolver_offsets_size, num_mems, globals_size, num_globals, @@ -4624,11 +4560,13 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module) interp->quitting = 0; interp->module = module; - interp->module->start_fn = -1; + + interp->module_inst.start_fn = -1; + interp->prev_resolvers = 0; //stack = calloc(1, STACK_SPACE); - fns = functions_count(module); + fns = module->num_funcs; labels_capacity = fns * MAX_LABELS; num_labels_elemsize = sizeof(u16); @@ -4642,41 +4580,37 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module) errors_size = 0xFFF; stack_size = sizeof(struct val) * 0xFF; labels_size = labels_capacity * sizeof(struct label); - num_labels_size = fns * num_labels_elemsize; - locals_size = sizeof(struct val) * 0xFF; - offsets_size = sizeof(int) * 0xFF; - resolver_offsets_size = offsets_size; + num_labels_size = fns * sizeof(u16); + resolver_offsets_size = sizeof(int) * 0xFF; callframes_size = sizeof(struct callframe) * 0xFF; resolver_size = sizeof(struct resolver) * MAX_LABELS; - globals_size = sizeof(struct val) * num_globals; + globals_size = sizeof(struct global_inst) * num_globals; + global_init_size = num_globals; locals_size = calculate_locals_size(module); tables_size = calculate_tables_size(module); - global_init_size = num_globals; if (num_mems > 1) { printf("more than one memory instance is not supported\n"); return 0; } - interp->labels.elem_size = sizeof(struct label); - interp->num_labels.elem_size = num_labels_elemsize; + interp->module_inst.num_globals = num_globals; memory_pages_size = 256 * WASM_PAGE_SIZE; memsize = - errors_size + stack_size + - labels_size + - num_labels_size + - locals_size + - offsets_size + + errors_size + resolver_offsets_size + + resolver_size + callframes_size + globals_size + global_init_size + + labels_size + + num_labels_size + locals_size + - tables_size + - resolver_size; + tables_size + ; mem = calloc(1, memsize); heap = malloc(memory_pages_size); @@ -4687,19 +4621,50 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module) // enable error reporting by default interp->errors.enabled = 1; - ok = - cursor_slice(&interp->mem, &interp->stack, stack_size) && - cursor_slice(&interp->mem, &interp->errors.cur, errors_size) && - cursor_slice(&interp->mem, &interp->resolver_offsets, resolver_offsets_size) && - cursor_slice(&interp->mem, &interp->callframes, callframes_size) && - cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size) && - cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size) && - cursor_slice(&interp->mem, &interp->globals, globals_size) && - cursor_slice(&interp->mem, &interp->global_init, global_init_size) && - array_alloc(&interp->mem, &interp->labels, labels_capacity) && - array_alloc(&interp->mem, &interp->num_labels, fns) && - alloc_tables(interp) && - alloc_locals(interp->module, &interp->mem, &interp->errors); + start = interp->mem.p; + + ok = cursor_slice(&interp->mem, &interp->stack, stack_size); + assert(interp->mem.p - start == stack_size); + + start = interp->mem.p; + ok = ok && cursor_slice(&interp->mem, &interp->errors.cur, errors_size); + assert(interp->mem.p - start == errors_size); + + start = interp->mem.p; + ok = ok && cursor_slice(&interp->mem, &interp->resolver_offsets, resolver_offsets_size); + assert(interp->mem.p - start == resolver_offsets_size); + + start = interp->mem.p; + ok = ok && cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size); + assert(interp->mem.p - start == resolver_size); + + start = interp->mem.p; + ok = ok && cursor_slice(&interp->mem, &interp->callframes, callframes_size); + assert(interp->mem.p - start == callframes_size); + + start = interp->mem.p; + ok = ok && (interp->module_inst.globals = cursor_alloc(&interp->mem, globals_size)); + assert(interp->mem.p - start == globals_size); + + start = interp->mem.p; + ok = ok && (interp->module_inst.globals_init = cursor_alloc(&interp->mem, num_globals)); + assert(interp->mem.p - start == num_globals); + + start = interp->mem.p; + ok = ok && cursor_slice(&interp->mem, &interp->labels, labels_size); + assert(interp->mem.p - start == labels_size); + + start = interp->mem.p; + ok = ok && cursor_slice(&interp->mem, &interp->num_labels, num_labels_size); + assert(interp->mem.p - start == num_labels_size); + + start = interp->mem.p; + ok = ok && alloc_tables(interp); + assert(interp->mem.p - start == tables_size); + + start = interp->mem.p; + ok = ok && alloc_locals(interp->module, &interp->mem, &interp->errors); + assert(interp->mem.p - start == locals_size); /* init memory pages */ assert((interp->mem.end - interp->mem.start) == memsize); @@ -4791,20 +4756,25 @@ int interp_wasm_module(struct wasm_interp *interp) if (!reset_memory(interp)) return interp_error(interp, "reset memory"); - wipe_cursor(&interp->globals); - wipe_cursor(&interp->global_init); + memset(interp->module_inst.globals, 0, + interp->module_inst.num_globals * + sizeof(*interp->module_inst.globals)); + + memset(interp->module_inst.globals_init, 0, + interp->module_inst.num_globals); // don't reset labels for perf! //interp->mem.p = interp->mem.start; - func = interp->module->start_fn != -1 ? interp->module->start_fn : - find_start_function(interp->module); + func = interp->module_inst.start_fn != -1 + ? interp->module_inst.start_fn + : find_start_function(interp->module); if (func == -1) { return interp_error(interp, "no start function found"); } else { - interp->module->start_fn = func; + interp->module_inst.start_fn = func; } debug("found start function %s (%d)\n", @@ -4829,7 +4799,6 @@ int run_wasm(unsigned char *wasm, unsigned long len) { struct wasm_parser p; struct wasm_interp interp; - int ok; wasm_parser_init(&p, wasm, len, len * 16); @@ -4842,11 +4811,14 @@ int run_wasm(unsigned char *wasm, unsigned long len) print_error_backtrace(&interp.errors); return 0; } + if (!interp_wasm_module(&interp)) { print_error_backtrace(&interp.errors); } + print_stack(&interp.stack); wasm_interp_free(&interp); wasm_parser_free(&p); - return ok; + + return 1; } diff --git a/src/wasm.h b/src/wasm.h @@ -550,10 +550,8 @@ struct module { unsigned int parsed; unsigned int custom_sections; - // this is a faster lookup than searching though imports/exports struct func *funcs; int num_funcs; - int start_fn; struct customsec custom_section[MAX_CUSTOM_SECTIONS]; struct typesec type_section; @@ -586,8 +584,26 @@ struct resolver { u8 start_tag; }; +struct global_inst { + struct val val; +}; + +struct module_inst { + struct table_inst *tables; + int num_tables; + + struct global_inst *globals; + unsigned char *globals_init; + int num_globals; + + + int start_fn; +}; + struct wasm_interp { struct module *module; + struct module_inst module_inst; + int prev_resolvers, quitting; struct errors errors; /* struct error */ @@ -597,16 +613,11 @@ struct wasm_interp { struct cursor stack; /* struct val */ struct cursor mem; /* u8/mixed */ struct cursor resolver_offsets; /* int */ - struct cursor globals; /* struct val */ - struct cursor global_init; /* u8 */ - - struct table_inst *tables; - int num_tables; struct cursor memory; /* memory pages (65536 blocks) */ - struct array labels; /* struct labels */ - struct array num_labels; + struct cursor labels; /* struct labels */ + struct cursor num_labels; // resolve stack for the current function. every time a control // instruction is encountered, the label index is pushed. When an