protoverse

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

commit e669c2d69908ffea1de08f9da01abe041b28fe62
parent a0686835b5209e4ec4b3b4a5856f4859229edba9
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 20 Jul 2021 14:42:35 -0700

hello-c executes to end, but is still broken

Diffstat:
Msrc/cursor.h | 15+++++++++++----
Msrc/wasm.c | 307++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/wasm.h | 9++++++++-
3 files changed, 238 insertions(+), 93 deletions(-)

diff --git a/src/cursor.h b/src/cursor.h @@ -166,17 +166,24 @@ static inline int pull_data_into_cursor(struct cursor *cursor, return 1; } - -static inline int cursor_drop(struct cursor *cur, int len) +static inline int cursor_dropn(struct cursor *cur, int size, int n) { - if (unlikely(cur->p - len < cur->start)) { + if (n == 0) + return 1; + + if (unlikely(cur->p - size*n < cur->start)) { return 0; } - cur->p -= len; + cur->p -= size*n; return 1; } +static inline int cursor_drop(struct cursor *cur, int size) +{ + return cursor_dropn(cur, size, 1); +} + static inline unsigned char *cursor_top(struct cursor *cur, int len) { if (unlikely(cur->p - len < cur->start)) { diff --git a/src/wasm.c b/src/wasm.c @@ -26,6 +26,8 @@ static const int MAX_LABELS = 128; +static int interp_code(struct wasm_interp *interp); + struct expr_parser { struct wasm_interp *interp; // optional... struct cursor *code; @@ -566,6 +568,7 @@ static char *instr_name(enum instr_tag tag) case i_table_op: return "table_op"; case i_table_get: return "table_get"; case i_table_set: return "table_set"; + case i_selects: return "selects"; } snprintf(unk, sizeof(unk), "0x%02x", tag); @@ -581,14 +584,15 @@ static INLINE int was_section_parsed(struct module *module, return module->parsed & (1 << section); } - static INLINE int cursor_push_callframe(struct cursor *cur, struct callframe *frame) { + //debug("pushing callframe %d fn:%d\n", ++callframe_cnt, frame->fn); return cursor_push(cur, (u8*)frame, sizeof(*frame)); } static INLINE int cursor_drop_callframe(struct cursor *cur) { + //debug("dropping callframe %d fn:%d\n", callframe_cnt--, top_callframe(cur)->fn); return cursor_drop(cur, sizeof(struct callframe)); } @@ -613,10 +617,10 @@ void print_error_backtrace(struct errors *errors) while (errs.p < errors->cur.p) { if (!cursor_pull_error(&errs, &err)) { - fprintf(stderr, "backtrace: couldn't pull error\n"); + printf("backtrace: couldn't pull error\n"); return; } - fprintf(stderr, "%08x:%s\n", err.pos, err.msg); + printf("%08x:%s\n", err.pos, err.msg); } } @@ -1442,7 +1446,6 @@ static int cursor_push_nullval(struct cursor *stack) return cursor_pushval(stack, &val); } -#ifdef DEBUG static const char *show_instr(struct instr *instr) { struct cursor buf; @@ -1526,6 +1529,9 @@ static const char *show_instr(struct instr *instr) cursor_push_str(&buf, tmp); break; + case i_selects: + break; + case i_br_table: break; @@ -1685,7 +1691,6 @@ static const char *show_instr(struct instr *instr) cursor_push_byte(&buf, 0); return buffer; } -#endif static int eval_const_instr(struct instr *instr, struct errors *errs, struct cursor *stack) @@ -2836,6 +2841,39 @@ static struct functype *get_function_type(struct wasm_interp *interp, int ind) return interp->module->funcs[ind].functype; } +static INLINE int count_local_resolvers(struct wasm_interp *interp, int *count) +{ + int offset; + u8 *p; + *count = 0; + if (unlikely(!cursor_top_int(&interp->resolver_offsets, &offset))) { + return interp_error(interp, "no top resolver offset?"); + } + p = interp->resolver_stack.start + offset * sizeof(struct resolver); + if (unlikely(p < interp->resolver_stack.start || + p >= interp->resolver_stack.end)) { + return interp_error(interp, "resolver offset oob?"); + } + *count = (interp->resolver_stack.p - p) / sizeof(struct resolver); + return 1; +} + +static INLINE int drop_callframe(struct wasm_interp *interp) +{ + int count, offset; + + if (!count_local_resolvers(interp, &count) != 0) { + return interp_error(interp, "unclean callframe drop, still have" + " %d unpopped labels", count); + } + + if (!cursor_popint(&interp->resolver_offsets, &offset)) { + return interp_error(interp, "pop resolver_offsets"); + } + + return cursor_drop_callframe(&interp->callframes); +} + static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *func, int fn) { struct callframe callframe; @@ -2844,12 +2882,24 @@ static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *f make_cursor(func->code.code, func->code.code + func->code.code_len, &callframe.code); callframe.fn = fn; + assert(func->code.code_len > 0); + if (unlikely(!cursor_push_callframe(&interp->callframes, &callframe))) return interp_error(interp, "oob cursor_pushcode"); + if (unlikely(!interp_code(interp))) { + return interp_error(interp, "call %s:%d", + get_function_name(interp->module, fn), + fn); + } + + if (unlikely(!drop_callframe(interp))) + return interp_error(interp, "drop callframe"); + return 1; } + static INLINE int call_builtin_func(struct wasm_interp *interp, struct builtin *builtin, int fn) { struct callframe callframe = {}; @@ -2864,7 +2914,10 @@ static INLINE int call_builtin_func(struct wasm_interp *interp, struct builtin * if (!builtin->fn(interp)) return interp_error(interp, "builtin trap"); - return cursor_drop_callframe(&interp->callframes); + if (unlikely(!drop_callframe(interp))) + return interp_error(interp, "pop callframe"); + + return 1; } static INLINE int call_func(struct wasm_interp *interp, struct func *func, int fn) @@ -2888,23 +2941,7 @@ static INLINE int count_resolvers(struct wasm_interp *interp) return cursor_count(&interp->resolver_stack, sizeof(struct resolver)); } -static INLINE int count_local_resolvers(struct wasm_interp *interp, int *count) -{ - int offset; - u8 *p; - if (unlikely(!cursor_top_int(&interp->resolver_offsets, &offset))) { - return interp_error(interp, "no top resolver offset?"); - } - p = interp->resolver_stack.start + offset * sizeof(struct resolver); - if (unlikely(p < interp->resolver_stack.start || - p >= interp->resolver_stack.end)) { - return interp_error(interp, "resolver offset oob?"); - } - *count = (interp->resolver_stack.p - p) / sizeof(struct resolver); - return 1; -} - -static int prepare_call(struct wasm_interp *interp, int func_index) +static int call_function(struct wasm_interp *interp, int func_index) { static char buf[128]; int i; @@ -2978,35 +3015,24 @@ static int prepare_call(struct wasm_interp *interp, int func_index) return 1; } -static int interp_code(struct wasm_interp *interp); - static int interp_call(struct wasm_interp *interp, int func_index) { #ifdef DEBUG - struct callframe *prev_frame; + struct callframe prev_frame; - prev_frame = top_callframe(&interp->callframes); + assert(top_callframe(&interp->callframes)); + memcpy(&prev_frame, top_callframe(&interp->callframes), sizeof(struct callframe)); #endif - if (unlikely(!prepare_call(interp, func_index))) { - interp_error(interp, "prepare"); - return 0; + if (unlikely(!call_function(interp, func_index))) { + return interp_error(interp, "prepare"); } - if (unlikely(!interp_code(interp))) { - return interp_error(interp, "call %s:%d", - get_function_name(interp->module, func_index), - func_index); - } - - if (unlikely(!cursor_drop_callframe(&interp->callframes))) - return interp_error(interp, "pop callframe"); - debug("returning from %s:%d to %s:%d\n", get_function_name(interp->module, func_index), func_index, - prev_frame ? get_function_name(interp->module, prev_frame->fn) : "", - prev_frame ? prev_frame->fn : -1); + get_function_name(interp->module, prev_frame.fn), + prev_frame.fn); return 1; } @@ -3085,6 +3111,10 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect ref, interp->module->num_funcs-1); } + debug("calling %s:%d indirectly", + get_function_name(interp->module, ref->addr), + ref->addr); + return interp_call(interp, ref->addr); } @@ -3161,14 +3191,17 @@ static INLINE int resolve_label(struct label *label, struct cursor *code) static INLINE int pop_resolver(struct wasm_interp *interp, struct resolver *resolver) { + /* #ifdef DEBUG int num_resolvers; #endif +*/ if (!cursor_pop(&interp->resolver_stack, (u8*)resolver, sizeof(*resolver))) { return interp_error(interp, "pop resolver"); } + /* #ifdef DEBUG if (unlikely(!count_local_resolvers(interp, &num_resolvers))) { return interp_error(interp, "local resolvers fn start"); @@ -3182,6 +3215,7 @@ static INLINE int pop_resolver(struct wasm_interp *interp, count_resolvers(interp), num_resolvers ); + */ return 1; } @@ -3263,8 +3297,10 @@ static int upsert_label(struct wasm_interp *interp, int fn, return 0; } + /* debug("upsert_label: %d labels for %s:%d\n", *num_labels, get_function_name(interp->module, fn), fn); + */ *ind = *num_labels; if (unlikely(!(label = index_label(&interp->labels, fn, *ind)))) @@ -3296,9 +3332,11 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe struct resolver resolver; struct callframe *frame; +/* #ifdef DEBUG int num_resolvers; #endif +*/ resolver.start_tag = start_tag; resolver.end_tag = end_tag; @@ -3330,6 +3368,7 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe return interp_error(interp, "push label index to resolver stack oob"); } + /* #ifdef DEBUG if (unlikely(!count_local_resolvers(interp, &num_resolvers))) { return interp_error(interp, "local resolvers fn start"); @@ -3341,6 +3380,7 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe instr_name(resolver.end_tag), cursor_count(&interp->resolver_stack, sizeof(resolver)), num_resolvers); + */ return 1; } @@ -3451,14 +3491,37 @@ static int parse_br_table(struct cursor *code, struct errors *errs, return 1; } -static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) +static int parse_select(struct cursor *code, struct errors *errs, u8 tag, + struct select_instr *select) { + if (tag == i_select) { + select->num_valtypes = 0; + select->valtypes = NULL; + return 1; + } + + if (unlikely(!read_int(code, &select->num_valtypes))) { + return note_error(errs, code, + "couldn't parse select valtype vec count"); + } + select->valtypes = code->p; + code->p += select->num_valtypes; + + return 1; +} + +static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) +{ op->pos = p->code->p - 1 - p->code->start; op->tag = tag; switch (tag) { // two-byte instrs + case i_select: + case i_selects: + return parse_select(p->code, p->errs, tag, &op->select); + case i_memory_size: case i_memory_grow: return pull_byte(p->code, &op->memidx); @@ -3487,7 +3550,11 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) case i_ref_func: case i_table_set: case i_table_get: - return leb128_read(p->code, (unsigned int*)&op->integer); + if (!read_int(p->code, &op->integer)) { + return note_error(p->errs, p->code, + "couldn't read int"); + } + return 1; case i_i32_load: case i_i64_load: @@ -3529,7 +3596,6 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) case i_nop: case i_return: case i_drop: - case i_select: case i_i32_eqz: case i_i32_eq: case i_i32_ne: @@ -4438,8 +4504,6 @@ static int interp_table_init(struct wasm_interp *interp, elem_inst = &interp->module_inst.elements[src]; - debug("table set count %d src %d dst %d\n", - num_inits, src, dst); if (!table_set(interp, table, dst, &elem_inst->val)) { return interp_error(interp, "table set failed for table %d ind %d"); @@ -4449,6 +4513,50 @@ static int interp_table_init(struct wasm_interp *interp, return 1; } +static int interp_select(struct wasm_interp *interp, struct select_instr *select) +{ + struct val top, bottom; + int c; + + (void)select; + + if (unlikely(!stack_pop_i32(interp, &c))) + return interp_error(interp, "pop select"); + + if (unlikely(!stack_popval(interp, &top))) + return interp_error(interp, "pop val top"); + + if (unlikely(!stack_popval(interp, &bottom))) + return interp_error(interp, "pop val bottom"); + + if (unlikely(top.type != bottom.type)) + return interp_error(interp, "type mismatch, %s != %s", + valtype_name(top.type), + valtype_name(bottom.type)); + + if (c != 0) + return stack_pushval(interp, &bottom); + else + return stack_pushval(interp, &top); +} + +static int interp_return(struct wasm_interp *interp) +{ + int count; + + if (unlikely(!count_local_resolvers(interp, &count))) { + return interp_error(interp, "failed to count fn labels?"); + } + + if (unlikely(!cursor_dropn(&interp->resolver_stack, + sizeof(struct resolver), count))) { + return interp_error(interp, "failed to drop %d local labels", + count); + } + + return i_return; +} + static int interp_instr(struct wasm_interp *interp, struct instr *instr) { interp->ops++; @@ -4462,6 +4570,9 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) switch (instr->tag) { case i_unreachable: return interp_error(interp, "unreachable"); case i_nop: return 1; + case i_select: + case i_selects: + return interp_select(interp, &instr->select); case i_local_get: return interp_local_get(interp, instr->integer); case i_local_set: return interp_local_set(interp, instr->integer); @@ -4531,7 +4642,7 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) case i_memory_grow: return interp_memory_grow(interp, instr->memidx); case i_table_op: return interp_error(interp, "todo: interp table_op"); case i_table_set: return interp_table_set(interp, instr->integer); - case i_return: return 1; + case i_return: return interp_return(interp); default: interp_error(interp, "unhandled instruction %s 0x%x", instr_name(instr->tag), instr->tag); @@ -4565,10 +4676,12 @@ static INLINE int interp_parse_instr(struct wasm_interp *interp, } instr->tag = tag; + instr->pos = code->p - 1 - code->start; + instr->tag = tag; if (!is_control_instr(tag) && !parse_instr(parser, instr->tag, instr)) { - return interp_error(interp, "parse instr"); + return interp_error(interp, "parse instr %s", instr_name(tag)); } return 1; @@ -4587,7 +4700,7 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, { struct resolver *resolver; struct label *label; - int offset, num_resolvers = 0; + int num_resolvers = 0; if (unlikely(!(resolver = top_resolver(interp, 0)))) { // no more resolvers, we done. @@ -4601,9 +4714,6 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, debug("interp_code_end local resolvers: %d\n", num_resolvers); if (num_resolvers == 0) { - if (!cursor_popint(&interp->resolver_offsets, &offset)) { - return interp_error(interp, "pop resolver_offsets"); - } return interp_end_done; } @@ -4640,6 +4750,7 @@ static int interp_code(struct wasm_interp *interp) struct expr_parser parser; struct cursor *code; struct callframe *frame; + int ret; make_interp_expr_parser(interp, &parser); @@ -4653,6 +4764,8 @@ static int interp_code(struct wasm_interp *interp) } if (unlikely(!interp_parse_instr(interp, code, &parser, &instr))) { + cursor_print_around(code, 5); + debug("end ? %d\n", top_callframe(&interp->callframes)->fn); return interp_error(interp, "parse instr"); } @@ -4665,10 +4778,13 @@ static int interp_code(struct wasm_interp *interp) } } - if (unlikely(!interp_instr(interp, &instr))) { + if (unlikely(!(ret = interp_instr(interp, &instr)))) { return interp_error(interp, "interp instr %s", - instr_name(instr.tag)); + show_instr(&instr)); } + + if (ret == i_return) + return 1; } return 1; @@ -4740,6 +4856,9 @@ static int calculate_tables_size(struct module *module) int i, num_tables, size; struct table *tables; + if (!was_section_parsed(module, section_table)) + return 0; + tables = module->table_section.tables; num_tables = module->table_section.num_tables; size = num_tables * sizeof(struct table_inst); @@ -4758,6 +4877,9 @@ static int alloc_tables(struct wasm_interp *interp) struct table_inst *inst; int i; + if (!was_section_parsed(interp->module, section_table)) + return 1; + interp->module_inst.num_tables = interp->module->table_section.num_tables; @@ -4964,6 +5086,14 @@ static int init_memories(struct wasm_interp *interp) struct wdata *data; int i; + debug("init memories\n"); + + if (!was_section_parsed(interp->module, section_data)) + return 1; + + if (!was_section_parsed(interp->module, section_memory)) + return 1; + for (i = 0; i < interp->module->data_section.num_datas; i++) { data = &interp->module->data_section.datas[i]; @@ -4983,6 +5113,9 @@ static int init_tables(struct wasm_interp *interp) struct elem *elem; int i; + if (!was_section_parsed(interp->module, section_table)) + return 1; + for (i = 0; i < interp->module->element_section.num_elements; i++) { elem = &interp->module->element_section.elements[i]; @@ -5005,8 +5138,10 @@ static int init_elements(struct wasm_interp *interp) int count = 0; int i, j; + debug("init elements\n"); + if (!was_section_parsed(interp->module, section_element)) - return 0; + return 1; elems = interp->module->element_section.elements; @@ -5089,6 +5224,28 @@ static int instantiate_module(struct wasm_interp *interp) return 1; } +static int reset_memory(struct wasm_interp *interp) +{ + int pages, num_mems; + + num_mems = was_section_parsed(interp->module, section_memory)? + interp->module->memory_section.num_mems : 0; + + reset_cursor(&interp->memory); + + if (num_mems == 1) { + pages = interp->module->memory_section.mems[0].min; + if (!cursor_malloc(&interp->memory, pages * WASM_PAGE_SIZE)) { + return interp_error(interp, + "could not alloc %d memory pages", + pages); + } + assert(interp->memory.p > interp->memory.start); + } + + return 1; +} + int wasm_interp_init(struct wasm_interp *interp, struct module *module) { unsigned char *mem, *heap, *start; @@ -5225,6 +5382,12 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module) return interp_error(interp, "not enough memory"); } + if (!reset_memory(interp)) + return interp_error(interp, "reset memory"); + + if (!instantiate_module(interp)) + return interp_error(interp, "instantiate module"); + return 1; } @@ -5239,28 +5402,6 @@ void wasm_interp_free(struct wasm_interp *interp) free(interp->memory.start); } -static int reset_memory(struct wasm_interp *interp) -{ - int pages, num_mems; - - num_mems = was_section_parsed(interp->module, section_memory)? - interp->module->memory_section.num_mems : 0; - - reset_cursor(&interp->memory); - - if (num_mems == 1) { - pages = interp->module->memory_section.mems[0].min; - if (!cursor_malloc(&interp->memory, pages * WASM_PAGE_SIZE)) { - return interp_error(interp, - "could not alloc %d memory pages", - pages); - } - assert(interp->memory.p > interp->memory.start); - } - - return 1; -} - int interp_wasm_module(struct wasm_interp *interp) { interp->ops = 0; @@ -5277,21 +5418,11 @@ int interp_wasm_module(struct wasm_interp *interp) reset_cursor(&interp->errors.cur); reset_cursor(&interp->callframes); - if (!reset_memory(interp)) - return interp_error(interp, "reset memory"); - - if (!instantiate_module(interp)) - return interp_error(interp, "instantiate module"); - // don't reset labels for perf! //interp->mem.p = interp->mem.start; - if (!prepare_call(interp, interp->module_inst.start_fn)) { - return interp_error(interp, "preparing start function"); - } - - if (interp_code(interp)) { + if (call_function(interp, interp->module_inst.start_fn)) { debug("interp success!!\n"); } else if (interp->quitting) { debug("finished running via process exit\n"); diff --git a/src/wasm.h b/src/wasm.h @@ -291,6 +291,7 @@ enum instr_tag { /* parametric instructions */ i_drop = 0x1A, i_select = 0x1B, + i_selects = 0x1C, /* variable instructions */ i_local_get = 0x20, @@ -522,6 +523,11 @@ struct table_init { int elemidx; }; +struct select_instr { + u8 *valtypes; + int num_valtypes; +}; + struct instr { enum instr_tag tag; int pos; @@ -530,6 +536,7 @@ struct instr { struct table_init table_init; struct call_indirect call_indirect; struct memarg memarg; + struct select_instr select; struct block block; double fp_double; float fp_single; @@ -633,7 +640,6 @@ struct wasm_interp { struct cursor callframes; /* struct callframe */ struct cursor stack; /* struct val */ struct cursor mem; /* u8/mixed */ - struct cursor resolver_offsets; /* int */ struct cursor memory; /* memory pages (65536 blocks) */ @@ -644,6 +650,7 @@ struct wasm_interp { // instruction is encountered, the label index is pushed. When an // instruction is popped, we can resolve the label struct cursor resolver_stack; /* struct resolver */ + struct cursor resolver_offsets; /* int */ }; struct builtin {