commit 941aa8a6401907165eac4afdf8b434facbe03489
parent ea7bfc7db638a22f789ba1a666673aea7bedf084
Author: William Casarin <jb55@jb55.com>
Date: Mon, 5 Jul 2021 11:34:47 -0700
global section, const expr parsing
Diffstat:
M | src/wasm.c | | | 270 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
M | src/wasm.h | | | 51 | +++++++++++++++++++++++++++++++++++++-------------- |
2 files changed, 258 insertions(+), 63 deletions(-)
diff --git a/src/wasm.c b/src/wasm.c
@@ -698,15 +698,15 @@ static int parse_func(struct wasm_parser *p, struct func *func)
func->locals = locals;
func->num_locals = elems;
- func->code_len = size - (p->cur.p - start);
+ func->code.code_len = size - (p->cur.p - start);
- if (!pull_data_into_cursor(&p->cur, &p->mem, &func->code,
- func->code_len)) {
+ if (!pull_data_into_cursor(&p->cur, &p->mem, &func->code.code,
+ func->code.code_len)) {
note_error(p, "code oom");
return 0;
}
- assert(func->code[func->code_len-1] == i_end);
+ assert(func->code.code[func->code.code_len-1] == i_end);
return 1;
}
@@ -735,6 +735,35 @@ static int parse_code_section(struct wasm_parser *p,
return 1;
}
+static int is_valid_reftype(unsigned char reftype)
+{
+ switch ((enum reftype)reftype) {
+ case funcref: return 1;
+ case externref: return 1;
+ }
+ return 0;
+}
+
+static int parse_reftype(struct wasm_parser *p, enum reftype *reftype)
+{
+ u8 tag;
+
+ if (!pull_byte(&p->cur, &tag)) {
+ note_error(p, "reftype");
+ return 0;
+ }
+
+ if (!is_valid_reftype(tag)) {
+ note_error(p, "invalid reftype: 0x%x", reftype);
+ return 0;
+ }
+
+ *reftype = (enum reftype)tag;
+
+ return 1;
+}
+
+
static int parse_export_section(struct wasm_parser *p,
struct exportsec *export_section)
{
@@ -759,15 +788,6 @@ static int parse_export_section(struct wasm_parser *p,
return 1;
}
-static int is_valid_reftype(unsigned char reftype)
-{
- switch ((enum reftype)reftype) {
- case funcref: return 1;
- case externref: return 1;
- }
- return 0;
-}
-
static int parse_limits(struct wasm_parser *p, struct limits *limits)
{
unsigned char tag;
@@ -799,27 +819,202 @@ static int parse_limits(struct wasm_parser *p, struct limits *limits)
static int parse_table(struct wasm_parser *p, struct table *table)
{
- unsigned char reftype;
- if (!pull_byte(&p->cur, &reftype)) {
+ if (!parse_reftype(p, &table->reftype)) {
note_error(p, "reftype");
return 0;
}
- if (!is_valid_reftype(reftype)) {
- note_error(p, "invalid reftype: 0x%x", reftype);
+ if (!parse_limits(p, &table->limits)) {
+ note_error(p, "limits");
return 0;
}
- table->reftype = (enum reftype)reftype;
+ return 1;
+}
- if (!parse_limits(p, &table->limits)) {
- note_error(p, "limits");
+static inline int is_valid_ref_instr(u8 tag)
+{
+ switch ((enum ref_instr)tag) {
+ case ref_null: return 1;
+ case ref_is_null: return 1;
+ case ref_func: return 1;
+ }
+ return 0;
+}
+
+static inline int is_valid_const_instr(u8 tag)
+{
+ switch ((enum const_instr)tag) {
+ case const_i32: return 1;
+ case const_i64: return 1;
+ case const_f32: return 1;
+ case const_f64: return 1;
+ }
+ return 0;
+}
+
+static int parse_const_instr(struct wasm_parser *p)
+{
+ u8 tag;
+ unsigned int n;
+
+ if (!pull_byte(&p->cur, &tag)) {
+ note_error(p, "tag");
+ return 0;
+ }
+
+ if (!is_valid_const_instr(tag)) {
+ note_error(p, "invalid const instr tag 0x%x", tag);
+ p->cur.p--;
+ return 0;
+ }
+
+ switch ((enum const_instr)tag) {
+ case const_i32:
+ case const_i64:
+ if (!leb128_read(&p->cur, &n)) {
+ note_error(p, "couldn't read integer");
+ return 0;
+ }
+ break;
+ case const_f32:
+ case const_f64:
+ note_error(p, "TODO parse float constants");
return 0;
}
return 1;
}
+static int parse_ref_instr(struct wasm_parser *p)
+{
+ u8 tag;
+ unsigned int idx;
+
+ if (!pull_byte(&p->cur, &tag)) {
+ note_error(p, "tag");
+ return 0;
+ }
+
+ if (!is_valid_ref_instr(tag)) {
+ //note_error(p, "invalid ref instr tag 0x%x", tag);
+ p->cur.p--;
+ return 0;
+ }
+
+ switch ((enum ref_instr)tag) {
+ case ref_null:
+ if (!parse_reftype(p, (enum reftype*)&tag)) {
+ note_error(p, "invalid ref.null instr reftype 0x%x", tag);
+ return 0;
+ }
+ break;
+
+ case ref_is_null:
+ break;
+
+ case ref_func:
+ if (!leb128_read(&p->cur, &idx)) {
+ note_error(p, "invalid ref.func idx");
+ return 0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static inline int parse_const_expr(struct wasm_parser *p)
+{
+ return parse_ref_instr(p) || parse_const_instr(p);
+}
+
+static int parse_const_exprs(struct wasm_parser *p, struct expr *code)
+{
+ code->code = p->cur.p;
+
+ while (p->cur.p < p->cur.end) {
+ if (*p->cur.p == i_end) {
+ p->cur.p++;
+ code->code_len = p->cur.p - code->code;
+ return 1;
+ }
+
+ if (!parse_const_expr(p)) {
+ note_error(p, "no constant expr found");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int parse_mut(struct wasm_parser *p, enum mut *mut)
+{
+ if (consume_byte(&p->cur, mut_const)) {
+ *mut = mut_const;
+ return 1;
+ }
+
+ if (consume_byte(&p->cur, mut_var)) {
+ *mut = mut_var;
+ return 1;
+ }
+
+ note_error(p, "unknown mut %02x", *p->cur.p);
+ return 0;
+}
+
+static int parse_globaltype(struct wasm_parser *p, struct globaltype *g)
+{
+ if (!parse_valtype(p, &g->valtype)) {
+ note_error(p, "valtype");
+ return 0;
+ }
+
+ return parse_mut(p, &g->mut);
+}
+
+static int parse_global(struct wasm_parser *p,
+ struct global *global)
+{
+ if (!parse_globaltype(p, &global->type)) {
+ note_error(p, "type");
+ return 0;
+ }
+
+ if (!parse_const_exprs(p, &global->init)) {
+ note_error(p, "init code");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int parse_global_section(struct wasm_parser *p,
+ struct globalsec *global_section)
+{
+ struct global *globals;
+ unsigned int elems, i;
+
+ if (!parse_vector(p, sizeof(*globals), &elems, (void**)&globals)) {
+ note_error(p, "globals vector");
+ return 0;
+ }
+
+ for (i = 0; i < elems; i++) {
+ if (!parse_global(p, &globals[i])) {
+ note_error(p, "global #%d/%d", i+1, elems);
+ return 0;
+ }
+ }
+
+ global_section->num_globals = elems;
+ global_section->globals = globals;
+
+ return 1;
+}
+
static int parse_memory_section(struct wasm_parser *p,
struct memsec *memory_section)
{
@@ -892,32 +1087,6 @@ static int parse_function_section(struct wasm_parser *p,
return 1;
}
-static int parse_mut(struct wasm_parser *p, enum mut *mut)
-{
- if (consume_byte(&p->cur, mut_const)) {
- *mut = mut_const;
- return 1;
- }
-
- if (consume_byte(&p->cur, mut_var)) {
- *mut = mut_var;
- return 1;
- }
-
- note_error(p, "unknown mut %02x", *p->cur.p);
- return 0;
-}
-
-static int parse_globaltype(struct wasm_parser *p, struct globaltype *g)
-{
- if (!parse_valtype(p, &g->valtype)) {
- note_error(p, "valtype");
- return 0;
- }
-
- return parse_mut(p, &g->mut);
-}
-
static int parse_import_table(struct wasm_parser *p, struct limits *limits)
{
if (!consume_byte(&p->cur, 0x70)) {
@@ -1085,8 +1254,11 @@ static int parse_section_by_tag(struct wasm_parser *p, enum section_tag tag,
}
return 1;
case section_global:
- note_error(p, "section_global parse not implemented");
- return 0;
+ if (!parse_global_section(p, &p->module.global_section)) {
+ note_error(p, "global section");
+ return 0;
+ }
+ return 1;
case section_export:
if (!parse_export_section(p, &p->module.export_section)) {
note_error(p, "export section");
@@ -1473,7 +1645,7 @@ static int prepare_call(struct wasm_interp *interp, int func_index)
}
/* update current function and push it to the codestack as well */
- make_cursor(func->code, func->code + func->code_len, &code);
+ make_cursor(func->code.code, func->code.code + func->code.code_len, &code);
if (!cursor_pushcode(&interp->code_stack, &code)) {
interp_error(interp, "oob cursor_pushcode");
return 0;
diff --git a/src/wasm.h b/src/wasm.h
@@ -19,6 +19,19 @@ enum valtype {
f64 = 0x7C,
};
+enum ref_instr {
+ ref_null = 0xD0,
+ ref_is_null = 0xD1,
+ ref_func = 0xD2,
+};
+
+enum const_instr {
+ const_i32 = 0x41,
+ const_i64 = 0x42,
+ const_f32 = 0x43,
+ const_f64 = 0x44,
+};
+
enum limit_type {
limit_min = 0x00,
limit_min_max = 0x01,
@@ -81,6 +94,21 @@ struct funcsec {
int num_indices;
};
+enum mut {
+ mut_const,
+ mut_var,
+};
+
+struct globaltype {
+ enum valtype valtype;
+ enum mut mut;
+};
+
+struct globalsec {
+ struct global *globals;
+ int num_globals;
+};
+
struct typesec {
struct functype *functypes;
int num_functypes;
@@ -93,16 +121,6 @@ enum import_type {
import_global,
};
-enum mut {
- mut_const,
- mut_var,
-};
-
-struct globaltype {
- enum valtype valtype;
- enum mut mut;
-};
-
struct importdesc {
enum import_type type;
union {
@@ -125,8 +143,13 @@ struct importsec {
};
struct expr {
- unsigned char *instrs;
- int num_instrs;
+ unsigned char *code;
+ int code_len;
+};
+
+struct global {
+ struct globaltype type;
+ struct expr init;
};
struct local {
@@ -136,8 +159,7 @@ struct local {
/* "code" */
struct func {
- unsigned char *code;
- int code_len;
+ struct expr code;
struct local *locals;
int num_locals;
};
@@ -310,6 +332,7 @@ struct module {
struct codesec code_section;
struct tablesec table_section;
struct memsec memory_section;
+ struct globalsec global_section;
};
struct wasm_interp {