protoverse

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

commit c15e6c39be19a657d59ae3b97af3005eb0f53991
parent 33f45476759ec8025c4b48498650b3431e807d8e
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 17 Jul 2021 17:26:17 -0700

fix builtin calls

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

Diffstat:
Msrc/cursor.h | 1-
Msrc/wasm.c | 252++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/wasm.h | 2+-
3 files changed, 180 insertions(+), 75 deletions(-)

diff --git a/src/cursor.h b/src/cursor.h @@ -179,7 +179,6 @@ static inline int pull_data_into_cursor(struct cursor *cursor, static inline unsigned char *cursor_top(struct cursor *cur, int len) { if (unlikely(cur->p - len < cur->start)) { - printf("cursor_top oob\n"); return NULL; } return cur->p - len; diff --git a/src/wasm.c b/src/wasm.c @@ -66,6 +66,22 @@ static const char *valtype_name(enum valtype valtype) return "?"; } +static const char *valtype_literal(enum valtype valtype) +{ + switch (valtype) { + case val_i32: return ""; + case val_i64: return "l"; + case val_f32: return ""; + case val_f64: return "f"; + case val_ref_null: return "null"; + case val_ref_func: return "func"; + case val_ref_extern: return "extern"; + } + + return "?"; +} + + static INLINE struct local *get_locals(struct func *func, int *num_locals) { switch (func->type) { @@ -111,8 +127,8 @@ static struct val *get_fn_local(struct wasm_interp *interp, int fn, int ind) } if (unlikely(ind >= num_locals)) { - interp_error(interp, "local index %d too high for %s (max %d)", - ind, func->name, num_locals-1); + interp_error(interp, "local index %d too high for %s:%d (max %d)", + ind, func->name, fn, num_locals-1); return NULL; } @@ -217,6 +233,43 @@ 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->i32); break; + case val_i64: printf("%llu", val->i64); break; + case val_f32: printf("%f", val->f32); break; + case val_f64: printf("%f", val->f64); break; + + case val_ref_null: + case val_ref_func: + case val_ref_extern: + break; + } + printf("%s", valtype_literal(val->type)); +} + +static void print_stack(struct cursor *stack) +{ + struct val val; + int i; + u8 *p = stack->p; + + if (stack->p == stack->start) { + printf("empty stack\n"); + return; + } + + for (i = 0; stack->p > stack->start; i++) { + cursor_popval(stack, &val); + printf("[%d] ", i); + print_val(&val); + printf("\n"); + } + + stack->p = p; +} + static int builtin_get_args(struct wasm_interp *interp) { struct val *argv, *argv_buf; @@ -227,12 +280,11 @@ static int builtin_get_args(struct wasm_interp *interp) if (!(argv_buf = get_local(interp, 1))) return interp_error(interp, "argv_buf"); - return 1; -} + print_stack(&interp->stack); -static int builtin_get_args_sizes(struct wasm_interp *interp) -{ - return interp_error(interp, "implement get_args_sizes"); + debug("get args %d %d\n", argv->i32, argv_buf->i32); + + return 1; } static INLINE int cursor_pushval(struct cursor *cur, struct val *val) @@ -240,11 +292,6 @@ static INLINE int cursor_pushval(struct cursor *cur, struct val *val) return cursor_push(cur, (u8*)val, sizeof(*val)); } -static INLINE int stack_pushval(struct wasm_interp *interp, struct val *val) -{ - return cursor_pushval(&interp->stack, val); -} - static INLINE int cursor_push_i32(struct cursor *stack, int i) { struct val val; @@ -259,16 +306,42 @@ static INLINE int stack_push_i32(struct wasm_interp *interp, int i) return cursor_push_i32(&interp->stack, i); } -/* -static int builtin_get_args_prep(struct wasm_interp *interp) + +static int builtin_get_args_sizes(struct wasm_interp *interp) { - return stack_push_i32(interp, 1) && stack_push_i32(interp, 2); + struct val *argc, *argv_buf_size; + + if (!(argc = get_local(interp, 0))) + return interp_error(interp, "argc"); + + if (!(argv_buf_size = get_local(interp, 1))) + return interp_error(interp, "argv_buf_size"); + + debug("get_args_sizes %d %d\n", argc->i32, argv_buf_size->i32); + + return stack_push_i32(interp, 0); +} + +static INLINE int stack_pushval(struct wasm_interp *interp, struct val *val) +{ + return cursor_pushval(&interp->stack, val); +} + +static int interp_exit(struct wasm_interp *interp) +{ + interp->quitting = 1; + return 0; +} + +static int builtin_proc_exit(struct wasm_interp *interp) +{ + return interp_exit(interp); } -*/ static struct builtin BUILTINS[] = { { .name = "args_get", .fn = builtin_get_args, .num_locals = 2 }, { .name = "args_sizes_get", .fn = builtin_get_args_sizes, .num_locals = 2 }, + { .name = "proc_exit", .fn = builtin_proc_exit, .num_locals = 2 }, }; static const int NUM_BUILTINS = sizeof(BUILTINS) / sizeof(*BUILTINS); @@ -434,22 +507,6 @@ static char *instr_name(enum instr_tag tag) return unk; } -static void print_val(struct val *val) -{ - switch (val->type) { - case val_i32: printf("%d:", val->i32); break; - case val_i64: printf("%llu:", val->i64); break; - case val_f32: printf("%f:", val->f32); break; - case val_f64: printf("%f:", val->f64); break; - - case val_ref_null: - case val_ref_func: - case val_ref_extern: - break; - } - printf("%s\n", valtype_name(val->type)); -} - static INLINE int was_section_parsed(struct module *module, enum section_tag section) { @@ -460,21 +517,6 @@ static INLINE int was_section_parsed(struct module *module, } -static void print_stack(struct cursor *stack) -{ - struct val val; - int i; - u8 *p = stack->p; - - for (i = 0; stack->p > stack->start; i++) { - cursor_popval(stack, &val); - printf("[%d] ", i); - print_val(&val); - } - - stack->p = p; -} - static INLINE int cursor_push_callframe(struct cursor *cur, struct callframe *frame) { return cursor_push(cur, (u8*)frame, sizeof(*frame)); @@ -1551,15 +1593,19 @@ static int parse_instrs_until(struct expr_parser *p, u8 stop_instr, *parsed_instrs = p->code->p; *instr_len = 0; + debug("parse_instrs_until starting\n"); for (;;) { if (!pull_byte(p->code, &tag)) return note_error(p->errs, p->code, "oob"); - if (!parse_instr(p, tag, &op)) + if (!parse_instr(p, tag, &op)) { return note_error(p->errs, p->code, - "parse %s instr (0x%x)", instr_name(tag), tag); + "parse %s instr (0x%x)", instr_name(tag), tag); + } - if (tag == stop_instr) { + if (tag == stop_instr || + (stop_instr == i_if && (tag == i_else || tag == i_end))) { + debug("parse_instrs_until ending\n"); *instr_len = p->code->p - *parsed_instrs; return 1; } @@ -2308,6 +2354,7 @@ static INLINE int set_fn_local(struct wasm_interp *interp, int fn, int ind, } memcpy(local, val, sizeof(*val)); + return 1; } @@ -2465,6 +2512,23 @@ static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *f return 1; } +static INLINE int call_builtin_func(struct wasm_interp *interp, struct builtin *builtin, int fn) +{ + struct callframe callframe = {0}; + + /* update current function and push it to the callframe as well */ + callframe.fn = fn; + + if (unlikely(!cursor_push_callframe(&interp->callframes, &callframe))) { + return interp_error(interp, "oob cursor_pushcode"); + } + + if (!builtin->fn(interp)) + return interp_error(interp, "builtin trap"); + + return cursor_pop_callframe(&interp->callframes, &callframe); +} + static INLINE int call_func(struct wasm_interp *interp, struct func *func, int fn) { switch (func->type) { @@ -2476,7 +2540,7 @@ static INLINE int call_func(struct wasm_interp *interp, struct func *func, int f "attempted to call unresolved fn: %s", func->name); } - return func->builtin->fn(interp); + return call_builtin_func(interp, func->builtin, fn); } return interp_error(interp, "corrupt func type: %02x", func->type); } @@ -2918,9 +2982,6 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) return parse_block(p, &op->blocks[0], i_end); case i_else: - return parse_block(p, &op->blocks[0], i_else) && - parse_block(p, &op->blocks[1], i_end); - case i_end: return 1; @@ -3077,7 +3138,8 @@ static int branch_jump(struct wasm_interp *interp, u8 end_tag) // consume instructions, use resolver stack to resolve jumps if (!parse_instrs_until(&parser, end_tag, &instrs, &instrs_len)) { - return interp_error(interp, "parse instrs"); + return interp_error(interp, "parse instrs end @ %s", + instr_name(end_tag)); } return pop_label_checkpoint(interp); @@ -3127,7 +3189,7 @@ static int interp_if(struct wasm_interp *interp) return 1; } - if (unlikely(!branch_jump(interp, i_end))) { + if (unlikely(!branch_jump(interp, i_if))) { return interp_error(interp, "jump"); } @@ -3555,28 +3617,66 @@ static int interp_memory_size(struct wasm_interp *interp) return 1; } +static int interp_i32_shl(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) { + return interp_error(interp, "gt_u prep"); + } + + c.i32 = lhs.i32 << rhs.i32; + + return stack_pushval(interp, &c); +} + +static void print_linestack(struct cursor *stack) +{ + struct val *val; + int first = 1; + + val = (struct val*)stack->p; + + while (--val >= (struct val*)stack->start) { + if (first) { + first = 0; + } else { + printf(", "); + } + print_val(val); + } + + printf("\n"); +} + static int interp_instr(struct wasm_interp *interp, u8 tag) { interp->ops++; - debug("%04lX %s\n", + debug("%04lX %s\t", interp_codeptr(interp)->p - 1 - interp_codeptr(interp)->start, - instr_name(tag)); + instr_name(tag) + ); + +#if DEBUG + print_linestack(&interp->stack); +#endif switch (tag) { case i_unreachable: return 1; - case i_nop: return 1; - case i_local_get: return interp_local_get(interp); - case i_local_set: return interp_local_set(interp); - case i_local_tee: return interp_local_tee(interp); - case i_global_get: return interp_global_get(interp); - case i_global_set: return interp_global_set(interp); - case i_i32_eqz: return interp_i32_eqz(interp); - case i_i32_add: return interp_i32_add(interp); - case i_i32_sub: return interp_i32_sub(interp); - case i_i32_const: return interp_i32_const(interp); - case i_i32_gt_u: return interp_i32_gt_u(interp); - case i_i32_lt_s: return interp_i32_lt_s(interp); + case i_nop: return 1; + case i_local_get: return interp_local_get(interp); + case i_local_set: return interp_local_set(interp); + case i_local_tee: return interp_local_tee(interp); + case i_global_get: return interp_global_get(interp); + case i_global_set: return interp_global_set(interp); + case i_i32_eqz: return interp_i32_eqz(interp); + case i_i32_add: return interp_i32_add(interp); + case i_i32_sub: return interp_i32_sub(interp); + case i_i32_const: return interp_i32_const(interp); + case i_i32_gt_u: return interp_i32_gt_u(interp); + case i_i32_lt_s: return interp_i32_lt_s(interp); + case i_i32_shl: return interp_i32_shl(interp); case i_i32_store: return interp_store(interp, val_i32, 0); case i_i32_store8: return interp_store(interp, val_i32, 8); @@ -3722,6 +3822,8 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module) global_init_size; memset(interp, 0, sizeof(*interp)); + + interp->quitting = 0; interp->module = module; interp->module->start_fn = -1; interp->prev_resolvers = 0; @@ -3883,6 +3985,10 @@ int interp_wasm_module(struct wasm_interp *interp) if (interp_code(interp)) { debug("interp success!!\n"); + } else if (interp->quitting) { + debug("finished running via process exit\n"); + } else { + return interp_error(interp, "interp_code"); } return 1; @@ -3905,9 +4011,9 @@ int run_wasm(unsigned char *wasm, unsigned long len) print_error_backtrace(&interp.errors); return 0; } - ok = interp_wasm_module(&interp); - print_error_backtrace(&interp.errors); - printf("ops: %ld\nstack:\n", interp.ops); + if (!interp_wasm_module(&interp)) { + print_error_backtrace(&interp.errors); + } print_stack(&interp.stack); wasm_interp_free(&interp); wasm_parser_free(&p); diff --git a/src/wasm.h b/src/wasm.h @@ -491,7 +491,7 @@ struct resolver { struct wasm_interp { struct module *module; - int prev_resolvers; + int prev_resolvers, quitting; struct errors errors; /* struct error */ size_t ops;