protoverse

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

commit 243e2da69a3139591441c3495637875794bb4d55
parent cf4664d5e2f2c2e3d14e018c247754fd894c08e9
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 18 Jul 2021 15:36:34 -0700

loops, fix br_if

Diffstat:
Msrc/cursor.h | 15+++++++++++++--
Msrc/wasm.c | 190++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/wasm.h | 2++
3 files changed, 155 insertions(+), 52 deletions(-)

diff --git a/src/cursor.h b/src/cursor.h @@ -49,7 +49,7 @@ static inline void make_array(struct array *a, u8* start, u8 *end, unsigned int static inline unsigned char *array_index(struct array *a, int ind) { - u8 *p = a->cur.start + a->elem_size * ind; + u8 *p = a->cur.start + a->elem_size * ind; if (unlikely(p >= a->cur.end)) { return NULL; } @@ -176,6 +176,17 @@ static inline int pull_data_into_cursor(struct cursor *cursor, } +static inline int cursor_drop(struct cursor *cur, int len) +{ + if (unlikely(cur->p - len < cur->start)) { + printf("cursor drop oob\n"); + return 0; + } + + cur->p -= len; + return 1; +} + static inline unsigned char *cursor_top(struct cursor *cur, int len) { if (unlikely(cur->p - len < cur->start)) { @@ -200,7 +211,7 @@ static inline int cursor_pop(struct cursor *cur, u8 *data, int len) printf("cursor_pop oob\n"); return 0; } - + cur->p -= len; memcpy(data, cur->p, len); diff --git a/src/wasm.c b/src/wasm.c @@ -2711,7 +2711,7 @@ static int prepare_call(struct wasm_interp *interp, int func_index) return 1; } -int interp_code(struct wasm_interp *interp); +static int interp_code(struct wasm_interp *interp); static int interp_call(struct wasm_interp *interp, int func_index) { @@ -2789,7 +2789,7 @@ static struct label *index_frame_label(struct wasm_interp *interp, int ind) return index_label(&interp->labels, frame->fn, ind); } -static int resolve_label(struct label *label, struct cursor *code) +static INLINE int resolve_label(struct label *label, struct cursor *code) { if (is_label_resolved(label)) { return 1; @@ -2907,15 +2907,22 @@ static INLINE int cursor_push_resolver(struct cursor *stack, struct resolver *re return cursor_push(stack, (u8*)resolver, sizeof(*resolver)); } +struct tag_info { + u8 flags; + u8 end_tag; +}; + // when we encounter a control instruction, try to resolve the label, otherwise // push the label index to the resolver stack for resolution later -static int push_label_checkpoint(struct wasm_interp *interp, struct label **label, u8 end_tag) +static int push_label_checkpoint(struct wasm_interp *interp, struct label **label, + u8 start_tag, u8 end_tag) { u32 instr_pos; int ind, fns; struct resolver resolver; struct callframe *frame; + resolver.start_tag = start_tag; resolver.end_tag = end_tag; resolver.label = 0; @@ -2972,6 +2979,11 @@ static int interp_jump(struct wasm_interp *interp, int jmp) return 1; } +static INLINE int jump_to_label(struct wasm_interp *interp, struct label *label) +{ + return interp_jump(interp, label->jump); +} + static int pop_label_and_jump(struct wasm_interp *interp, int jump) { if (!pop_label_checkpoint(interp)) @@ -2980,7 +2992,7 @@ static int pop_label_and_jump(struct wasm_interp *interp, int jump) return interp_jump(interp, jump); } -static int parse_block(struct expr_parser *p, struct block *block, u8 end_tag) +static int parse_block(struct expr_parser *p, struct block *block, u8 start_tag, u8 end_tag) { struct label *label = NULL; @@ -2989,7 +3001,7 @@ static int parse_block(struct expr_parser *p, struct block *block, u8 end_tag) // if we don't have an interpreter instance, we don't care about // label resolution (NOT TRUE ANYMORE!) - if (p->interp != NULL && !push_label_checkpoint(p->interp, &label, i_end)) + if (p->interp != NULL && !push_label_checkpoint(p->interp, &label, start_tag, i_end)) return note_error(p->errs, p->code, "push checkpoint"); if (label && is_label_resolved(label)) { @@ -3023,11 +3035,10 @@ static INLINE int parse_memarg(struct cursor *code, struct memarg *memarg) static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) { - /* - debug("%04lX parsing instr %s (0x%02x)\n", - p->code->p - 1 - p->code->start, instr_name(tag), tag); - */ + /*debug("%04lX parsing instr %s (0x%02x)\n", + p->code->p - 1 - p->code->start, instr_name(tag), tag);*/ + op->pos = p->code->p - 1 - p->code->start; op->tag = tag; switch (tag) { @@ -3037,9 +3048,11 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) return pull_byte(p->code, &op->memidx); case i_block: + return parse_block(p, &op->block, i_block, i_end); case i_loop: + return parse_block(p, &op->block, i_loop, i_end); case i_if: - return parse_block(p, &op->block, i_end); + return parse_block(p, &op->block, i_if, i_end); case i_else: case i_end: @@ -3228,14 +3241,14 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) return note_error(p->errs, p->code, "unhandled tag: 0x%x", tag); } -static int branch_jump(struct wasm_interp *interp, u8 end_tag) +static int branch_jump(struct wasm_interp *interp, u8 start_tag, u8 end_tag) { u8 *instrs; int instrs_len; struct expr_parser parser; struct label *label; - if (!push_label_checkpoint(interp, &label, end_tag)) { + if (!push_label_checkpoint(interp, &label, start_tag, end_tag)) { return interp_error(interp, "label checkpoint"); } @@ -3273,7 +3286,7 @@ static int interp_block(struct wasm_interp *interp) return interp_error(interp, "couldn't parse blocktype"); } - if (unlikely(!push_label_checkpoint(interp, &label, i_end))) { + if (unlikely(!push_label_checkpoint(interp, &label, i_block, i_end))) { return interp_error(interp, "block label checkpoint"); } @@ -3302,7 +3315,7 @@ static int interp_if(struct wasm_interp *interp) return 1; } - if (unlikely(!branch_jump(interp, i_if))) { + if (unlikely(!branch_jump(interp, i_if, i_if))) { return interp_error(interp, "jump"); } @@ -3322,25 +3335,42 @@ static int interp_i32_eqz(struct wasm_interp *interp) return cursor_pushval(&interp->stack, &res); } -static INLINE int top_resolver_stack(struct cursor *stack, int index, struct resolver **resolver) +static INLINE struct resolver *top_resolver_stack(struct cursor *stack, int index) { struct resolver *p = (struct resolver*)stack->p; p = &p[-(index+1)]; if (p < (struct resolver*)stack->start) - return 0; - *resolver = p; - return 1; + return NULL; + return p; +} + +static INLINE struct resolver *top_resolver(struct wasm_interp *interp, int index) +{ + return top_resolver_stack(&interp->resolver_stack, index); +} + +static INLINE struct label *top_label(struct wasm_interp *interp, int index) +{ + struct resolver *resolver; + + if (unlikely(!(resolver = top_resolver(interp, index)))) { + interp_error(interp, "invalid resolver index %d", index); + return NULL; + } + + return index_frame_label(interp, resolver->label); } static int unresolved_break(struct wasm_interp *interp, int index) { struct expr_parser parser; - struct resolver *resolver; struct callframe *frame; struct label *label; u8 *instrs; int instrs_len; + struct resolver *resolver; + debug("breaking %d times from unresolved label\n", index+1); make_interp_expr_parser(interp, &parser); if (unlikely(!(frame = top_callframe(&interp->callframes)))) { @@ -3348,21 +3378,16 @@ static int unresolved_break(struct wasm_interp *interp, int index) } while (index-- >= 0) { - if (unlikely(!top_resolver_stack(&interp->resolver_stack, 0, - &resolver))) { + if (unlikely(!(resolver = top_resolver(interp, 0)))) { return interp_error(interp, "invalid resolver index %d", - index); + index); } - debug("unresolved break index %d, ends at i_%s\n", index, - instr_name(resolver->end_tag)); - - // TODO: breaking from functions (return) - if (unlikely(!(label = index_label(&interp->labels, frame->fn, - resolver->label)))) { + if (unlikely(!(label = index_frame_label(interp, resolver->label)))) { return interp_error(interp, "no label"); } + // TODO: breaking from functions (return) if (is_label_resolved(label)) { return pop_label_and_jump(interp, label->jump); } @@ -3383,18 +3408,13 @@ static int unresolved_break(struct wasm_interp *interp, int index) static int interp_br_jump(struct wasm_interp *interp, int index) { struct label *label; - struct resolver *resolver = NULL; - - if (unlikely(!top_resolver_stack(&interp->resolver_stack, index, &resolver))) { - return interp_error(interp, "invalid resolver index %d", index); - } - if (unlikely(!(label = index_frame_label(interp, resolver->label)))) { - return interp_error(interp, "index label"); + if (unlikely(!(label = top_label(interp, index)))) { + return interp_error(interp, "no label?"); } if (is_label_resolved(label)) { - return interp_jump(interp, label->jump); + return pop_label_and_jump(interp, label->jump); } return unresolved_break(interp, index); @@ -4052,13 +4072,38 @@ static int interp_extend(struct wasm_interp *interp, enum valtype to, return 1; } +static INLINE int interp_drop(struct wasm_interp *interp) +{ + return cursor_drop(&interp->stack, sizeof(struct val)); +} + +static int interp_loop(struct wasm_interp *interp) +{ + struct blocktype blocktype; + struct cursor *code; + struct label *label; + + if (unlikely(!(code = interp_codeptr(interp)))) { + return interp_error(interp, "empty callstack?"); + } + + if (unlikely(!parse_blocktype(code, &interp->errors, &blocktype))) { + return interp_error(interp, "couldn't parse blocktype"); + } + + if (unlikely(!push_label_checkpoint(interp, &label, i_loop, i_end))) { + return interp_error(interp, "block label checkpoint"); + } + + return 1; +} + + static int interp_instr(struct wasm_interp *interp, struct instr *instr) { interp->ops++; - debug("%04lX %-30s | ", - interp_codeptr(interp)->p - 1 - interp_codeptr(interp)->start, - show_instr(instr)); + debug("%04X %-30s | ", instr->pos, show_instr(instr)); #if DEBUG print_linestack(&interp->stack); @@ -4118,6 +4163,8 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) case i_i64_load32_s: return interp_load(interp, &instr->memarg, val_i64, 32, 1); case i_i64_load32_u: return interp_load(interp, &instr->memarg, val_i64, 32, 0); + case i_drop: return interp_drop(interp); + case i_loop: return interp_loop(interp); case i_if: return interp_if(interp); case i_end: return pop_label_checkpoint(interp); case i_call: return interp_call(interp, instr->integer); @@ -4148,33 +4195,59 @@ static int is_control_instr(u8 tag) return 0; } -int interp_code(struct wasm_interp *interp) + +static INLINE int interp_parse_instr(struct wasm_interp *interp, + struct cursor *code, struct expr_parser *parser, + struct instr *instr) +{ + u8 tag; + + if (unlikely(!pull_byte(code, &tag))) { + return interp_error(interp, "no more instrs to pull"); + } + + instr->tag = tag; + + if (is_control_instr(tag)) { + debug("control instr %s\n", instr_name(tag)); + } else if (!parse_instr(parser, instr->tag, instr)) { + return interp_error(interp, "parse instr"); + } + + return 1; +} + +static int interp_code(struct wasm_interp *interp) { int offset, num_resolvers = 0; - struct cursor *code; struct instr instr; struct expr_parser parser; - u8 tag; + struct resolver *resolver; + struct label *label; + struct cursor *code; + struct callframe *frame; make_interp_expr_parser(interp, &parser); + if (unlikely(!(frame = top_callframe(&interp->callframes)))) { + return interp_error(interp, "no callframe"); + } + for (;;) { if (unlikely(!(code = interp_codeptr(interp)))) { return interp_error(interp, "codeptr"); } - if (unlikely(!pull_byte(code, &tag))) { - return interp_error(interp, "no more instrs to pull"); - } - - instr.tag = tag; - - if (!is_control_instr(instr.tag) && - !parse_instr(&parser, instr.tag, &instr)) { + if (unlikely(!interp_parse_instr(interp, code, &parser, &instr))) { return interp_error(interp, "parse instr"); } if (instr.tag == i_end) { + if (unlikely(!(resolver = top_resolver(interp, 0)))) { + // no more resolvers, we done. + return 1; + } + if (unlikely(!count_local_resolvers(interp, &num_resolvers))) { return interp_error(interp, @@ -4189,6 +4262,23 @@ int interp_code(struct wasm_interp *interp) } break; } + + // if we hit the end of a loop, continue at the start + if (resolver && resolver->start_tag == i_loop) { + if (unlikely(!(label = + index_label(&interp->labels, frame->fn, + resolver->label)))) { + return interp_error(interp, "no loop label?"); + } + + resolve_label(label, code); + + if (!interp_jump(interp, label_instr_pos(label))) { + return interp_error(interp, "jump to loop label"); + } + + continue; + } } if (unlikely(!interp_instr(interp, &instr))) { diff --git a/src/wasm.h b/src/wasm.h @@ -476,6 +476,7 @@ struct memarg { struct instr { enum instr_tag tag; + int pos; union { struct memarg memarg; struct block block; @@ -551,6 +552,7 @@ struct callframe { struct resolver { u16 label; u8 end_tag; + u8 start_tag; unsigned char unused; };