protoverse

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

commit c5c6d4645ec00158de1ab291694701b957e3c6c0
parent 5d9ea066ea725c396c19fbe0cc55da03b5916027
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 15 Jul 2021 09:15:33 -0700

initial element section parsing

Diffstat:
Msrc/wasm.c | 268+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/wasm.h | 23+++++++++++++----------
2 files changed, 173 insertions(+), 118 deletions(-)

diff --git a/src/wasm.c b/src/wasm.c @@ -29,6 +29,14 @@ struct val { }; }; +struct expr_parser { + struct wasm_interp *interp; // optional... + struct cursor *code; + struct cursor *errs; +}; + +static int parse_instr(struct expr_parser *parser, u8 tag, struct instr *op); + static inline struct callframe *top_callframe(struct cursor *cur) { if (cur->p <= cur->start) { @@ -1204,14 +1212,118 @@ static int parse_global_section(struct wasm_parser *p, return 1; } +static inline void make_interp_expr_parser(struct wasm_interp *interp, + struct expr_parser *p) +{ + assert(interp); + + p->interp = interp; + p->code = interp_codeptr(interp); + p->errs = &interp->errors; + + assert(p->code); +} + +static inline void make_expr_parser(struct cursor *errs, struct cursor *code, + struct expr_parser *p) +{ + p->interp = NULL; + p->code = code; + p->errs = errs; +} + +static int parse_instrs_until(struct expr_parser *p, u8 stop_instr, + struct cursor *parsed_instrs) +{ + u8 tag; + struct instr op; + + parsed_instrs->start = p->code->p; + parsed_instrs->p = p->code->p; + + for (;;) { + if (!pull_byte(p->code, &tag)) + return note_error(p->errs, p->code, "oob"); + + if (!parse_instr(p, tag, &op)) + return note_error(p->errs, p->code, + "parse %s instr (0x%x)", instr_name(tag), tag); + + if (tag == stop_instr) { + parsed_instrs->end = p->code->p; + return 1; + } + } +} + +static int parse_expr(struct wasm_parser *p, struct expr *expr) +{ + struct expr_parser parser; + struct cursor code; + + make_expr_parser(&p->errs, &p->cur, &parser); + + if (!parse_instrs_until(&parser, i_end, &code)) + return parse_err(p, "instrs"); + + expr->code = code.start; + expr->code_len = code.end - code.start; + + return 1; +} + +static int parse_element(struct wasm_parser *p, struct elem *elem) +{ + u8 tag = 0; + (void)elem; + + if (!pull_byte(&p->cur, &tag)) + return parse_err(p, "tag"); + + if (tag > 7) + return parse_err(p, "expected tag 0x00 to 0x07, got 0x%02x", tag); + + switch (tag) { + case 0x00: + if (!parse_expr(p, &elem->offset)) + return parse_err(p, "elem 0x00 offset expr"); + + if (!parse_vector(p, + sizeof(*elem->func_indices), + &elem->num_func_indices, + (void**)&elem->func_indices)) + return parse_err(p, "elem 0x00 func indices"); + + elem->mode = elem_mode_active; + elem->tableidx = 0; + elem->reftype = funcref; + break; + + default: + return parse_err(p, "implement parse element 0x%02x", tag); + } + + return 1; +} + + static int parse_element_section(struct wasm_parser *p, struct elemsec *elemsec) { - struct element *elements; - unsigned int count; + struct elem *elements; + unsigned int count, i; - if (!parse_vector(p, sizeof(struct elem), &count, (void**)&elements)) { + if (!parse_vector(p, sizeof(struct elem), &count, (void**)&elements)) return parse_err(p, "elements vec"); + + for (i = 0; i < count; i++) { + if (!parse_element(p, &elements[i])) + return parse_err(p, "element %d/%d", i+1, count); } + + elemsec->num_elements = count; + elemsec->elements = elements; + + return 1; } static int parse_memory_section(struct wasm_parser *p, @@ -1528,70 +1640,62 @@ static int parse_section_by_tag(struct wasm_parser *p, enum section_tag tag, return 0; case section_type: if (!parse_type_section(p, &p->module.type_section)) { - parse_err(p, "type section"); - return 0; + return parse_err(p, "type section"); } return 1; case section_import: if (!parse_import_section(p, &p->module.import_section)) { - parse_err(p, "import section"); - return 0; + return parse_err(p, "import section"); } return 1; case section_function: if (!parse_function_section(p, &p->module.func_section)) { - parse_err(p, "function section"); - return 0; + return parse_err(p, "function section"); } return 1; case section_table: if (!parse_table_section(p, &p->module.table_section)) { - parse_err(p, "table section"); - return 0; + return parse_err(p, "table section"); } return 1; case section_memory: if (!parse_memory_section(p, &p->module.memory_section)) { - parse_err(p, "memory section"); - return 0; + return parse_err(p, "memory section"); } return 1; case section_global: if (!parse_global_section(p, &p->module.global_section)) { - parse_err(p, "global section"); - return 0; + return parse_err(p, "global section"); } return 1; case section_export: if (!parse_export_section(p, &p->module.export_section)) { - parse_err(p, "export section"); - return 0; + return parse_err(p, "export section"); } return 1; case section_start: if (!parse_start_section(p, &p->module.start_section)) { - parse_err(p, "start section"); - return 0; + return parse_err(p, "start section"); } return 1; + case section_element: - parse_err(p, "section_element parse not implemented"); - return 0; + return parse_element_section(p, &p->module.element_section); + case section_code: if (!parse_code_section(p, &p->module.code_section)) { - parse_err(p, "code section"); - return 0; + return parse_err(p, "code section"); } return 1; + case section_data: if (!parse_data_section(p, &p->module.data_section)) { - parse_err(p, "data section"); - return 0; + return parse_err(p, "data section"); } return 1; + default: - parse_err(p, "invalid section tag"); - return 0; + return parse_err(p, "invalid section tag"); } return 1; @@ -2128,43 +2232,6 @@ static int resolve_label(struct wasm_interp *interp) return 1; } -static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op); - -// -// consume instructions to resolve labels -static int parse_instrs_until(struct wasm_interp *interp, u8 stop_instr, - struct cursor *parsed_instrs) -{ - u8 tag; - struct instr op; - struct cursor *code; - - if (!(code = interp_codeptr(interp))) { - interp_error(interp, "codeptr"); - return 0; - } - - parsed_instrs->start = code->p; - parsed_instrs->p = code->p; - - for (;;) { - if (!pull_byte(code, &tag)) { - interp_error(interp, "oob"); - return 0; - } - - if (!parse_instr(interp, tag, &op)) { - interp_error(interp, "parse %s instr (0x%x)", instr_name(tag), tag); - return 0; - } - - if (tag == stop_instr) { - parsed_instrs->end = code->p; - return 1; - } - } -} - static inline u16 *func_num_labels(struct wasm_interp *interp, int fn) { u16 *num = (u16*)array_index(&interp->num_labels, fn); @@ -2289,33 +2356,25 @@ static int label_checkpoint(struct wasm_interp *interp, int *jumped) return 1; } - -static int parse_block(struct wasm_interp *interp, struct block *block, u8 end_tag) +static int parse_block(struct expr_parser *p, struct block *block, u8 end_tag) { - struct cursor *code; int jumped; - if (!(code = interp_codeptr(interp))) { - interp_error(interp, "codeptr"); - return 0; - } + if (!parse_blocktype(p->code, p->errs, &block->type)) + return note_error(p->errs, p->code, "blocktype"); - if (!parse_blocktype(code, &interp->errors, &block->type)) { - interp_error(interp, "blocktype"); - return 0; - } + // if we don't have an interpreter instance, we don't care about + // label resolution + if (p->interp && !label_checkpoint(p->interp, &jumped)) + return note_error(p->errs, p->code, "checkpoint"); - if (!label_checkpoint(interp, &jumped)) { - interp_error(interp, "checkpoint"); - return 0; - } + if (!parse_instrs_until(p, end_tag, &block->instrs)) + return note_error(p->errs, p->code, "parse instrs"); - if (!parse_instrs_until(interp, end_tag, &block->instrs)) { - interp_error(interp, "checkpoint"); - return 0; - } + if (p->interp) + return resolve_label(p->interp); - return resolve_label(interp); + return 1; } static inline int parse_memarg(struct cursor *code, struct memarg *memarg) @@ -2325,32 +2384,25 @@ static inline int parse_memarg(struct cursor *code, struct memarg *memarg) } -static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op) +static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) { - struct cursor *code; - - if (!(code = interp_codeptr(interp))) { - interp_error(interp, "codeptr"); - return 0; - } - - debug("%04lX parsing instr %s (0x%02x)\n", code->p - 1 - 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); switch (tag) { // two-byte instrs case i_memory_size: case i_memory_grow: - return pull_byte(code, &op->memidx); + return pull_byte(p->code, &op->memidx); case i_block: case i_loop: case i_if: - return parse_block(interp, &op->blocks[0], i_end); + return parse_block(p, &op->blocks[0], i_end); case i_else: - return parse_block(interp, &op->blocks[0], i_else) && - parse_block(interp, &op->blocks[1], i_end); + return parse_block(p, &op->blocks[0], i_else) && + parse_block(p, &op->blocks[1], i_end); case i_end: return 1; @@ -2361,7 +2413,7 @@ static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op) case i_local_tee: case i_global_get: case i_global_set: - return leb128_read(code, &op->integer); + return leb128_read(p->code, &op->integer); case i_i32_load: case i_i64_load: @@ -2386,23 +2438,21 @@ static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op) case i_i64_store8: case i_i64_store16: case i_i64_store32: - return parse_memarg(code, &op->memarg); + return parse_memarg(p->code, &op->memarg); case i_br: case i_br_if: case i_br_table: case i_call_indirect: - interp_error(interp, "consume dynamic-size op"); - return 0; + return note_error(p->errs, p->code, "consume dynamic-size op"); case i_i32_const: case i_i64_const: - return leb128_read(code, &op->integer); + return leb128_read(p->code, &op->integer); case i_f32_const: case i_f64_const: - interp_error(interp, "parse float const"); - return 0; + return note_error(p->errs, p->code, "parse float const"); // single-tag ops case i_unreachable: @@ -2481,13 +2531,13 @@ static int parse_instr(struct wasm_interp *interp, u8 tag, struct instr *op) return 1; } - interp_error(interp, "unhandled tag: 0x%x", tag); - return 0; + return note_error(p->errs, p->code, "unhandled tag: 0x%x", tag); } static int branch_jump(struct wasm_interp *interp, u8 end_tag) { struct cursor instrs; + struct expr_parser parser; int jumped; if (!label_checkpoint(interp, &jumped)) { @@ -2499,8 +2549,10 @@ static int branch_jump(struct wasm_interp *interp, u8 end_tag) return 1; } + make_interp_expr_parser(interp, &parser); + // consume instructions, use resolver stack to resolve jumps - if (!parse_instrs_until(interp, end_tag, &instrs)) { + if (!parse_instrs_until(&parser, end_tag, &instrs)) { interp_error(interp, "parse instrs"); return 0; } diff --git a/src/wasm.h b/src/wasm.h @@ -88,18 +88,25 @@ enum elem_mode { elem_mode_passive, elem_mode_active, elem_mode_declarative, -} +}; + +struct expr { + unsigned char *code; + int code_len; +}; struct elem { + struct expr offset; + int tableidx; + int *func_indices; + unsigned int num_func_indices; enum elem_mode mode; enum reftype reftype; - int tableidx; - struct expr offset; }; struct elemsec { - struct elem *elems; - int num_elems; + struct elem *elements; + int num_elements; }; struct memsec { @@ -160,11 +167,6 @@ struct importsec { int num_imports; }; -struct expr { - unsigned char *code; - int code_len; -}; - struct global { struct globaltype type; struct expr init; @@ -420,6 +422,7 @@ struct module { struct memsec memory_section; struct globalsec global_section; struct startsec start_section; + struct elemsec element_section; struct datasec data_section; };