protoverse

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

commit abb7c50bdce9eba7d7604af1f5a0d845885a12d0
parent 3e2b1a3a82bfe9d9147efb33c9d1062025ce3eda
Author: William Casarin <jb55@jb55.com>
Date:   Fri,  6 Aug 2021 16:39:17 -0700

more flexible function calling

can call dynamic external functions

Diffstat:
Msrc/wasm.c | 299++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/wasm.h | 3++-
2 files changed, 160 insertions(+), 142 deletions(-)

diff --git a/src/wasm.c b/src/wasm.c @@ -190,45 +190,39 @@ static INLINE int read_mem_i32(struct wasm_interp *interp, u32 ptr, int *i) static INLINE struct val *get_local(struct wasm_interp *interp, u32 ind) { struct callframe *frame; - struct func *func; if (unlikely(!(frame = top_callframe(&interp->callframes)))) { interp_error(interp, "no callframe?"); return NULL; } - func = &interp->module->funcs[frame->fn]; - - if (unlikely(ind >= func->num_locals)) { + if (unlikely(ind >= frame->func->num_locals)) { interp_error(interp, "local index %d too high for %s:%d (max %d)", - ind, func->name, frame->fn, func->num_locals-1); + ind, frame->func->name, frame->func->idx, + frame->func->num_locals-1); return NULL; } return &frame->locals[ind]; } -static INLINE int get_params(struct wasm_interp *interp, - struct val** vals, u32 num_vals) +static INLINE int get_params(struct wasm_interp *interp, struct val** vals, + u32 num_vals) { - struct callframe *frame; - struct func *fn; - - if (unlikely(!(frame = top_callframe(&interp->callframes)))) - return interp_error(interp, "no callframe?"); + struct callframe *frame; - if (unlikely(!(fn = get_fn(interp->module, frame->fn)))) - return interp_error(interp, "invalid fn %d", frame->fn); + if (unlikely(!(frame = top_callframe(&interp->callframes)))) + return interp_error(interp, "no callframe?"); - if (unlikely(num_vals != fn->functype->params.num_valtypes)) { - return interp_error(interp, - "requested %d params, but there are %d", - num_vals, fn->functype->params.num_valtypes); - } + if (unlikely(num_vals != frame->func->functype->params.num_valtypes)) { + return interp_error(interp, + "requested %d params, but there are %d", + num_vals, frame->func->functype->params.num_valtypes); + } - *vals = frame->locals; + *vals = frame->locals; - return 1; + return 1; } static INLINE int stack_popval(struct wasm_interp *interp, struct val *val) @@ -431,15 +425,16 @@ void print_callstack(struct wasm_interp *interp) { int i = 0; struct callframe *frame; - struct func *func; printf("callstack:\n"); while ((frame = top_callframes(&interp->callframes, i++))) { - func = get_fn(interp->module, frame->fn); - if (!func) + if (!frame->func) { printf("??\n"); - else - printf("%d %s:%d\n", i, func->name, frame->fn); + continue; + } + else { + printf("%d %s:%d\n", i, frame->func->name, frame->func->idx); + } } } @@ -543,6 +538,15 @@ static int wasi_abort(struct wasm_interp *interp) return 0; } +static INLINE const char *get_function_name(struct module *module, int fn) +{ + struct func *func = NULL; + if (unlikely(!(func = get_fn(module, fn)))) { + return "unknown"; + } + return func->name; +} + static int wasi_args_sizes_get(struct wasm_interp *interp); static int wasi_args_get(struct wasm_interp *interp); static int wasi_fd_write(struct wasm_interp *interp); @@ -550,6 +554,7 @@ static int wasi_environ_sizes_get(struct wasm_interp *interp); static int wasi_environ_get(struct wasm_interp *interp); static struct builtin BUILTINS[] = { + { .name = "null", .fn = NULL }, // for reasons { .name = "args_get", .fn = wasi_args_get }, { .name = "fd_write", .fn = wasi_fd_write }, { .name = "environ_sizes_get", .fn = wasi_environ_sizes_get }, @@ -1037,15 +1042,6 @@ static INLINE int count_imported_functions(struct module *module) return count_imports(module, &typ); } -static INLINE const char *get_function_name(struct module *module, int fn) -{ - struct func *func = NULL; - if (unlikely(!(func = get_fn(module, fn)))) { - return "unknown"; - } - return func->name; -} - static void print_element_section(struct elemsec *section) { printf("%d elements\n", section->num_elements); @@ -3036,12 +3032,24 @@ static int count_fn_locals(struct func *func) return num_locals; } +static void make_builtin_func(struct func *func, const char *name, + struct functype *type, struct builtin *builtin, u32 idx) +{ + func->name = name; + func->builtin = builtin; + func->functype = type; + func->type = func_type_builtin; + func->num_locals = count_fn_locals(func); + func->idx = idx; +} + static int make_func_lookup_table(struct wasm_parser *parser) { u32 i, num_imports, num_func_imports, num_internal_funcs, typeidx, fn; struct import *import; struct importsec *imports; struct func *func; + struct builtin *builtin; fn = 0; @@ -3067,18 +3075,20 @@ static int make_func_lookup_table(struct wasm_parser *parser) func = &parser->module.funcs[fn++]; - func->name = import->name; - typeidx = import->desc.typeidx; - func->functype = &parser->module.type_section.functypes[typeidx]; - func->type = func_type_builtin; - func->num_locals = count_fn_locals(func); - if (import->resolved_builtin == -1) { debug("warning: %s not resolved\n", func->name); - func->builtin = NULL; + builtin = NULL; } else { - func->builtin = builtin_func(import->resolved_builtin); + builtin = builtin_func(import->resolved_builtin); } + + make_builtin_func( + func, + import->name, + &parser->module.type_section.functypes[import->desc.typeidx], + builtin, + fn + ); } /* module fns */ @@ -3091,6 +3101,7 @@ static int make_func_lookup_table(struct wasm_parser *parser) func->functype = &parser->module.type_section.functypes[typeidx]; func->name = find_function_name(&parser->module, fn); func->num_locals = count_fn_locals(func); + func->idx = fn; } assert(fn == parser->module.num_funcs); @@ -3729,26 +3740,24 @@ static INLINE int drop_callframe_return(struct wasm_interp *interp, int returnin from = "(aux)"; from_fn = -1; } else { - from = get_function_name(interp->module, frame->fn); - from_fn = frame->fn; + from = get_function_name(interp->module, frame->func->idx); + from_fn = frame->func->idx; } if (!(frame = top_callframes(&interp->callframes, 1))) { to = "(aux)"; to_fn = -1; } else { - to = get_function_name(interp->module, frame->fn); - to_fn = frame->fn; + to = get_function_name(interp->module, frame->func->idx); + to_fn = frame->func->idx; } #endif frame = top_callframe(&interp->callframes); + func = frame->func; if (unlikely(!cursor_popint(&interp->resolver_offsets, &offset))) return interp_error(interp, "pop resolver_offsets"); - if (unlikely(!(func = get_fn(interp->module, frame->fn)))) - return interp_error(interp, "no fn??"); - cnt = count_stack_vals(&interp->stack); if (returning) { @@ -3767,7 +3776,7 @@ static INLINE int drop_callframe_return(struct wasm_interp *interp, int returnin func->functype->result.num_valtypes)) { return interp_error(interp, "%s:%d extra values on stack: have %d-prev:%d=%d, expected %d", - func->name, frame->fn, cnt, + func->name, frame->func->idx, cnt, frame->prev_stack_items, cnt - frame->prev_stack_items, func->functype->result.num_valtypes); @@ -3786,78 +3795,6 @@ static INLINE int drop_callframe(struct wasm_interp *interp) return drop_callframe_return(interp, 1); } -static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *func, - int fn, struct val *locals, int prev_items) -{ - struct callframe callframe; - - /* update current function and push it to the callframe as well */ - make_cursor(func->code.code, func->code.code + func->code.code_len, &callframe.code); - callframe.fn = fn; - callframe.locals = locals; - callframe.prev_stack_items = prev_items; - - assert(func->code.code_len > 0); - - if (unlikely(!push_callframe(interp, &callframe))) - return interp_error(interp, "push callframe"); - - /* - 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 val *params, int prev_items) -{ - struct callframe callframe = {}; - - /* update current function and push it to the callframe as well */ - callframe.fn = fn; - callframe.locals = params; - callframe.prev_stack_items = prev_items; - - if (unlikely(!push_callframe(interp, &callframe))) - return interp_error(interp, "oob cursor_pushcode"); - - if (!builtin->fn(interp)) - return interp_error(interp, "builtin trap"); - - 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, struct val *locals, int prev_items) -{ - switch (func->type) { - case func_type_wasm: - return call_wasm_func(interp, func->wasm_func, fn, locals, - prev_items); - case func_type_builtin: - if (func->builtin == NULL) { - return interp_error(interp, - "attempted to call unresolved fn: %s", - func->name); - } - return call_builtin_func(interp, func->builtin, fn, locals, - prev_items); - } - return interp_error(interp, "corrupt func type: %02x", func->type); -} - static void make_default_val(struct val *val) { switch (val->type) { @@ -3900,7 +3837,7 @@ static struct val *alloc_frame_locals(struct wasm_interp *interp, } static int prepare_call(struct wasm_interp *interp, struct func *func, - int func_index, struct val **locals, int *prev_items) + struct val **locals, int *prev_items) { static char buf[128]; struct val *local; @@ -3930,7 +3867,7 @@ static int prepare_call(struct wasm_interp *interp, struct func *func, if (unlikely(!cursor_popval(&interp->stack, &val))) { return interp_error(interp, "not enough arguments for call to %s: [%s], needed %d args, got %d", - get_function_name(interp->module, func_index), + func->name, functype_str(func->functype, buf, sizeof(buf)), func->functype->params.num_valtypes, ind); @@ -3974,12 +3911,90 @@ static int prepare_call(struct wasm_interp *interp, struct func *func, return 1; } -static int call_function(struct wasm_interp *interp, int func_index) +static INLINE int call_wasm_func(struct wasm_interp *interp, struct func *func) { - struct func *func; + struct callframe callframe; + struct val *locals; + int prev_items; + + if (!prepare_call(interp, func, &locals, &prev_items)) + return interp_error(interp, "prepare args"); + + /* update current function and push it to the callframe as well */ + make_cursor(func->wasm_func->code.code, + func->wasm_func->code.code + func->wasm_func->code.code_len, + &callframe.code); + + callframe.func = func; + callframe.locals = locals; + callframe.prev_stack_items = prev_items; + + assert(func->wasm_func->code.code_len > 0); + + if (unlikely(!push_callframe(interp, &callframe))) + return interp_error(interp, "push callframe"); + + /* + 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 func *func) +{ + struct callframe callframe = {}; struct val *locals; int prev_items; + if (!prepare_call(interp, func, &locals, &prev_items)) + return interp_error(interp, "prepare args"); + + /* update current function and push it to the callframe as well */ + callframe.func = func; + callframe.locals = locals; + callframe.prev_stack_items = prev_items; + + if (unlikely(!push_callframe(interp, &callframe))) + return interp_error(interp, "oob cursor_pushcode"); + + if (!func->builtin->fn(interp)) + return interp_error(interp, "builtin trap"); + + 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) +{ + switch (func->type) { + case func_type_wasm: + return call_wasm_func(interp, func); + case func_type_builtin: + if (func->builtin == NULL) { + return interp_error(interp, + "attempted to call unresolved fn: %s", + func->name); + } + return call_builtin_func(interp, func); + } + return interp_error(interp, "corrupt func type: %02x", func->type); +} + + +static int call_function(struct wasm_interp *interp, int func_index) +{ + struct func *func; + debug("calling %s:%d\n", get_function_name(interp->module, func_index), func_index); if (unlikely(!(func = get_fn(interp->module, func_index)))) { @@ -3990,10 +4005,7 @@ static int call_function(struct wasm_interp *interp, int func_index) interp->module->code_section.num_funcs); } - if (!prepare_call(interp, func, func_index, &locals, &prev_items)) - return interp_error(interp, "prepare args"); - - return call_func(interp, func, func_index, locals, prev_items); + return call_func(interp, func); } static int interp_call(struct wasm_interp *interp, int func_index) @@ -4024,8 +4036,9 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect static char buf[128]; static char buf2[128]; struct functype *type; - struct func *func; + struct func *func, pfunc; struct table_inst *table; + struct builtin *builtin; struct refval *ref; u32 ftidx; int i; @@ -4073,9 +4086,13 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect i, call->tableidx); } - if (ref->addr >= interp->module->num_funcs) { - return interp_error(interp, "invalid function ref %d (max %d)", - ref, interp->module->num_funcs-1); + // HACKY special case for indirect host builtins + i = -((int)ref->addr); + if (-i < 0 && i < NUM_BUILTINS) { + builtin = &BUILTINS[i]; + make_builtin_func(&pfunc, builtin->name, type, builtin, -i); + debug("calling indirect builtin %s\n", pfunc.name); + return call_builtin_func(interp, &pfunc); } func = &interp->module->funcs[ref->addr]; @@ -4150,7 +4167,7 @@ static struct label *index_frame_label(struct wasm_interp *interp, u32 ind) return NULL; } - return index_label(&interp->labels, frame->fn, ind); + return index_label(&interp->labels, frame->func->idx, ind); } static INLINE int resolve_label(struct label *label, struct cursor *code) @@ -4187,7 +4204,7 @@ static INLINE int pop_resolver(struct wasm_interp *interp, }; label = index_label(&interp->labels, - top_callframe(&interp->callframes)->fn, + top_callframe(&interp->callframes)->func->idx, resolver->label); #endif @@ -4215,7 +4232,7 @@ static int pop_label(struct wasm_interp *interp, if (unlikely(!(*frame = top_callframe(&interp->callframes)))) return interp_error(interp, "no callframe?"); - if (unlikely(!(*label = index_label(&interp->labels, (*frame)->fn, + if (unlikely(!(*label = index_label(&interp->labels, (*frame)->func->idx, resolver->label)))) return interp_error(interp, "index label"); @@ -4338,16 +4355,16 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe if (unlikely(!frame)) { return interp_error(interp, "no callframes available?"); - } else if (unlikely(frame->fn >= fns)) { + } else if (unlikely(frame->func->idx >= fns)) { return interp_error(interp, "invalid fn index?"); } instr_pos = frame->code.p - frame->code.start; - if (unlikely(!upsert_label(interp, frame->fn, instr_pos, &ind))) { + if (unlikely(!upsert_label(interp, frame->func->idx, instr_pos, &ind))) { return interp_error(interp, "upsert label"); } - if (unlikely(!(*label = index_label(&interp->labels, frame->fn, ind)))) { + if (unlikely(!(*label = index_label(&interp->labels, frame->func->idx, ind)))) { return interp_error(interp, "couldn't index label"); } diff --git a/src/wasm.h b/src/wasm.h @@ -253,6 +253,7 @@ struct func { struct functype *functype; enum func_type type; const char *name; + u32 idx; }; struct codesec { @@ -639,7 +640,7 @@ struct label { struct callframe { struct cursor code; struct val *locals; - u32 fn; + struct func *func; u16 prev_stack_items; };