protoverse

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

commit 3788ed1555b2483ab5caad867585578b72cd5d39
parent 3c17c9518f6102ae8006799cab4f1c0fc606c0d1
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 20 Jul 2021 10:36:11 -0700

optimize table.init

Diffstat:
Msrc/wasm.c | 307++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/wasm.h | 6+++++-
Mtodo/todo.txt | 1+
3 files changed, 163 insertions(+), 151 deletions(-)

diff --git a/src/wasm.c b/src/wasm.c @@ -127,11 +127,6 @@ static struct val *get_local(struct wasm_interp *interp, int ind) return get_fn_local(interp, frame->fn, ind); } -static INLINE int stack_dropval(struct wasm_interp *interp) -{ - return cursor_drop(&interp->stack, sizeof(struct val)); -} - static INLINE int stack_popval(struct wasm_interp *interp, struct val *val) { return cursor_popval(&interp->stack, val); @@ -174,6 +169,7 @@ static int is_reftype(enum valtype type) return 0; } +/* static INLINE int cursor_pop_ref(struct cursor *stack, struct val *val) { if (!cursor_popval(stack, val)) { @@ -184,6 +180,7 @@ static INLINE int cursor_pop_ref(struct cursor *stack, struct val *val) } return 1; } +*/ static INLINE int stack_pop_ref(struct wasm_interp *interp, struct val *val) { @@ -238,6 +235,14 @@ static void print_val(struct val *val) printf("%s", valtype_literal(val->type)); } +static void print_refval(struct refval *ref, enum reftype reftype) +{ + struct val val; + val.type = (enum valtype)reftype; + val.ref = *ref; + print_val(&val); +} + static void print_stack(struct cursor *stack) { struct val val; @@ -245,7 +250,6 @@ static void print_stack(struct cursor *stack) u8 *p = stack->p; if (stack->p == stack->start) { - printf("empty stack\n"); return; } @@ -559,6 +563,9 @@ static char *instr_name(enum instr_tag tag) case i_ref_null: return "ref_null"; case i_ref_func: return "ref_func"; case i_ref_is_null: return "ref_is_null"; + case i_table_op: return "table_op"; + case i_table_get: return "table_get"; + case i_table_set: return "table_set"; } snprintf(unk, sizeof(unk), "0x%02x", tag); @@ -1435,6 +1442,7 @@ 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; @@ -1479,6 +1487,8 @@ static const char *show_instr(struct instr *instr) case i_i32_const: case i_i64_const: case i_ref_func: + case i_table_set: + case i_table_get: sprintf(tmp, "%d", instr->integer); cursor_push_str(&buf, tmp); break; @@ -1668,12 +1678,14 @@ static const char *show_instr(struct instr *instr) case i_i64_extend16_s: case i_i64_extend32_s: case i_ref_is_null: + case i_table_op: break; } cursor_push_byte(&buf, 0); return buffer; } +#endif static int eval_const_instr(struct instr *instr, struct errors *errs, struct cursor *stack) @@ -3473,6 +3485,8 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) case i_i32_const: case i_i64_const: case i_ref_func: + case i_table_set: + case i_table_get: return leb128_read(p->code, (unsigned int*)&op->integer); case i_i32_load: @@ -4261,6 +4275,119 @@ static int interp_loop(struct wasm_interp *interp) return 1; } +static INLINE int table_set(struct wasm_interp *interp, + struct table_inst *table, int ind, struct val *val) +{ + + if (unlikely(ind >= table->num_refs)) { + return interp_error(interp, "invalid index %d (max %d)", + ind, + interp->module_inst.num_tables); + } + + if (unlikely(table->reftype != (enum reftype)val->type)) { + return interp_error(interp, "can't store %s ref in %s table", + valtype_name(val->type), + valtype_name((enum valtype)table->reftype)); + } + + debug("setting table[%ld] ref %d to ", + (table - interp->module_inst.tables) / sizeof (struct table_inst), + ind); +#ifdef DEBUG + print_refval(&val->ref, table->reftype); + printf("\n"); +#endif + + memcpy(&table->refs[ind], &val->ref, sizeof(struct refval)); + + return 1; +} + +static int interp_table_set(struct wasm_interp *interp, int tableidx) +{ + struct table_inst *table; + struct val val; + int ind; + + if (unlikely(tableidx >= interp->module_inst.num_tables)) { + return interp_error(interp, "tableidx oob %d (max %d)", + tableidx, + interp->module_inst.num_tables + 1); + } + + table = &interp->module_inst.tables[tableidx]; + + if (unlikely(!stack_pop_ref(interp, &val))) { + return interp_error(interp, "pop ref"); + } + + if (unlikely(!stack_pop_i32(interp, &ind))) { + return interp_error(interp, "pop elem index"); + } + + return table_set(interp, table, ind, &val); +} + +static int interp_table_init(struct wasm_interp *interp, + struct table_init *t) +{ + struct table_inst *table; + struct elem_inst *elem_inst; + int num_inits, offset, s; + + if (unlikely(t->tableidx >= interp->module_inst.num_tables)) { + return interp_error(interp, "tableidx oob %d (max %d)", + t->tableidx, + interp->module_inst.num_tables + 1); + } + + table = &interp->module_inst.tables[t->tableidx]; + + // TODO: elem addr ? + if (unlikely(t->elemidx >= interp->module->element_section.num_elements)) { + return interp_error(interp, "elemidx oob %d (max %d)", + t->elemidx, + interp->module->element_section.num_elements + 1); + } + + if (unlikely(!stack_pop_i32(interp, &num_inits))) { + return interp_error(interp, "pop num_inits"); + } + + if (unlikely(!stack_pop_i32(interp, &s))) { + return interp_error(interp, "pop s"); + } + + if (unlikely(!stack_pop_i32(interp, &offset))) { + return interp_error(interp, "pop offset"); + } + + for (; num_inits; num_inits--, offset++, s++) { + if (unlikely(s + num_inits > interp->module_inst.num_elements)) { + return interp_error(interp, "index oob elem.elem s+n %d (max %d)", + s + num_inits, + interp->module_inst.num_elements + 1); + } + + if (unlikely(offset + num_inits > table->num_refs)) { + return interp_error(interp, "index oob tab.elem d+n %d (max %d)", + offset + num_inits, + table->num_refs + 1); + } + + elem_inst = &interp->module_inst.elements[s]; + + debug("table set num_inits %d s %d offset %d\n", + num_inits, s, offset); + if (!table_set(interp, table, offset, &elem_inst->val)) { + return interp_error(interp, + "table set failed for table %d ind %d"); + } + } + + return 1; +} static int interp_instr(struct wasm_interp *interp, struct instr *instr) { @@ -4342,6 +4469,8 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) case i_br_if: return interp_br_if(interp, instr->integer); case i_memory_size: return interp_memory_size(interp, instr->memidx); 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; default: interp_error(interp, "unhandled instruction %s 0x%x", @@ -4437,123 +4566,6 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, return interp_end_next; } -static int interp_table_set(struct wasm_interp *interp, int tableidx) -{ - struct table_inst *table; - struct val val; - int ind; - - if (unlikely(tableidx >= interp->module_inst.num_tables)) { - return interp_error(interp, "tableidx oob %d (max %d)", - tableidx, - interp->module_inst.num_tables + 1); - } - - table = &interp->module_inst.tables[tableidx]; - - if (unlikely(!stack_pop_ref(interp, &val))) { - return interp_error(interp, "pop ref"); - } - - if (unlikely(!stack_pop_i32(interp, &ind))) { - return interp_error(interp, "pop elem index"); - } - - if (ind >= table->num_refs) { - return interp_error(interp, "invalid index %d for table %d (max %d)", - ind, tableidx, - interp->module_inst.num_tables); - } - - if (table->reftype != (enum reftype)val.type) { - return interp_error(interp, "can't store %s ref in %s table", - valtype_name(val.type), - valtype_name((enum valtype)table->reftype)); - } - - memcpy(&table->refs[ind], &val.ref, sizeof(struct refval)); - - return 1; -} - -static int interp_table_init(struct wasm_interp *interp, struct table_init *t) -{ - struct elem_inst *elem_inst; - struct table_inst *table; - int n, s, d; - - if (unlikely(t->tableidx >= interp->module_inst.num_tables)) { - return interp_error(interp, "tableidx oob %d (max %d)", - t->tableidx, - interp->module_inst.num_tables + 1); - } - - table = &interp->module_inst.tables[t->tableidx]; - - // TODO: elem addr ? - if (unlikely(t->elemidx >= interp->module_inst.num_elements)) { - return interp_error(interp, "elemidx oob %d (max %d)", - t->elemidx, - interp->module_inst.num_elements + 1); - } - - if (unlikely(!stack_pop_i32(interp, &n))) { - return interp_error(interp, "pop n"); - } - - if (unlikely(!stack_pop_i32(interp, &s))) { - return interp_error(interp, "pop s"); - } - - if (unlikely(!stack_pop_i32(interp, &d))) { - return interp_error(interp, "pop d"); - } - - if (unlikely(s + n > interp->module_inst.num_elements)) { - return interp_error(interp, "index oob elem.elem s+n %d (max %d)", - s + n, - interp->module_inst.num_elements + 1); - } - - if (unlikely(d + n > table->num_refs)) { - return interp_error(interp, "index oob tab.elem d+n %d (max %d)", - d + n, - table->num_refs); - } - - if (n == 0) { - return 1; - } - - elem_inst = &interp->module_inst.elements[s]; - - if (unlikely(!stack_push_i32(interp, d))) { - return interp_error(interp, "push d"); - } - - if (unlikely(!stack_pushval(interp, &elem_inst->ref))) { - return interp_error(interp, "push ref"); - } - - if (unlikely(!interp_table_set(interp, t->tableidx))) { - return interp_error(interp, "table set"); - } - - if (unlikely(!stack_push_i32(interp, d+1))) { - return interp_error(interp, "push d+1"); - } - - if (unlikely(!stack_push_i32(interp, s+1))) { - return interp_error(interp, "push s+1"); - } - - if (unlikely(!stack_push_i32(interp, n-1))) { - return interp_error(interp, "push n-1"); - } - - return interp_table_init(interp, t); -} - static int interp_elem_drop(struct wasm_interp *interp, int elemidx) { (void)interp; @@ -4760,7 +4772,7 @@ static int alloc_locals(struct module *module, struct cursor *mem, static int init_element(struct wasm_interp *interp, struct expr *init, struct elem_inst *elem_inst) { - if (!eval_const_val(init, &interp->errors, &interp->stack, &elem_inst->ref)) { + if (!eval_const_val(init, &interp->errors, &interp->stack, &elem_inst->val)) { return interp_error(interp, "failed to eval element init expr"); } return 1; @@ -4845,20 +4857,14 @@ static int init_globals(struct wasm_interp *interp) static int count_element_insts(struct module *module) { - struct elem *elems, *elem; + struct elem *elem; int i, size = 0; if (!was_section_parsed(module, section_element)) return 0; - elems = module->element_section.elements; - for (i = 0; i < module->element_section.num_elements; i++) { - elem = &elems[i]; - - if (elem->mode != elem_mode_active) - continue; - + elem = &module->element_section.elements[i]; size += elem->num_inits; } @@ -4869,17 +4875,19 @@ static int count_element_insts(struct module *module) static int init_tables(struct wasm_interp *interp) { struct elem *elem; - struct elem_inst *inst; int i; - for (i = 0; i < interp->module_inst.num_elements; i++) { - inst = &interp->module_inst.elements[i]; - elem = &interp->module->element_section.elements[inst->elem]; + for (i = 0; i < interp->module->element_section.num_elements; i++) { + elem = &interp->module->element_section.elements[i]; + + if (elem->mode != elem_mode_active) + continue; - if (!init_table(interp, elem, i, - interp->module_inst.num_elements)) { + if (!init_table(interp, elem, i, elem->num_inits)) { return interp_error(interp, "init table failed"); } + + break; } return 1; @@ -4923,8 +4931,9 @@ static int init_elements(struct wasm_interp *interp) } // https://webassembly.github.io/spec/core/exec/modules.html#instantiation -static int instantiate_module(struct wasm_interp *interp, int func) +static int instantiate_module(struct wasm_interp *interp) { + int func; //TODO:Assert module is valid with external types classifying its imports // TODO: If the number # of imports is not equal to the number of provided external values then fail @@ -4938,6 +4947,10 @@ static int instantiate_module(struct wasm_interp *interp, int func) } */ + func = interp->module_inst.start_fn != -1 + ? interp->module_inst.start_fn + : find_start_function(interp->module); + memset(interp->module_inst.globals, 0, interp->module_inst.num_globals * sizeof(*interp->module_inst.globals)); @@ -4949,6 +4962,8 @@ static int instantiate_module(struct wasm_interp *interp, int func) return interp_error(interp, "no start function found"); } else { interp->module_inst.start_fn = func; + debug("found start function %s (%d)\n", + get_function_name(interp->module, func), func); } if (!init_elements(interp)) { @@ -5102,6 +5117,9 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module) return interp_error(interp, "not enough memory"); } + if (!instantiate_module(interp)) + return interp_error(interp, "instantiate module"); + return 1; } @@ -5140,8 +5158,6 @@ static int reset_memory(struct wasm_interp *interp) int interp_wasm_module(struct wasm_interp *interp) { - int func; - interp->ops = 0; if (interp->module->code_section.num_funcs == 0) { @@ -5163,15 +5179,6 @@ int interp_wasm_module(struct wasm_interp *interp) //interp->mem.p = interp->mem.start; - func = interp->module_inst.start_fn != -1 - ? interp->module_inst.start_fn - : find_start_function(interp->module); - - if (!instantiate_module(interp, func)) - return interp_error(interp, "instantiate module"); - - debug("found start function %s (%d)\n", - get_function_name(interp->module, func), func); if (!prepare_call(interp, interp->module_inst.start_fn)) { return interp_error(interp, "preparing start function"); diff --git a/src/wasm.h b/src/wasm.h @@ -126,7 +126,7 @@ struct val { }; struct elem_inst { - struct val ref; + struct val val; u16 elem; u16 init; }; @@ -298,6 +298,8 @@ enum instr_tag { i_local_tee = 0x22, i_global_get = 0x23, i_global_set = 0x24, + i_table_get = 0x25, + i_table_set = 0x26, /* memory instructions */ i_i32_load = 0x28, @@ -474,6 +476,7 @@ enum instr_tag { i_ref_is_null = 0xD1, i_ref_func = 0xD2, + i_table_op = 0xFC, /* TODO: more instrs */ }; @@ -524,6 +527,7 @@ struct instr { int pos; union { struct br_table br_table; + struct table_init table_init; struct call_indirect call_indirect; struct memarg memarg; struct block block; diff --git a/todo/todo.txt b/todo/todo.txt @@ -3,3 +3,4 @@ do we need to reset function locals on return? @wasm check blocktypes when popping labels @wasm make chess demo @examples getting started @docs +optimize table initialization @wasm