protoverse

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

commit 64bf2c270ed8bb417615c1e15f84f44585f815e4
parent e7966eafde08d5c6f71695a47f87f23ca740a8f8
Author: William Casarin <jb55@jb55.com>
Date:   Fri, 16 Jul 2021 17:48:06 -0700

use function locals like they were intended

get rid of the weird local stack we were using

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

Diffstat:
Msrc/wasm.c | 141++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/wasm.h | 17+++++++++++++----
2 files changed, 73 insertions(+), 85 deletions(-)

diff --git a/src/wasm.c b/src/wasm.c @@ -25,16 +25,6 @@ static const int MAX_LABELS = 128; -struct val { - enum valtype type; - union { - int i32; - u64 i64; - float f32; - double f64; - }; -}; - struct expr_parser { struct wasm_interp *interp; // optional... struct cursor *code; @@ -82,18 +72,61 @@ static INLINE int offset_stack_top(struct cursor *cur) return *(p - sizeof(*p)); } -static INLINE struct val *get_local(struct wasm_interp *interp, int ind) +static INLINE struct local *get_locals(struct func *func, int *num_locals) +{ + switch (func->type) { + case func_type_wasm: + *num_locals = func->wasm_func->num_locals; + return func->wasm_func->locals; + case func_type_builtin: + *num_locals = func->builtin->num_locals; + return func->builtin->locals; + } + return NULL; +} + +static INLINE int is_valid_fn_index(struct module *module, int ind) +{ + return ind >= 0 && ind < module->num_funcs; +} + +static INLINE struct func *get_function(struct module *module, int ind) +{ + if (unlikely(!is_valid_fn_index(module, ind))) + return NULL; + return &module->funcs[ind]; +} + +static struct val *get_local(struct wasm_interp *interp, int ind) { - struct val *p; - int offset = offset_stack_top(&interp->locals_offsets); + struct callframe *frame; + struct func *func; + struct local *locals; + int num_locals; + + if (unlikely(!(frame = top_callframe(&interp->callframes)))) { + interp_error(interp, "no callframe?"); + return NULL; + } + + if (unlikely(!(func = get_function(interp->module, frame->fn)))) { + interp_error(interp, "unknown fn %d", frame->fn); + return NULL; + } - if (unlikely(!(p = index_cursor(&interp->locals, offset + ind, - sizeof(struct val))))) { - interp_error(interp, "%d local oob %d > %ld", ind, offset + ind, - interp->locals.end - interp->locals.start); + if (unlikely(!(locals = get_locals(func, &num_locals)))) { + interp_error(interp, "couldn't find locals for %s", + func->name); return NULL; } - return p; + + if (unlikely(!(ind >= num_locals))) { + interp_error(interp, "local index %d too high for %s (max %d)", + ind, func->name, num_locals-1); + return NULL; + } + + return &locals[ind].val; } static INLINE int stack_pop_i32(struct wasm_interp *interp, int *i) @@ -560,18 +593,6 @@ static INLINE int count_imported_functions(struct module *module) return count_imports(module, &typ); } -static INLINE int is_valid_fn_index(struct module *module, int ind) -{ - return ind >= 0 && ind < module->num_funcs; -} - -static INLINE struct func *get_function(struct module *module, int ind) -{ - if (unlikely(!is_valid_fn_index(module, ind))) - return NULL; - return &module->funcs[ind]; -} - static INLINE const char *get_function_name(struct module *module, int fn) { struct func *func = NULL; @@ -932,12 +953,12 @@ static int parse_export(struct wasm_parser *p, struct wexport *export) static int parse_local(struct wasm_parser *p, struct local *local) { - if (unlikely(!leb128_read(&p->cur, &local->n))) { + if (unlikely(!leb128_read(&p->cur, (unsigned int*)&local->val.i32))) { parse_err(p, "n"); return 0; } - if (unlikely(!parse_valtype(p, &local->valtype))) { + if (unlikely(!parse_valtype(p, &local->val.type))) { parse_err(p, "valtype"); return 0; } @@ -2074,37 +2095,15 @@ static int interp_i32_sub(struct wasm_interp *interp) return cursor_pushval(&interp->stack, &c); } -static INLINE int count_locals(struct wasm_interp *interp) -{ - int offset = offset_stack_top(&interp->locals_offsets); - int count = cursor_count(&interp->locals, sizeof(struct val)); - return count - offset; -} - static int set_local(struct wasm_interp *interp, int ind, struct val *val) { struct val *local; - int nlocals; - - nlocals = count_locals(interp); - if (ind > nlocals) { - /* TODO: if we hit this then we need to push empty locals up to the index */ - interp_error(interp, "local index out of order"); - return 0; + if (unlikely(!(local = get_local(interp, ind)))) { + return interp_error(interp, "no local?"); } - if (ind < nlocals) { - debug("memsetting local %d\n", ind); - if (!(local = get_local(interp, ind))) { - return 0; - } - memcpy(local, val, sizeof(*val)); - return 1; - } - - cursor_pushval(&interp->locals, val); - assert(count_locals(interp) > 0); + memcpy(local, val, sizeof(*val)); return 1; } @@ -2136,7 +2135,6 @@ static int interp_local_set(struct wasm_interp *interp) static int interp_local_get(struct wasm_interp *interp) { unsigned int index; - unsigned int nlocals; struct val *val; struct cursor *code; @@ -2150,13 +2148,6 @@ static int interp_local_get(struct wasm_interp *interp) return 0; } - nlocals = count_locals(interp); - if (unlikely(index >= nlocals)) { - interp_error(interp, "local %d not set (%d locals)", index, - nlocals); - return 0; - } - if (unlikely(!(val = get_local(interp, index)))) { interp_error(interp, "get local"); return 0; @@ -2295,13 +2286,9 @@ static int prepare_call(struct wasm_interp *interp, int func_index) interp->module->code_section.num_funcs); } - /* record locals offset for indexing locals in the next function */ - offset = cursor_count(&interp->locals, sizeof(struct val)); - if (unlikely(!cursor_push_int(&interp->locals_offsets, offset))) - return interp_error(interp, "push locals offset"); - offset = count_resolvers(interp); - /* this is like locals offsets but for label resolvers */ + /* push label resolver offsets, used to keep track of per-func resolvers */ + /* TODO: maybe move this data to struct func? */ if (unlikely(!cursor_push_int(&interp->resolver_offsets, offset))) return interp_error(interp, "push resolver offset"); @@ -2343,8 +2330,8 @@ static int prepare_call(struct wasm_interp *interp, int func_index) valtype_name(paramtype)); } - if (unlikely(!cursor_pushval(&interp->locals, &val))) { - return interp_error(interp, "push param local"); + if (unlikely(!set_local(interp, i, &val))) { + return interp_error(interp, "set param local %d", i); } } @@ -3089,10 +3076,6 @@ int interp_code(struct wasm_interp *interp) return interp_error(interp, "pop resolver_offsets"); } - if (!cursor_popint(&interp->locals_offsets, - &offset)) - return interp_error(interp, - "pop locals_offset"); break; } } @@ -3206,8 +3189,6 @@ void wasm_interp_init(struct wasm_interp *interp, struct module *module) ok = cursor_slice(&interp->mem, &interp->stack, stack_size) && cursor_slice(&interp->mem, &interp->errors.cur, errors_size) && - cursor_slice(&interp->mem, &interp->locals, locals_size) && - cursor_slice(&interp->mem, &interp->locals_offsets, offsets_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) && @@ -3243,8 +3224,6 @@ int interp_wasm_module(struct wasm_interp *interp) reset_cursor(&interp->resolver_stack); reset_cursor(&interp->resolver_offsets); reset_cursor(&interp->errors.cur); - reset_cursor(&interp->locals); - reset_cursor(&interp->locals_offsets); reset_cursor(&interp->callframes); // don't reset labels for perf! diff --git a/src/wasm.h b/src/wasm.h @@ -181,9 +181,18 @@ struct global { struct expr init; }; +struct val { + enum valtype type; + union { + int i32; + u64 i64; + float f32; + double f64; + }; +}; + struct local { - unsigned int n; - enum valtype valtype; + struct val val; }; /* "code" */ @@ -486,8 +495,6 @@ struct wasm_interp { struct cursor callframes; /* struct callframe */ struct cursor stack; /* struct val */ struct cursor mem; /* u8/mixed */ - struct cursor locals; /* struct val */ - struct cursor locals_offsets; /* int */ struct cursor resolver_offsets; /* int */ struct array labels; /* struct labels */ @@ -501,6 +508,8 @@ struct wasm_interp { struct builtin { const char *name; + struct local locals[8]; + int num_locals; int (*fn)(struct wasm_interp *); int (*prepare_args)(struct wasm_interp *); };