protoverse

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

commit ac22c121184c6ad6329ce449e1bcdc6c44138622
parent 6d5354ef9d578eea5005d93eceda11f967a5ee52
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 14 Jul 2021 09:13:44 -0700

setup interpreter to be run many times

Diffstat:
Msrc/bench.c | 9++++-----
Msrc/cursor.h | 6++++++
Msrc/wasm.c | 141++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/wasm.h | 5+++--
4 files changed, 96 insertions(+), 65 deletions(-)

diff --git a/src/bench.c b/src/bench.c @@ -20,13 +20,12 @@ static int bench_wasm(unsigned char *wasm, unsigned long len, int times) return 0; } - wasm_interp_init(&interp); + wasm_interp_init(&interp, &p.module); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t1); for (i = 0; i < times; i++) { - if (!interp_wasm_module(&interp, &p.module)) { - printf("bench: interp_wasm_module failed\n"); - break; + if (!interp_wasm_module(&interp)) { + //print_error_backtrace(&interp.errors); } ops += interp.ops; } @@ -35,7 +34,7 @@ static int bench_wasm(unsigned char *wasm, unsigned long len, int times) nanos = (t2.tv_sec - t1.tv_sec) * (long)1e9 + (t2.tv_nsec - t1.tv_nsec); ms = nanos / 1e6; printf("ns/run\t%ld\nms/run\t%f\nns\t%ld\nms\t%ld\nops\t%d\nns/op\t%ld\n", - nanos/times, (double)ms/(double)times, nanos, ms, ops, nanos/ops); + nanos/times, (double)ms/(double)times, nanos, ms, ops, nanos/(ops+1)); wasm_interp_free(&interp); wasm_parser_free(&p); diff --git a/src/cursor.h b/src/cursor.h @@ -6,6 +6,7 @@ #include "varint.h" #include <stdio.h> +#include <assert.h> #include <string.h> #define unlikely(x) __builtin_expect((x),0) @@ -21,6 +22,11 @@ struct array { unsigned int elem_size; }; +static inline void reset_cursor(struct cursor *cursor) +{ + cursor->p = cursor->start; +} + static inline void make_cursor(u8 *start, u8 *end, struct cursor *cursor) { cursor->start = start; diff --git a/src/wasm.c b/src/wasm.c @@ -295,7 +295,7 @@ static inline int offset_stack_top(struct cursor *cur) return *(p - sizeof(*p)); } -static void print_error_backtrace(struct cursor *errors) +void print_error_backtrace(struct cursor *errors) { struct cursor errs; struct error err; @@ -1872,7 +1872,7 @@ static inline int interp_i32_gt_u(struct wasm_interp *interp) return 0; } - c.i32 = (unsigned int)b.i32 > (unsigned int)a.i32; + c.i32 = (unsigned int)b.i32 > (unsigned int)a.i32; return cursor_pushval(&interp->stack, &c); } @@ -2118,8 +2118,11 @@ static int resolve_label(struct wasm_interp *interp) label = index_label(&interp->labels, frame->fn, label_ind); assert(label); - assert(!label_is_resolved(label)); + if (label_is_resolved(label)) { + debug("label %d is already resolved\n", label_ind); + return 1; + } label->jump = frame->code.p - frame->code.start; label->instr_pos |= 0x80000000; @@ -2209,9 +2212,6 @@ static int upsert_label(struct wasm_interp *interp, int fn, num_labels = func_num_labels(interp, fn); - debug("upsert_label: %d labels for %s\n", - *num_labels, get_function_name(interp->module, fn)); - if (*num_labels > 0 && ((*ind = find_label(interp, fn, instr_pos)) == 0)) { // we already have the label return 1; @@ -2223,6 +2223,9 @@ static int upsert_label(struct wasm_interp *interp, int fn, return 0; } + debug("upsert_label: %d labels for %s\n", + *num_labels, get_function_name(interp->module, fn)); + *ind = *num_labels; label = index_label(&interp->labels, fn, *ind); assert(label); @@ -2234,7 +2237,7 @@ static int upsert_label(struct wasm_interp *interp, int fn, } -static int label_checkpoint(struct wasm_interp *interp) +static int label_checkpoint(struct wasm_interp *interp, int *jumped) { u32 instr_pos; int ind; @@ -2243,6 +2246,8 @@ static int label_checkpoint(struct wasm_interp *interp) struct label *label; struct callframe *frame; + *jumped = 0; + fns = functions_count(interp->module); frame = top_callframe(&interp->callframes); @@ -2267,10 +2272,13 @@ static int label_checkpoint(struct wasm_interp *interp) if (label_is_resolved(label)) { frame->code.p = frame->code.start + label->jump; + debug("label is resolved, jumping to %04lX\n", + frame->code.p - frame->code.start); if (frame->code.p >= frame->code.end) { interp_error(interp, "code pointer at or past end, evil jump?"); return 0; } + *jumped = 1; return 1; } @@ -2287,8 +2295,7 @@ static int label_checkpoint(struct wasm_interp *interp) static int parse_block(struct wasm_interp *interp, struct block *block, u8 end_tag) { struct cursor *code; - - debug("parsing block"); + int jumped; if (!(code = interp_codeptr(interp))) { interp_error(interp, "codeptr"); @@ -2300,7 +2307,7 @@ static int parse_block(struct wasm_interp *interp, struct block *block, u8 end_t return 0; } - if (!label_checkpoint(interp)) { + if (!label_checkpoint(interp, &jumped)) { interp_error(interp, "checkpoint"); return 0; } @@ -2323,7 +2330,7 @@ static inline int parse_memarg(struct cursor *code, struct memarg *memarg) static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op) { struct cursor *code; - + if (!(code = interp_codeptr(interp))) { interp_error(interp, "codeptr"); return 0; @@ -2483,12 +2490,17 @@ static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op) static int branch_jump(struct wasm_interp *interp, u8 end_tag) { struct cursor instrs; + int jumped; - if (!label_checkpoint(interp)) { + if (!label_checkpoint(interp, &jumped)) { interp_error(interp, "label checkpoint"); return 0; } + if (jumped) { + return 1; + } + // consume instructions, use resolver stack to resolve jumps if (!parse_instrs_until(interp, end_tag, &instrs)) { interp_error(interp, "parse instrs"); @@ -2592,10 +2604,6 @@ int interp_code(struct wasm_interp *interp) return 1; } -#define STACK_SPACE 5242880 -#define MEM_SPACE 5242880 -#define LOCALS_SPACE 5242880 - static int find_function(struct module *module, const char *name) { struct wexport *export; @@ -2638,19 +2646,57 @@ void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t a cursor_slice(&p->mem, &p->errs, 0xFFFF); } -void wasm_interp_init(struct wasm_interp *interp) +void wasm_interp_init(struct wasm_interp *interp, struct module *module) { - static unsigned char *stack, *mem; + unsigned char *mem; + int ok, fns, errors_size, stack_size, locals_size, offsets_size, + callframes_size, resolver_size, labels_size, num_labels_size, + labels_capacity, num_labels_elemsize, memsize; - interp->ops = 0; + memset(interp, 0, sizeof(*interp)); + interp->module = module; + + //stack = calloc(1, STACK_SPACE); + fns = functions_count(module); + labels_capacity = fns * MAX_LABELS; + num_labels_elemsize = sizeof(u16); + + errors_size = 0xFFFF; + stack_size = 0xFFFF; + labels_size = labels_capacity * sizeof(struct label); + num_labels_size = fns * num_labels_elemsize; + locals_size = sizeof(struct val) * NUM_LOCALS; + offsets_size = sizeof(int) * 255; + callframes_size = sizeof(struct callframe) * 255; + resolver_size = sizeof(u16) * MAX_LABELS; + + interp->labels.elem_size = sizeof(struct label); + interp->num_labels.elem_size = num_labels_elemsize; - stack = calloc(1, STACK_SPACE); - mem = calloc(1, MEM_SPACE); + memsize = + errors_size + + stack_size + + labels_size + + num_labels_size + + locals_size + + offsets_size + + callframes_size + + resolver_size; - make_cursor(stack, stack + STACK_SPACE, &interp->stack); - make_cursor(mem, mem + MEM_SPACE, &interp->mem); + mem = calloc(1, memsize); + make_cursor(mem, mem + memsize, &interp->mem); + + ok = + cursor_slice(&interp->mem, &interp->stack, stack_size) && + cursor_slice(&interp->mem, &interp->errors, errors_size) && + cursor_slice(&interp->mem, &interp->locals, locals_size) && + cursor_slice(&interp->mem, &interp->locals_offsets, offsets_size) && + cursor_slice(&interp->mem, &interp->callframes, callframes_size) && + cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size) && + array_alloc(&interp->mem, &interp->labels, labels_capacity) && + array_alloc(&interp->mem, &interp->num_labels, fns); - cursor_slice(&interp->mem, &interp->errors, 0xFFFF); + assert(ok); } void wasm_parser_free(struct wasm_parser *parser) @@ -2660,52 +2706,31 @@ void wasm_parser_free(struct wasm_parser *parser) void wasm_interp_free(struct wasm_interp *interp) { - free(interp->stack.start); free(interp->mem.start); } -static int alloc_labels(struct wasm_interp *interp, int fns) +int interp_wasm_module(struct wasm_interp *interp) { - const int capacity = fns * MAX_LABELS; - - interp->labels.elem_size = sizeof(struct label); - interp->num_labels.elem_size = sizeof(u16); + int ok, func; - return array_alloc(&interp->mem, &interp->labels, capacity) && - array_alloc(&interp->mem, &interp->num_labels, fns); - -} - -int interp_wasm_module(struct wasm_interp *interp, struct module *module) -{ - int ok, func, fns; - - interp->module = module; interp->ops = 0; - if (module->code_section.num_funcs == 0) { + if (interp->module->code_section.num_funcs == 0) { interp_error(interp, "empty module"); return 0; } // reset cursors - interp->stack.p = interp->stack.start; - interp->errors.p = interp->errors.start; - interp->mem.p = interp->mem.start; + reset_cursor(&interp->stack); + reset_cursor(&interp->errors); + reset_cursor(&interp->locals); + reset_cursor(&interp->locals_offsets); + reset_cursor(&interp->callframes); + // don't reset labels for perf! - fns = functions_count(module); - - ok = - cursor_slice(&interp->mem, &interp->locals, - sizeof(struct val) * NUM_LOCALS) && - cursor_slice(&interp->mem, &interp->locals_offsets, sizeof(int) * 255) && - cursor_slice(&interp->mem, &interp->callframes, sizeof(struct callframe) * 255) && - cursor_slice(&interp->mem, &interp->resolver_stack, sizeof(u32) * MAX_LABELS) && - alloc_labels(interp, fns); - - assert(ok); + //interp->mem.p = interp->mem.start; - func = find_start_function(module); + func = find_start_function(interp->module); if (func == -1) { interp_error(interp, "no start function found"); ok = 0; @@ -2740,8 +2765,8 @@ int run_wasm(unsigned char *wasm, unsigned long len) return 0; } - wasm_interp_init(&interp); - ok = interp_wasm_module(&interp, &p.module); + wasm_interp_init(&interp, &p.module); + ok = interp_wasm_module(&interp); print_error_backtrace(&interp.errors); printf("ops: %ld\nstack:\n", interp.ops); print_stack(&interp.stack); diff --git a/src/wasm.h b/src/wasm.h @@ -446,10 +446,11 @@ struct wasm_parser { int run_wasm(unsigned char *wasm, unsigned long len); int parse_wasm(struct wasm_parser *p); -void wasm_interp_init(struct wasm_interp *interp); +void wasm_interp_init(struct wasm_interp *interp, struct module *module); void wasm_parser_free(struct wasm_parser *parser); void wasm_parser_init(struct wasm_parser *parser, u8 *wasm, size_t wasm_len, size_t arena_size); void wasm_interp_free(struct wasm_interp *interp); -int interp_wasm_module(struct wasm_interp *interp, struct module *module); +int interp_wasm_module(struct wasm_interp *interp); +void print_error_backtrace(struct cursor *errors); #endif /* PROTOVERSE_WASM_H */