protoverse

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

commit 4b5d61d3d8685edd135c268bb7d85972cbe48a50
parent 78e56aa88a5ce28025eb1399284aa6019dc69807
Author: William Casarin <jb55@jb55.com>
Date:   Fri, 16 Jul 2021 23:49:49 -0700

memory sizes

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

Diffstat:
Msrc/bench.c | 5++++-
Msrc/wasm.c | 107++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/wasm.h | 3++-
3 files changed, 104 insertions(+), 11 deletions(-)

diff --git a/src/bench.c b/src/bench.c @@ -20,7 +20,10 @@ static int bench_wasm(unsigned char *wasm, unsigned long len, int times) return 0; } - wasm_interp_init(&interp, &p.module); + if (!wasm_interp_init(&interp, &p.module)) { + print_error_backtrace(&interp.errors); + return 0; + } interp.errors.enabled = 0; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t1); diff --git a/src/wasm.c b/src/wasm.c @@ -395,6 +395,11 @@ static void print_stack(struct cursor *stack) stack->p = p; } +static INLINE int cursor_push_cursor(struct cursor *cur, struct cursor *push) +{ + return cursor_push(cur, (u8*)push, sizeof(*push)); +} + static INLINE int cursor_push_callframe(struct cursor *cur, struct callframe *frame) { return cursor_push(cur, (u8*)frame, sizeof(*frame)); @@ -2110,8 +2115,6 @@ static int make_func_lookup_table(struct wasm_parser *parser) func->wasm_func = &parser->module.code_section.funcs[i]; func->functype = &parser->module.type_section.functypes[typeidx]; func->name = find_exported_function_name(&parser->module, fn); - debug("func %s, %d params\n", func->name, - func->functype->params.num_valtypes); } assert(fn == parser->module.num_funcs); @@ -2864,7 +2867,10 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) case i_br_if: case i_i32_const: case i_i64_const: - return leb128_read(p->code, &op->integer); + if (unlikely(!leb128_read(p->code, &op->integer))) { + return note_error(p->errs, p->code, "failed to read integer"); + } + return 1; case i_f32_const: case i_f64_const: @@ -3178,6 +3184,34 @@ static int interp_global_get(struct wasm_interp *interp) return 1; } +static int interp_memory_size(struct wasm_interp *interp) +{ + struct limits *mem; + struct cursor *code; + u8 memidx; + + if (unlikely(!(code = interp_codeptr(interp)))) { + return interp_error(interp, "codeptr"); + } + + if (unlikely(!was_section_parsed(interp->module, section_memory) || + interp->module->memory_section.num_mems == 0)) { + return interp_error(interp, "no memory sections"); + } + + mem = &interp->module->memory_section.mems[0]; + + if (!stack_push_i32(interp, mem->max / 65536)) { + return interp_error(interp, "push memory size"); + } + + if (!pull_byte(code, &memidx)) { + return interp_error(interp, "memidx"); + } + + return 1; +} + static int interp_instr(struct wasm_interp *interp, u8 tag) { interp->ops++; @@ -3203,6 +3237,7 @@ static int interp_instr(struct wasm_interp *interp, u8 tag) case i_call: return interp_call(interp); case i_block: return interp_block(interp); case i_br_if: return interp_br_if(interp); + case i_memory_size: return interp_memory_size(interp); default: interp_error(interp, "unhandled instruction %s 0x%x", instr_name(tag), tag); @@ -3304,12 +3339,15 @@ void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t a cursor_slice(&p->mem, &p->errs.cur, 0xFFFF); } -void wasm_interp_init(struct wasm_interp *interp, struct module *module) +int wasm_interp_init(struct wasm_interp *interp, struct module *module) { unsigned char *mem; - int ok, fns, errors_size, stack_size, locals_size, offsets_size, + struct limits *mem_limits; + struct cursor mem_inst; + int i, 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, resolver_offsets_size; + labels_capacity, num_labels_elemsize, memsize, num_mem_sizes, + resolver_offsets_size, num_mems, mems_cursor_sizes; memset(interp, 0, sizeof(*interp)); interp->module = module; @@ -3331,10 +3369,28 @@ void wasm_interp_init(struct wasm_interp *interp, struct module *module) resolver_offsets_size = offsets_size; callframes_size = sizeof(struct callframe) * 0xFF; resolver_size = sizeof(struct resolver) * MAX_LABELS; + mems_cursor_sizes = 0; + + num_mems = was_section_parsed(interp->module, section_memory)? + interp->module->memory_section.num_mems : 0; interp->labels.elem_size = sizeof(struct label); interp->num_labels.elem_size = num_labels_elemsize; + /* memory sizes */ + num_mem_sizes = 0; + for (i = 0; i < num_mems; i++) { + mem_limits = &interp->module->memory_section.mems[i]; + if (mem_limits->type == limit_min) { + debug("min mems push %d\n", mem_limits->min); + num_mem_sizes += mem_limits->min; + } else { + debug("max mems push %d\n", mem_limits->max); + num_mem_sizes += mem_limits->max; + } + mems_cursor_sizes += sizeof(struct cursor); + } + memsize = errors_size + stack_size + @@ -3344,6 +3400,8 @@ void wasm_interp_init(struct wasm_interp *interp, struct module *module) offsets_size + resolver_offsets_size + callframes_size + + num_mem_sizes + + mems_cursor_sizes + resolver_size; mem = calloc(1, memsize); @@ -3358,10 +3416,30 @@ void wasm_interp_init(struct wasm_interp *interp, struct module *module) 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) && + cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size) && + cursor_slice(&interp->mem, &interp->mems, mems_cursor_sizes) && array_alloc(&interp->mem, &interp->labels, labels_capacity) && array_alloc(&interp->mem, &interp->num_labels, fns); - assert(ok); + if (!ok) { + return interp_error(interp, "not enough memory 1"); + } + + /* memory instances */ + num_mem_sizes = 0; + for (i = 0; i < num_mems; i++) { + mem_limits = &interp->module->memory_section.mems[i]; + ok = ok && cursor_slice(&interp->mem, &mem_inst, mem_limits->max); + if (!ok || !cursor_push_cursor(&interp->mems, &mem_inst)) { + return interp_error(interp, "push mems cursor"); + } + } + + if (!ok) { + return interp_error(interp, "not enough memory"); + } + + return 1; } void wasm_parser_free(struct wasm_parser *parser) @@ -3376,7 +3454,8 @@ void wasm_interp_free(struct wasm_interp *interp) int interp_wasm_module(struct wasm_interp *interp) { - int func; + int func, mems, i; + struct cursor *cursor; interp->ops = 0; @@ -3391,6 +3470,13 @@ int interp_wasm_module(struct wasm_interp *interp) reset_cursor(&interp->resolver_offsets); reset_cursor(&interp->errors.cur); reset_cursor(&interp->callframes); + + mems = cursor_count(&interp->mems, sizeof(struct cursor)); + for (i = 0; i < mems; i++) { + cursor = &((struct cursor*)&interp->mems.p)[i]; + reset_cursor(cursor); + } + // don't reset labels for perf! //interp->mem.p = interp->mem.start; @@ -3431,7 +3517,10 @@ int run_wasm(unsigned char *wasm, unsigned long len) return 0; } - wasm_interp_init(&interp, &p.module); + if (!wasm_interp_init(&interp, &p.module)) { + print_error_backtrace(&interp.errors); + return 0; + } ok = interp_wasm_module(&interp); print_error_backtrace(&interp.errors); printf("ops: %ld\nstack:\n", interp.ops); diff --git a/src/wasm.h b/src/wasm.h @@ -501,6 +501,7 @@ struct wasm_interp { struct cursor stack; /* struct val */ struct cursor mem; /* u8/mixed */ struct cursor resolver_offsets; /* int */ + struct cursor mems; /* struct cursor, memory instance blocks */ struct array labels; /* struct labels */ struct array num_labels; @@ -529,7 +530,7 @@ 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, struct module *module); +int 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);