protoverse

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

commit c6c4462700a581b82c916959e5b7e951105a7b01
parent 63382c476a5eec3ab2e00d7be713d0ad509bc53e
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 21 Jul 2021 13:58:15 -0700

C execution is working!

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

Diffstat:
M.gitignore | 1+
MMakefile | 3+++
Msrc/cursor.h | 4+++-
Msrc/parse.h | 1+
Msrc/wasm.c | 943++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/wasm.h | 94+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Dwasm/hello-c.c | 14--------------
Mwasm/hello-c.wasm | 0
Mwasm/hello.wasm | 0
Mwasm/hello.wat | 6+-----
Mwasm/loop.wat | 20+++++++++++---------
11 files changed, 746 insertions(+), 340 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -11,3 +11,4 @@ todo/done.txt *.wasm /tags todo/todo.txt.bak +*.txt diff --git a/Makefile b/Makefile @@ -34,6 +34,9 @@ wasm: $(WASMS) %.wasm: %.wat wat2wasm $^ -o $@ +%.c.wasm: %.wasm.c + emcc -g $< -s WASM=1 -o $@ + wasm/hello-c.wasm: wasm/hello-c.c emcc -g $< -s WASM=1 -o $@ diff --git a/src/cursor.h b/src/cursor.h @@ -220,7 +220,9 @@ static inline int cursor_push(struct cursor *cursor, u8 *data, int len) return 0; } - memcpy(cursor->p, data, len); + if (cursor->p != data) + memcpy(cursor->p, data, len); + cursor->p += len; return 1; diff --git a/src/parse.h b/src/parse.h @@ -74,6 +74,7 @@ struct tok_str { u8 *data; int len; }; + union number { int integer; double fdouble; diff --git a/src/wasm.c b/src/wasm.c @@ -4,12 +4,14 @@ #include "debug.h" #include "error.h" +#include <unistd.h> #include <stdarg.h> #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include <stdint.h> +#include <inttypes.h> #define interp_error(p, fmt, ...) note_error(&((p)->errors), interp_codeptr(p), fmt, ##__VA_ARGS__) #define parse_err(p, fmt, ...) note_error(&((p)->errs), &(p)->cur, fmt, ##__VA_ARGS__) @@ -76,7 +78,7 @@ static const char *valtype_literal(enum valtype valtype) { switch (valtype) { case val_i32: return ""; - case val_i64: return "l"; + case val_i64: return "L"; case val_f32: return ""; case val_f64: return "f"; case val_ref_null: return "null"; @@ -87,19 +89,19 @@ static const char *valtype_literal(enum valtype valtype) return "?"; } -static INLINE int is_valid_fn_index(struct module *module, int ind) +static INLINE int is_valid_fn_index(struct module *module, u32 ind) { - return ind >= 0 && ind < module->num_funcs; + return ind < module->num_funcs; } -static INLINE struct func *get_function(struct module *module, int ind) +static INLINE struct func *get_function(struct module *module, u32 ind) { if (unlikely(!is_valid_fn_index(module, ind))) return NULL; return &module->funcs[ind]; } -static struct val *get_fn_local(struct wasm_interp *interp, int fn, int ind) +static struct val *get_fn_local(struct wasm_interp *interp, int fn, u32 ind) { struct func *func; @@ -117,7 +119,7 @@ static struct val *get_fn_local(struct wasm_interp *interp, int fn, int ind) return &func->locals[ind].val; } -static struct val *get_local(struct wasm_interp *interp, int ind) +static struct val *get_local(struct wasm_interp *interp, u32 ind) { struct callframe *frame; @@ -155,6 +157,18 @@ static INLINE int cursor_pop_i32(struct cursor *stack, int *i) return 1; } +static INLINE int cursor_pop_i64(struct cursor *stack, int64_t *i) +{ + struct val val; + if (unlikely(!cursor_popval(stack, &val))) + return 0; + if (unlikely(val.type != val_i64)) + return 0; + *i = val.num.i64; + return 1; +} + + static int is_reftype(enum valtype type) { switch (type) { @@ -201,6 +215,11 @@ static INLINE int stack_pop_i32(struct wasm_interp *interp, int *i) return cursor_pop_i32(&interp->stack, i); } +static INLINE int stack_pop_i64(struct wasm_interp *interp, int64_t *i) +{ + return cursor_pop_i64(&interp->stack, i); +} + static INLINE int cursor_pop_valtype(struct cursor *stack, enum valtype type, struct val *val) { @@ -225,7 +244,7 @@ static void print_val(struct val *val) { switch (val->type) { case val_i32: printf("%d", val->num.i32); break; - case val_i64: printf("%lu", val->num.i64); break; + case val_i64: printf("%" PRId64, val->num.i64); break; case val_f32: printf("%f", val->num.f32); break; case val_f64: printf("%f", val->num.f64); break; @@ -239,6 +258,7 @@ static void print_val(struct val *val) printf("%s", valtype_literal(val->type)); } +#ifdef DEBUG static void print_refval(struct refval *ref, enum reftype reftype) { struct val val; @@ -246,6 +266,7 @@ static void print_refval(struct refval *ref, enum reftype reftype) val.ref = *ref; print_val(&val); } +#endif static void print_stack(struct cursor *stack) { @@ -318,9 +339,11 @@ static int builtin_proc_exit(struct wasm_interp *interp) static int builtin_get_args_sizes(struct wasm_interp *interp); static int builtin_get_args(struct wasm_interp *interp); +static int builtin_fd_write(struct wasm_interp *interp); static struct builtin BUILTINS[] = { { .name = "args_get", .fn = builtin_get_args }, + { .name = "fd_write", .fn = builtin_fd_write }, { .name = "args_sizes_get", .fn = builtin_get_args_sizes }, { .name = "proc_exit", .fn = builtin_proc_exit }, }; @@ -604,7 +627,7 @@ void print_error_backtrace(struct errors *errors) static void _functype_str(struct functype *ft, struct cursor *buf) { - int i; + u32 i; cursor_push_str(buf, "("); @@ -651,7 +674,7 @@ static void print_functype(struct functype *ft) static void print_type_section(struct typesec *typesec) { - int i; + u32 i; printf("%d functypes:\n", typesec->num_functypes); for (i = 0; i < typesec->num_functypes; i++) { printf(" "); @@ -692,7 +715,7 @@ static void print_import(struct import *import) static void print_import_section(struct importsec *importsec) { - int i; + u32 i; printf("%d imports:\n", importsec->num_imports); for (i = 0; i < importsec->num_imports; i++) { printf(" "); @@ -714,7 +737,7 @@ static void print_limits(struct limits *limits) static void print_memory_section(struct memsec *memory) { - int i; + u32 i; struct limits *mem; printf("%d memory:\n", memory->num_mems); @@ -728,7 +751,7 @@ static void print_memory_section(struct memsec *memory) static void print_table_section(struct tablesec *section) { - int i; + u32 i; struct table *table; printf("%d tables:\n", section->num_tables); @@ -743,7 +766,7 @@ static void print_table_section(struct tablesec *section) static int count_imports(struct module *module, enum import_type *typ) { - int i, count = 0; + u32 i, count = 0; struct import *import; struct importsec *imports; @@ -787,13 +810,13 @@ static void print_element_section(struct elemsec *section) static void print_start_section(struct module *module) { - int fn = module->start_section.start_fn; + u32 fn = module->start_section.start_fn; printf("start function: %d <%s>\n", fn, get_function_name(module, fn)); } static void print_export_section(struct exportsec *exportsec) { - int i; + u32 i; printf("%d exports:\n", exportsec->num_exports); for (i = 0; i < exportsec->num_exports; i++) { printf(" "); @@ -898,7 +921,7 @@ static void print_section(struct module *module, enum section_tag section) static void print_module(struct module *module) { - int i; + u32 i; enum section_tag section; for (i = 0; i < num_sections; i++) { @@ -934,10 +957,9 @@ static int leb128_write(struct cursor *write, unsigned int value) #define LEB128_4(type) (BYTE_AT(type, 3, 21) | LEB128_3(type)) #define LEB128_5(type) (BYTE_AT(type, 4, 28) | LEB128_4(type)) -static INLINE int leb128_read(struct cursor *read, unsigned int *val_) +static INLINE int read_i64(struct cursor *read, int64_t *val) { - int *val = (signed int*)val_; - int shift; + int64_t shift; u8 byte; *val = 0; @@ -951,7 +973,7 @@ static INLINE int leb128_read(struct cursor *read, unsigned int *val_) } while ((byte & 0x80) != 0); /* sign bit of byte is second high-order bit (0x40) */ - if ((shift < (signed int)sizeof(*val)) && (byte & 0x40)) + if ((shift < 64) && (byte & 0x40)) *val |= (~0 << shift); return 1; @@ -959,30 +981,57 @@ static INLINE int leb128_read(struct cursor *read, unsigned int *val_) static INLINE int uleb128_read(struct cursor *read, unsigned int *val) { - //unsigned char *start; - int shift; + unsigned int shift = 0; u8 byte; - - //start = read->p; *val = 0; - shift = 0; for (;;) { - if (!pull_byte(read, &byte)) { + if (!pull_byte(read, &byte)) return 0; - } - *val |= (byte & 0x7F) << shift; - if ((byte & 0x80) == 0) + + *val |= (0x7F & byte) << shift; + + if ((0x80 & byte) == 0) break; + shift += 7; } return 1; } +static INLINE int sleb128_read(struct cursor *read, signed int *val) +{ + int shift; + u8 byte; + + *val = 0; + shift = 0; + + do { + if (!pull_byte(read, &byte)) + return 0; + *val |= ((byte & 0x7F) << shift); + shift += 7; + } while ((byte & 0x80) != 0); + + /* sign bit of byte is second high-order bit (0x40) */ + if ((shift < 32) && (byte & 0x40)) + *val |= (0xFFFFFFFF << shift); + + return 1; +} + /* +static INLINE int uleb128_read(struct cursor *read, unsigned int *val) +{ + unsigned char p[6] = {0}; + *val = 0; + if (pull_byte(read, &p[0]) && (p[0] & 0x80) == 0) { *val = LEB128_1(unsigned int); + if (p[0] == 0x7F) + assert((int)*val == -1); return 1; } else if (pull_byte(read, &p[1]) && (p[1] & 0x80) == 0) { *val = LEB128_2(unsigned int); @@ -1000,16 +1049,23 @@ static INLINE int uleb128_read(struct cursor *read, unsigned int *val) } //printf("%02X & 0xF0\n", p[4] & 0xF0); } - */ - /* reset if we're missing */ - //read->p = start; + return 0; +} +*/ static INLINE int read_int(struct cursor *read, int *val) { - return leb128_read(read, (unsigned int *)val); + return sleb128_read(read, val); +} + + +static INLINE int read_u32(struct cursor *read, u32 *val) +{ + return uleb128_read(read, val); } + static int parse_section_tag(struct cursor *cur, enum section_tag *section) { unsigned char byte; @@ -1052,7 +1108,7 @@ static int parse_valtype(struct wasm_parser *p, enum valtype *valtype) static int parse_result_type(struct wasm_parser *p, struct resulttype *rt) { - int i, elems; + u32 i, elems; enum valtype valtype; unsigned char *start; @@ -1060,7 +1116,7 @@ static int parse_result_type(struct wasm_parser *p, struct resulttype *rt) rt->valtypes = 0; start = p->mem.p; - if (unlikely(!read_int(&p->cur, &elems))) { + if (unlikely(!read_u32(&p->cur, &elems))) { parse_err(p, "vec len"); return 0; } @@ -1109,8 +1165,8 @@ static int parse_func_type(struct wasm_parser *p, struct functype *func) static int parse_name(struct wasm_parser *p, const char **name) { - unsigned int bytes; - if (unlikely(!leb128_read(&p->cur, &bytes))) { + u32 bytes; + if (unlikely(!read_u32(&p->cur, &bytes))) { parse_err(p, "name len"); return 0; } @@ -1163,7 +1219,7 @@ static int parse_export(struct wasm_parser *p, struct wexport *export) return 0; } - if (!leb128_read(&p->cur, &export->index)) { + if (!read_u32(&p->cur, &export->index)) { parse_err(p, "export index"); return 0; } @@ -1173,7 +1229,7 @@ static int parse_export(struct wasm_parser *p, struct wexport *export) static int parse_local(struct wasm_parser *p, struct local *local) { - if (unlikely(!read_int(&p->cur, &local->val.num.i32))) { + if (unlikely(!read_u32(&p->cur, &local->val.num.u32))) { debug("fail parse local\n"); return parse_err(p, "n"); } @@ -1186,12 +1242,11 @@ static int parse_local(struct wasm_parser *p, struct local *local) return 1; } -static int parse_vector(struct wasm_parser *p, unsigned int item_size, - unsigned int *elems, void **items) +static int parse_vector(struct wasm_parser *p, int item_size, + u32 *elems, void **items) { - if (!leb128_read(&p->cur, elems)) { - parse_err(p, "len"); - return 0; + if (!read_u32(&p->cur, elems)) { + return parse_err(p, "len"); } *items = cursor_alloc(&p->mem, *elems * item_size); @@ -1206,19 +1261,18 @@ static int parse_vector(struct wasm_parser *p, unsigned int item_size, static int parse_func(struct wasm_parser *p, struct wasm_func *func) { - unsigned int size; - int i; - unsigned char *start; struct local *locals; + u32 i, size; + u8 *start; - if (!leb128_read(&p->cur, &size)) { + if (!read_u32(&p->cur, &size)) { return parse_err(p, "code size"); } start = p->cur.p; locals = (struct local*)p->mem.p; - if (!read_int(&p->cur, &func->num_locals)) { + if (!read_u32(&p->cur, &func->num_locals)) { return parse_err(p, "read locals vec"); } @@ -1262,18 +1316,13 @@ static int parse_code_section(struct wasm_parser *p, struct codesec *code_section) { struct wasm_func *funcs; - int i; + u32 i; - if (!parse_vector(p, sizeof(*funcs), - (unsigned int*)&code_section->num_funcs, + if (!parse_vector(p, sizeof(*funcs), &code_section->num_funcs, (void**)&funcs)) { return parse_err(p, "funcs"); } - if (code_section->num_funcs < 0) { - return parse_err(p, "code_section num_funcs < 0"); - } - for (i = 0; i < code_section->num_funcs; i++) { if (!parse_func(p, &funcs[i])) { return parse_err(p, "func #%d", i); @@ -1319,7 +1368,7 @@ static int parse_export_section(struct wasm_parser *p, struct exportsec *export_section) { struct wexport *exports; - unsigned int elems, i; + u32 elems, i; if (!parse_vector(p, sizeof(*exports), &elems, (void**)&exports)) { parse_err(p, "vector"); @@ -1350,14 +1399,14 @@ static int parse_limits(struct wasm_parser *p, struct limits *limits) return parse_err(p, "invalid tag %02x", tag); } - if (!leb128_read(&p->cur, &limits->min)) { + if (!read_u32(&p->cur, &limits->min)) { return parse_err(p, "min"); } if (tag == limit_min) return 1; - if (!leb128_read(&p->cur, &limits->max)) { + if (!read_u32(&p->cur, &limits->max)) { return parse_err(p, "max"); } @@ -1509,7 +1558,7 @@ static const char *show_instr(struct instr *instr) case i_ref_func: case i_table_set: case i_table_get: - sprintf(tmp, "%d", instr->integer); + sprintf(tmp, "%d", instr->i32); cursor_push_str(&buf, tmp); break; @@ -1723,12 +1772,12 @@ static int eval_const_instr(struct instr *instr, struct errors *errs, } return 1; case ci_ref_func: - if (unlikely(!cursor_push_funcref(stack, instr->integer))) { + if (unlikely(!cursor_push_funcref(stack, instr->i32))) { return note_error(errs, stack, "couldn't push funcref"); } return 1; case ci_const_i32: - if (unlikely(!cursor_push_i32(stack, instr->integer))) { + if (unlikely(!cursor_push_i32(stack, instr->i32))) { return note_error(errs, stack, "global push i32 const"); } @@ -1867,7 +1916,7 @@ static int parse_global_section(struct wasm_parser *p, struct globalsec *global_section) { struct global *globals; - unsigned int elems, i; + u32 elems, i; if (!parse_vector(p, sizeof(*globals), &elems, (void**)&globals)) { return parse_err(p, "globals vector"); @@ -1898,7 +1947,7 @@ static INLINE void make_interp_expr_parser(struct wasm_interp *interp, } static int parse_instrs_until(struct expr_parser *p, u8 stop_instr, - u8 **parsed_instrs, int *instr_len) + u8 **parsed_instrs, u32 *instr_len) { u8 tag; struct instr op; @@ -1942,10 +1991,10 @@ static int parse_expr(struct wasm_parser *p, struct expr *expr) static int parse_elem_func_inits(struct wasm_parser *p, struct elem *elem) { - int index, i; + u32 index, i; struct expr *expr; - if (!read_int(&p->cur, &elem->num_inits)) + if (!read_u32(&p->cur, &elem->num_inits)) return parse_err(p, "func indices vec read fail"); if (!(elem->inits = cursor_alloc(&p->mem, elem->num_inits * @@ -1957,12 +2006,12 @@ static int parse_elem_func_inits(struct wasm_parser *p, struct elem *elem) expr = &elem->inits[i]; expr->code = p->mem.p; - if (!read_int(&p->cur, &index)) + if (!read_u32(&p->cur, &index)) return parse_err(p, "func index %d read fail", i); if (!cursor_push_byte(&p->mem, i_ref_func)) return parse_err(p, "push ref_func instr oob for %d", i); if (!leb128_write(&p->mem, index)) - return parse_err(p, "push ref_func int index oob for %d", i); + return parse_err(p, "push ref_func u32 index oob for %d", i); if (!cursor_push_byte(&p->mem, i_end)) return parse_err(p, "push i_end for init %d", i); @@ -2028,7 +2077,7 @@ static int parse_custom_section(struct wasm_parser *p, u32 size, static int parse_element_section(struct wasm_parser *p, struct elemsec *elemsec) { struct elem *elements; - unsigned int count, i; + u32 count, i; if (!parse_vector(p, sizeof(struct elem), &count, (void**)&elements)) return parse_err(p, "elements vec"); @@ -2048,7 +2097,7 @@ static int parse_memory_section(struct wasm_parser *p, struct memsec *memory_section) { struct limits *mems; - unsigned int elems, i; + u32 elems, i; if (!parse_vector(p, sizeof(*mems), &elems, (void**)&mems)) { return parse_err(p, "mems vector"); @@ -2069,17 +2118,17 @@ static int parse_memory_section(struct wasm_parser *p, static int parse_start_section(struct wasm_parser *p, struct startsec *start_section) { - if (!read_int(&p->cur, &start_section->start_fn)) { + if (!read_u32(&p->cur, &start_section->start_fn)) { return parse_err(p, "start_fn index"); } return 1; } -static INLINE int parse_byte_vector(struct wasm_parser *p, unsigned char **data, - int *data_len) +static INLINE int parse_byte_vector(struct wasm_parser *p, u8 **data, + u32 *data_len) { - if (!read_int(&p->cur, data_len)) { + if (!read_u32(&p->cur, data_len)) { return parse_err(p, "len"); } @@ -2136,7 +2185,7 @@ static int parse_wdata(struct wasm_parser *p, struct wdata *data) case 2: data->mode = datamode_active; - if (!read_int(&p->cur, &data->active.mem_index)) { + if (!read_u32(&p->cur, &data->active.mem_index)) { return parse_err(p, "read active data mem_index"); } @@ -2157,7 +2206,7 @@ static int parse_wdata(struct wasm_parser *p, struct wdata *data) static int parse_data_section(struct wasm_parser *p, struct datasec *section) { struct wdata *data; - unsigned int elems, i; + u32 elems, i; if (!parse_vector(p, sizeof(*data), &elems, (void**)&data)) { return parse_err(p, "datas vector"); @@ -2179,11 +2228,10 @@ static int parse_table_section(struct wasm_parser *p, struct tablesec *table_section) { struct table *tables; - unsigned int elems, i; + u32 elems, i; if (!parse_vector(p, sizeof(*tables), &elems, (void**)&tables)) { - parse_err(p, "tables vector"); - return 0; + return parse_err(p, "tables vector"); } for (i = 0; i < elems; i++) { @@ -2202,16 +2250,14 @@ static int parse_table_section(struct wasm_parser *p, static int parse_function_section(struct wasm_parser *p, struct funcsec *funcsec) { - unsigned int *indices; - unsigned int i, elems; + u32 i, elems, *indices; if (!parse_vector(p, sizeof(*indices), &elems, (void**)&indices)) { - parse_err(p, "indices"); - return 0; + return parse_err(p, "indices"); } for (i = 0; i < elems; i++) { - if (!leb128_read(&p->cur, &indices[i])) { + if (!read_u32(&p->cur, &indices[i])) { parse_err(p, "typeidx #%d", i); return 0; } @@ -2240,7 +2286,7 @@ static int parse_import_table(struct wasm_parser *p, struct limits *limits) static int parse_importdesc(struct wasm_parser *p, struct importdesc *desc) { - unsigned char tag; + u8 tag; if (!pull_byte(&p->cur, &tag)) { parse_err(p, "oom"); @@ -2251,7 +2297,7 @@ static int parse_importdesc(struct wasm_parser *p, struct importdesc *desc) switch (desc->type) { case import_func: - if (!leb128_read(&p->cur, &desc->typeidx)) { + if (!read_u32(&p->cur, &desc->typeidx)) { parse_err(p, "typeidx"); return 0; } @@ -2318,18 +2364,16 @@ static int parse_import(struct wasm_parser *p, struct import *import) static int parse_import_section(struct wasm_parser *p, struct importsec *importsec) { - unsigned int elems, i; + u32 elems, i; struct import *imports; if (!parse_vector(p, sizeof(*imports), &elems, (void**)&imports)) { - parse_err(p, "imports"); - return 0; + return parse_err(p, "imports"); } for (i = 0; i < elems; i++) { if (!parse_import(p, &imports[i])) { - parse_err(p, "import #%d", i); - return 0; + return parse_err(p, "import #%d", i); } } @@ -2342,7 +2386,7 @@ static int parse_import_section(struct wasm_parser *p, struct importsec *imports /* type section is just a vector of function types */ static int parse_type_section(struct wasm_parser *p, struct typesec *typesec) { - unsigned int elems, i; + u32 elems, i; struct functype *functypes; typesec->num_functypes = 0; @@ -2479,14 +2523,14 @@ static int parse_section(struct wasm_parser *p) { enum section_tag tag; struct section; - unsigned int bytes; + u32 bytes; if (!parse_section_tag(&p->cur, &tag)) { parse_err(p, "section tag"); return 2; } - if (!leb128_read(&p->cur, &bytes)) { + if (!read_u32(&p->cur, &bytes)) { return parse_err(p, "section len"); } @@ -2499,9 +2543,9 @@ static int parse_section(struct wasm_parser *p) return 1; } -static struct builtin *builtin_func(int ind) +static struct builtin *builtin_func(u32 ind) { - if (unlikely(ind < 0 || ind >= NUM_BUILTINS)) { + if (unlikely(ind >= NUM_BUILTINS)) { printf("UNUSUAL: invalid builtin index %d (max %d)\n", ind, NUM_BUILTINS-1); return NULL; @@ -2509,9 +2553,9 @@ static struct builtin *builtin_func(int ind) return &BUILTINS[ind]; } -static const char *find_exported_function_name(struct module *module, int fn) +static const char *find_exported_function_name(struct module *module, u32 fn) { - int i; + u32 i; struct wexport *export; if (!was_section_parsed(module, section_export)) @@ -2520,7 +2564,7 @@ static const char *find_exported_function_name(struct module *module, int fn) for (i = 0; i < module->export_section.num_exports; i++) { export = &module->export_section.exports[i]; if (export->desc == export_func && - export->index == (unsigned int)fn) { + export->index == fn) { return export->name; } } @@ -2531,11 +2575,12 @@ static const char *find_exported_function_name(struct module *module, int fn) static int make_func_lookup_table(struct wasm_parser *parser) { - int i, num_imports, num_func_imports, num_internal_funcs, typeidx; + u32 i, num_imports, num_func_imports, num_internal_funcs, typeidx, fn; struct import *import; struct importsec *imports; struct func *func; - int fn = 0; + + fn = 0; imports = &parser->module.import_section; num_func_imports = count_imported_functions(&parser->module); @@ -2618,7 +2663,7 @@ int parse_wasm(struct wasm_parser *p) return parse_err(p, "failed making func lookup table"); } - print_module(&p->module); + //print_module(&p->module); debug("module parse success!\n\n"); return 1; @@ -2679,7 +2724,7 @@ static int interp_i32_sub(struct wasm_interp *interp) return stack_pushval(interp, &c); } -static INLINE int set_fn_local(struct wasm_interp *interp, int fn, int ind, +static INLINE int set_fn_local(struct wasm_interp *interp, int fn, u32 ind, struct val *val) { struct val *local; @@ -2693,7 +2738,7 @@ static INLINE int set_fn_local(struct wasm_interp *interp, int fn, int ind, return 1; } -static INLINE int set_local(struct wasm_interp *interp, int ind, +static INLINE int set_local(struct wasm_interp *interp, u32 ind, struct val *val) { struct callframe *frame; @@ -2705,7 +2750,7 @@ static INLINE int set_local(struct wasm_interp *interp, int ind, return set_fn_local(interp, frame->fn, ind, val); } -static INLINE int interp_local_tee(struct wasm_interp *interp, int index) +static INLINE int interp_local_tee(struct wasm_interp *interp, u32 index) { struct val *val; @@ -2720,7 +2765,7 @@ static INLINE int interp_local_tee(struct wasm_interp *interp, int index) return 1; } -static int interp_local_set(struct wasm_interp *interp, int index) +static int interp_local_set(struct wasm_interp *interp, u32 index) { struct val val; @@ -2735,7 +2780,7 @@ static int interp_local_set(struct wasm_interp *interp, int index) return 1; } -static INLINE int interp_local_get(struct wasm_interp *interp, int index) +static INLINE int interp_local_get(struct wasm_interp *interp, u32 index) { struct val *val; @@ -2746,7 +2791,7 @@ static INLINE int interp_local_get(struct wasm_interp *interp, int index) return stack_pushval(interp, val); } -static INLINE void make_i64_val(struct val *val, int64_t v) +static INLINE void make_i64_val(struct val *val, u64 v) { val->type = val_i64; val->num.i64 = v; @@ -2790,12 +2835,92 @@ static INLINE int interp_i32_gt_s(struct wasm_interp *interp) return stack_pushval(interp, &c); } +static INLINE int interp_i64_sub(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + return interp_error(interp, "binop prep"); + c.num.i64 = lhs.num.i64 - rhs.num.i64; + return stack_pushval(interp, &c); +} + +static INLINE int interp_i64_ge_u(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + return interp_error(interp, "binop prep"); + c.type = val_i32; + c.num.i32 = lhs.num.i64 >= rhs.num.i64; + return stack_pushval(interp, &c); +} + +static INLINE int interp_i64_mul(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + return interp_error(interp, "binop prep"); + c.num.i64 = lhs.num.i64 * rhs.num.i64; + return stack_pushval(interp, &c); +} + +static INLINE int interp_i64_div_u(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + return interp_error(interp, "binop prep"); + if (rhs.num.u64 == 0) + return interp_error(interp, "congrats, you divided by zero"); + c.num.u64 = lhs.num.u64 / rhs.num.u64; + return stack_pushval(interp, &c); +} + +static int interp_i64_eqz(struct wasm_interp *interp) +{ + struct val a, res; + if (unlikely(!stack_pop_valtype(interp, val_i64, &a))) + return interp_error(interp, "pop val"); + res.type = val_i32; + res.num.i64 = a.num.i64 == 0; + return cursor_pushval(&interp->stack, &res); +} + +static INLINE int interp_i64_gt_s(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + return interp_error(interp, "binop prep"); + c.type = val_i32; + c.num.i32 = lhs.num.i64 > rhs.num.i64; + return stack_pushval(interp, &c); +} + +static INLINE int interp_i64_gt_u(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + return interp_error(interp, "binop prep"); + c.type = val_i32; + c.num.i32 = lhs.num.u64 > rhs.num.u64; + return stack_pushval(interp, &c); +} + static INLINE int interp_i32_gt_u(struct wasm_interp *interp) { struct val lhs, rhs, c; if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) return interp_error(interp, "binop prep"); - c.num.i32 = (unsigned int)lhs.num.i32 > (unsigned int)rhs.num.i32; + c.num.i32 = lhs.num.u32 > rhs.num.u32; + return stack_pushval(interp, &c); +} + +static INLINE int interp_i32_div_u(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) + return interp_error(interp, "binop prep"); + if (rhs.num.u64 == 0) + return interp_error(interp, "congrats, you divided by zero"); + c.num.i32 = lhs.num.i32 / rhs.num.i32; return stack_pushval(interp, &c); } @@ -2826,7 +2951,7 @@ static INLINE int interp_i32_le_s(struct wasm_interp *interp) return stack_pushval(interp, &c); } -static INLINE int interp_i64_const(struct wasm_interp *interp, int64_t c) +static INLINE int interp_i64_const(struct wasm_interp *interp, u64 c) { struct val val; make_i64_val(&val, c); @@ -2834,7 +2959,7 @@ static INLINE int interp_i64_const(struct wasm_interp *interp, int64_t c) } -static INLINE int interp_i32_const(struct wasm_interp *interp, int c) +static INLINE int interp_i32_const(struct wasm_interp *interp, u32 c) { struct val val; make_i32_val(&val, c); @@ -2971,12 +3096,13 @@ static int prepare_function_args(struct wasm_interp *interp, struct func *func, struct local *local; enum valtype paramtype; struct val val; - int i, ind; + u32 i, ind; /* push params as locals */ for (i = 0; i < func->functype->params.num_valtypes; i++) { - paramtype = (enum valtype)func->functype->params.valtypes[i]; ind = func->functype->params.num_valtypes-1-i; + paramtype = (enum valtype)func->functype->params.valtypes[ind]; + //ind = i; local = &func->locals[ind]; if (unlikely(!cursor_popval(&interp->stack, &val))) { @@ -3005,11 +3131,13 @@ static int prepare_function_args(struct wasm_interp *interp, struct func *func, } - for (; i < func->num_locals - func->functype->params.num_valtypes; i++) { + for (i=func->functype->params.num_valtypes; + i < func->num_locals; i++) { local = &func->locals[i]; make_default_val(&local->val); debug("setting local %d (%s) to default\n", - i, valtype_name(local->val.type)); + i-func->functype->params.num_valtypes, + valtype_name(local->val.type)); } return 1; @@ -3077,7 +3205,8 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect struct func *func; struct table_inst *table; struct refval *ref; - int i, ftidx; + u32 ftidx; + int i; if (unlikely(!was_section_parsed(interp->module, section_table))) { return interp_error(interp, "no table section"); @@ -3110,7 +3239,7 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect return interp_error(interp, "pop i32"); } - if (unlikely(i >= table->num_refs)) { + if (unlikely(i >= (int)table->num_refs)) { return interp_error(interp, "invalid index %d in table %d (max %d)", i, call->tableidx, table->num_refs-1); } @@ -3143,7 +3272,7 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect ref, interp->module->num_funcs-1); } - debug("calling %s:%d indirectly", + debug("calling %s:%d indirectly\n", get_function_name(interp->module, ref->addr), ref->addr); @@ -3167,6 +3296,7 @@ static int parse_blocktype(struct cursor *cur, struct errors *errs, struct block blocktype->tag = blocktype_index; cur->p--; + // TODO: this should be read_s64 if (!read_int(cur, &blocktype->type_index)) { note_error(errs, cur, "parse_blocktype: read type_index\n"); return 0; @@ -3176,7 +3306,7 @@ static int parse_blocktype(struct cursor *cur, struct errors *errs, struct block return 1; } -static INLINE struct label *index_label(struct cursor *a, int fn, int ind) +static INLINE struct label *index_label(struct cursor *a, u32 fn, u32 ind) { return index_cursor(a, ((MAX_LABELS * fn) + ind), sizeof(struct label)); } @@ -3191,7 +3321,7 @@ static INLINE int is_label_resolved(struct label *label) return label->instr_pos & 0x80000000; } -static struct label *index_frame_label(struct wasm_interp *interp, int ind) +static struct label *index_frame_label(struct wasm_interp *interp, u32 ind) { struct callframe *frame; @@ -3226,6 +3356,7 @@ static INLINE int pop_resolver(struct wasm_interp *interp, /* #ifdef DEBUG int num_resolvers; + struct label *label; #endif */ @@ -3238,10 +3369,16 @@ static INLINE int pop_resolver(struct wasm_interp *interp, if (unlikely(!count_local_resolvers(interp, &num_resolvers))) { return interp_error(interp, "local resolvers fn start"); }; + + label = index_label(&interp->labels, + top_callframe(&interp->callframes)->fn, + resolver->label); #endif - debug("popped resolver %d i_%s i_%s %d local_resolvers:%d\n", - resolver->label, + debug("%04lX popped resolver %04x-%04x i_%s i_%s %d local_resolvers:%d\n", + interp_codeptr(interp)->p - interp_codeptr(interp)->start, + label_instr_pos(label), + label->jump, instr_name(resolver->start_tag), instr_name(resolver->end_tag), count_resolvers(interp), @@ -3251,31 +3388,37 @@ static INLINE int pop_resolver(struct wasm_interp *interp, return 1; } -static int pop_label_checkpoint(struct wasm_interp *interp) +static int pop_label(struct wasm_interp *interp, + struct resolver *resolver, + struct callframe **frame, + struct label **label) { - struct label *label; - struct callframe *frame; - struct resolver resolver; - - resolver.label = 0; - resolver.end_tag = 0; - - if (unlikely(!pop_resolver(interp, &resolver))) + if (unlikely(!pop_resolver(interp, resolver))) return interp_error(interp, "couldn't pop jump resolver stack"); - if (unlikely(!(frame = top_callframe(&interp->callframes)))) + if (unlikely(!(*frame = top_callframe(&interp->callframes)))) return interp_error(interp, "no callframe?"); - if (unlikely(!(label = index_label(&interp->labels, frame->fn, resolver.label)))) + if (unlikely(!(*label = index_label(&interp->labels, (*frame)->fn, + resolver->label)))) return interp_error(interp, "index label"); - if (unlikely(!resolve_label(label, &frame->code))) + if (unlikely(!resolve_label(*label, &(*frame)->code))) return interp_error(interp, "resolve label"); return 1; } -static INLINE u16 *func_num_labels(struct wasm_interp *interp, int fn) +static INLINE int pop_label_checkpoint(struct wasm_interp *interp) +{ + struct resolver resolver; + struct callframe *frame; + struct label *label; + + return pop_label(interp, &resolver, &frame, &label); +} + +static INLINE u16 *func_num_labels(struct wasm_interp *interp, u32 fn) { u16 *num = index_cursor(&interp->num_labels, fn, sizeof(u16)); assert(num); @@ -3283,7 +3426,7 @@ static INLINE u16 *func_num_labels(struct wasm_interp *interp, int fn) return num; } -static int find_label(struct wasm_interp *interp, int fn, u32 instr_pos) +static int find_label(struct wasm_interp *interp, u32 fn, u32 instr_pos) { u16 *num_labels, i; struct label *label; @@ -3310,7 +3453,7 @@ static INLINE void set_label_pos(struct label *label, u32 pos) } // upsert an unresolved label -static int upsert_label(struct wasm_interp *interp, int fn, +static int upsert_label(struct wasm_interp *interp, u32 fn, u32 instr_pos, int *ind) { struct label *label; @@ -3359,12 +3502,12 @@ struct tag_info { static int push_label_checkpoint(struct wasm_interp *interp, struct label **label, u8 start_tag, u8 end_tag) { - u32 instr_pos; - int ind, fns; + u32 instr_pos, fns; + int ind; struct resolver resolver; struct callframe *frame; -/* + /* #ifdef DEBUG int num_resolvers; #endif @@ -3406,8 +3549,9 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe return interp_error(interp, "local resolvers fn start"); }; #endif - debug("pushed resolver %d i_%s i_%s %ld local_resolvers:%d \n", - resolver.label, + debug("pushed resolver 0x%04X-0x%04X i_%s i_%s %ld local_resolvers:%d \n", + label_instr_pos(*label), + (*label)->jump, instr_name(resolver.start_tag), instr_name(resolver.end_tag), cursor_count(&interp->resolver_stack, sizeof(resolver)), @@ -3437,21 +3581,86 @@ static int interp_jump(struct wasm_interp *interp, int jmp) return 1; } -static int pop_label_and_jump(struct wasm_interp *interp, struct label *label, int times) +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 NULL; + return p; +} + +static INLINE struct resolver *top_resolver(struct wasm_interp *interp, u32 index) +{ + return top_resolver_stack(&interp->resolver_stack, index); +} + +static int break_jump(struct wasm_interp *interp, struct resolver *resolver, + struct label *label) +{ + /* + debug("break jumping to %s %s\n", + instr_name(resolver->start_tag), + instr_name(resolver->end_tag) + ); + */ + + if (resolver->start_tag != i_loop) + return interp_jump(interp, label->jump); + + return interp_jump(interp, label_instr_pos(label)); +} + +static int pop_label_and_skip(struct wasm_interp *interp, struct label *label, + int times) { int i; + struct resolver resolver; assert(is_label_resolved(label)); + + if (unlikely(times == 0)) + return interp_error(interp, "can't pop label 0 times"); for (i = 0; i < times; i++) { - if (!cursor_drop(&interp->resolver_stack, - sizeof(struct resolver))) { - return interp_error(interp, "drop label"); + if (!pop_resolver(interp, &resolver)) { + return interp_error(interp, "top resolver"); } } return interp_jump(interp, label->jump); } +static int pop_label_and_break(struct wasm_interp *interp, struct label *label, + int times) +{ + int i; + struct resolver resolver; + assert(is_label_resolved(label)); + + if (unlikely(times == 0)) + return interp_error(interp, "can't pop label 0 times"); + + for (i = 0; i < times; i++) { + if (!pop_resolver(interp, &resolver)) { + return interp_error(interp, "pop resolver"); + } + } + + // we have a loop, push the popped resolver + if (resolver.start_tag == i_loop) { + debug("repushing resolver\n"); + if (unlikely(!cursor_push_resolver(&interp->resolver_stack, &resolver))) { + return interp_error(interp, "re-push loop resolver"); + } + } + + if (!(label = index_frame_label(interp, resolver.label))) { + return interp_error(interp, "index label"); + } + + return break_jump(interp, &resolver, label); +} + static int parse_block(struct expr_parser *p, struct block *block, u8 start_tag, u8 end_tag) { struct label *label = NULL; @@ -3470,11 +3679,7 @@ static int parse_block(struct expr_parser *p, struct block *block, u8 start_tag, block->instrs = p->code->start + label_instr_pos(label); block->instrs_len = (p->code->start + label->jump) - block->instrs; - if (unlikely(block->instrs_len < 0)) { - return interp_error(p->interp, "jump is before instr_pos ??"); - } - - return pop_label_and_jump(p->interp, label, 1); + return pop_label_and_skip(p->interp, label, 1); } if (!parse_instrs_until(p, end_tag, &block->instrs, &block->instrs_len)) @@ -3488,35 +3693,35 @@ static int parse_block(struct expr_parser *p, struct block *block, u8 start_tag, static INLINE int parse_memarg(struct cursor *code, struct memarg *memarg) { - return read_int(code, &memarg->align) && - read_int(code, &memarg->offset); + return read_u32(code, &memarg->align) && + read_u32(code, &memarg->offset); } static int parse_call_indirect(struct cursor *code, struct call_indirect *call_indirect) { - return read_int(code, &call_indirect->typeidx) && - read_int(code, &call_indirect->tableidx); + return read_u32(code, &call_indirect->typeidx) && + read_u32(code, &call_indirect->tableidx); } static int parse_br_table(struct cursor *code, struct errors *errs, struct br_table *br_table) { - int i; + u32 i; - if (unlikely(!read_int(code, &br_table->num_label_indices))) { + if (unlikely(!read_u32(code, &br_table->num_label_indices))) { return note_error(errs, code, "fail read br_table num_indices"); } for (i = 0; i < br_table->num_label_indices; i++) { - if (unlikely(!read_int(code, &br_table->label_indices[i]))) { + if (unlikely(!read_u32(code, &br_table->label_indices[i]))) { return note_error(errs, code, "failed to read br_table label %d/%d", i+1, br_table->num_label_indices); } } - if (unlikely(!read_int(code, &br_table->default_label))) { + if (unlikely(!read_u32(code, &br_table->default_label))) { return note_error(errs, code, "failed to parse default label"); } @@ -3532,7 +3737,7 @@ static int parse_select(struct cursor *code, struct errors *errs, u8 tag, return 1; } - if (unlikely(!read_int(code, &select->num_valtypes))) { + if (unlikely(!read_u32(code, &select->num_valtypes))) { return note_error(errs, code, "couldn't parse select valtype vec count"); } @@ -3577,17 +3782,29 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) case i_global_set: case i_br: case i_br_if: - case i_i32_const: - case i_i64_const: case i_ref_func: case i_table_set: case i_table_get: - if (!read_int(p->code, &op->integer)) { + if (!read_u32(p->code, &op->u32)) { return note_error(p->errs, p->code, "couldn't read int"); } return 1; + case i_i32_const: + if (!read_int(p->code, &op->i32)) { + return note_error(p->errs, p->code, + "couldn't read int"); + } + return 1; + + case i_i64_const: + if (!read_i64(p->code, &op->i64)) { + return note_error(p->errs, p->code, + "couldn't read i64"); + } + return 1; + case i_i32_load: case i_i64_load: case i_f32_load: @@ -3764,7 +3981,7 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op) static int branch_jump(struct wasm_interp *interp, u8 start_tag, u8 end_tag) { u8 *instrs; - int instrs_len; + u32 instrs_len; struct expr_parser parser; struct label *label; @@ -3777,7 +3994,7 @@ static int branch_jump(struct wasm_interp *interp, u8 start_tag, u8 end_tag) } if (is_label_resolved(label)) { - return pop_label_and_jump(interp, label, 1); + return pop_label_and_skip(interp, label, 1); } make_interp_expr_parser(interp, &parser); @@ -3815,6 +4032,30 @@ static int interp_block(struct wasm_interp *interp) return 1; } +static INLINE int interp_end(struct wasm_interp *interp) +{ + return pop_label_checkpoint(interp); + + /* + struct resolver resolver; + struct callframe *frame; + struct label *label; + + debug("interp end\n"); + + if (!pop_label(interp, &resolver, &frame, &label)) { + return interp_error(interp, "pop label at end inst"); + } + + if (resolver.start_tag == i_loop) { + debug("loop jumping at end instr\n"); + return interp_jump(interp, label->jump); + } + + return 1; + */ +} + static int interp_if(struct wasm_interp *interp) { struct val cond; @@ -3857,21 +4098,7 @@ static int interp_i32_eqz(struct wasm_interp *interp) return cursor_pushval(&interp->stack, &res); } -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 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) +static INLINE struct label *top_label(struct wasm_interp *interp, u32 index) { struct resolver *resolver; @@ -3887,18 +4114,28 @@ static int unresolved_break(struct wasm_interp *interp, int index) { struct expr_parser parser; struct callframe *frame; - struct label *label; + u32 instrs_len; u8 *instrs; - int instrs_len; - struct resolver *resolver; - debug("breaking %d times from unresolved label\n", index+1); + struct resolver *resolver = NULL; + struct label *label = NULL; + +#if DEBUG + int times; +#endif + make_interp_expr_parser(interp, &parser); if (unlikely(!(frame = top_callframe(&interp->callframes)))) { return interp_error(interp, "no top callframe?"); } + +#if DEBUG + times = index+1; +#endif + debug("breaking %d times from unresolved label\n", times); + while (index-- >= 0) { if (unlikely(!(resolver = top_resolver(interp, 0)))) { return interp_error(interp, "invalid resolver index %d", @@ -3911,7 +4148,7 @@ static int unresolved_break(struct wasm_interp *interp, int index) // TODO: breaking from functions (return) if (is_label_resolved(label)) { - if (!pop_label_and_jump(interp, label, 1)) + if (!pop_label_and_skip(interp, label, 1)) return interp_error(interp, "pop and jump"); else continue; @@ -3923,16 +4160,30 @@ static int unresolved_break(struct wasm_interp *interp, int index) } if (unlikely(!pop_label_checkpoint(interp))) { - return interp_error(interp, "pop label"); + return interp_error(interp, "pop label"); } + } + + debug("finished breaking %d times from unresolved label (it was a %s)\n", + times, + instr_name(resolver->start_tag)); + assert(resolver); + assert(label); + if (resolver->start_tag == i_loop) { + debug("jumping to start of loop\n"); + if (unlikely(!cursor_push_resolver(&interp->resolver_stack, + resolver))) { + return interp_error(interp, "re-push loop resolver"); + } + return interp_jump(interp, label_instr_pos(label)); } return 1; } -static int interp_br_jump(struct wasm_interp *interp, int index) +static int interp_br_jump(struct wasm_interp *interp, u32 index) { struct label *label; @@ -3941,18 +4192,34 @@ static int interp_br_jump(struct wasm_interp *interp, int index) } if (is_label_resolved(label)) { - return pop_label_and_jump(interp, label, index+1); + return pop_label_and_break(interp, label, index+1); } return unresolved_break(interp, index); } -static INLINE int interp_br(struct wasm_interp *interp, int ind) +static INLINE int interp_br(struct wasm_interp *interp, u32 ind) { return interp_br_jump(interp, ind); } -static INLINE int interp_br_if(struct wasm_interp *interp, int ind) +static INLINE int interp_br_table(struct wasm_interp *interp, + struct br_table *br_table) +{ + int i; + + if (!stack_pop_i32(interp, &i)) { + return interp_error(interp, "pop br_table index"); + } + + if ((u32)i < br_table->num_label_indices) { + return interp_br_jump(interp, br_table->label_indices[i]); + } + + return interp_br_jump(interp, br_table->default_label); +} + +static INLINE int interp_br_if(struct wasm_interp *interp, u32 ind) { int cond = 0; @@ -3967,7 +4234,7 @@ static INLINE int interp_br_if(struct wasm_interp *interp, int ind) return 1; } -static struct val *get_global_inst(struct wasm_interp *interp, int ind) +static struct val *get_global_inst(struct wasm_interp *interp, u32 ind) { struct global_inst *global_inst; @@ -3991,7 +4258,7 @@ static struct val *get_global_inst(struct wasm_interp *interp, int ind) return &global_inst->val; } -static int interp_global_get(struct wasm_interp *interp, int ind) +static int interp_global_get(struct wasm_interp *interp, u32 ind) { struct globalsec *section = &interp->module->global_section; struct val *global; @@ -4061,6 +4328,11 @@ static int interp_mem_offset(struct wasm_interp *interp, t->size = *N/8; t->pos = interp->memory.start + offset; + if (t->pos < interp->memory.start) { + return interp_error(interp, + "invalid memory offset %d\n", offset); + } + if (t->pos + t->size > interp->memory.p) { return interp_error(interp, "mem store oob pos:%d size:%d mem:%d", offset, t->size, @@ -4073,12 +4345,16 @@ static int interp_mem_offset(struct wasm_interp *interp, static int wrap_val(struct val *val, unsigned int size) { switch (val->type) { case val_i32: + if (size == 32) + return 1; //debug("before %d size %d (mask %lx)\n", val->num.i32, size, (1UL << size)-1); val->num.i32 &= (1UL << size)-1; //debug("after %d size %d (mask %lx)\n", val->num.i32, size, (1UL << size)-1); break; case val_i64: - val->num.i64 &= (1UL << size)-1; + if (size == 64) + return 1; + val->num.i64 &= (1ULL << size)-1; break; default: return 0; @@ -4103,8 +4379,9 @@ static int store_val(struct wasm_interp *interp, int i, } } - debug("storing %d at %ld, N:%d\n", val->num.i32, - target.pos - interp->memory.start, N); + debug("storing %d at %ld (%d bytes), N:%d\n", val->num.i32, + target.pos - interp->memory.start, + target.size, N); memcpy(target.pos, &val->num.i32, target.size); @@ -4124,6 +4401,112 @@ static INLINE int store_i32(struct wasm_interp *interp, int offset, int i) return store_simple(interp, offset, &val); } +static int interp_load(struct wasm_interp *interp, struct memarg *memarg, + enum valtype type, int N, int sign) +{ + struct memtarget target; + struct val out = {0}; + int i; + + (void)sign; + + out.type = type; + + if (unlikely(!stack_pop_i32(interp, &i))) { + return interp_error(interp, "pop stack"); + } + + if (unlikely(!interp_mem_offset(interp, &N, i, type, memarg, &target))) { + return interp_error(interp, "memory target"); + } + + memcpy(&out.num.i32, target.pos, target.size); + wrap_val(&out, target.size * 8); + debug("loading %d from %ld (copying %d bytes)\n", out.num.i32, + target.pos - interp->memory.start, target.size); + + if (unlikely(!stack_pushval(interp, &out))) { + return interp_error(interp, + "push to stack after load %s", valtype_name(type)); + } + + return 1; +} + +static INLINE int load_i32(struct wasm_interp *interp, int *i) +{ + struct memarg memarg = { .offset = 0, .align = 0 }; + if (!interp_load(interp, &memarg, val_i32, 0, -1)) { + return interp_error(interp, "load"); + } + return stack_pop_i32(interp, i); +} + +static int builtin_fd_write(struct wasm_interp *interp) +{ + struct val *fd, *iovs, *iovs_len, *written; + int iovec_data = 0; + int str_len = 0; + + if (!(fd = get_local(interp, 0))) + return interp_error(interp, "fd"); + + if (!(iovs = get_local(interp, 1))) + return interp_error(interp, "iovs"); + + if (!(iovs_len = get_local(interp, 2))) + return interp_error(interp, "iovs_len"); + + if (!(written = get_local(interp, 3))) + return interp_error(interp, "written"); + + debug("fd_write %d %d %d %d\n", + fd->num.i32, + iovs->num.i32, + iovs_len->num.i32, + written->num.i32 + ); + + if (!stack_push_i32(interp, iovs->num.i32)) { + return interp_error(interp, "push iovec ptr"); + } + + if (!load_i32(interp, &iovec_data)) { + return interp_error(interp, "load iovec data"); + } + + if (!stack_push_i32(interp, iovs->num.i32 + 4)) { + return interp_error(interp, "push iovec ptr"); + } + + if (!load_i32(interp, &str_len)) { + return interp_error(interp, "load iovec data"); + } + + debug("fd_write len %d\n", str_len); + + if (interp->memory.start + iovec_data + str_len >= + interp->memory.p) { + return interp_error(interp, "fd_write oob"); + } + + if (fd->num.i32 >= 10) { + return interp_error(interp, "weird fd %d", fd->num.i32); + } + + written->num.i32 = write(fd->num.i32, + interp->memory.start + iovec_data, + str_len + ); + + if (written->num.i32 != str_len) { + return interp_error(interp, "written %d != %d", + written->num.i32, str_len); + } + + return stack_push_i32(interp, written->num.i32); +} + static int builtin_get_args(struct wasm_interp *interp) { struct val *argv, *argv_buf; @@ -4182,37 +4565,6 @@ static int interp_store(struct wasm_interp *interp, struct memarg *memarg, return store_val(interp, i, memarg, type, &c, N); } -static int interp_load(struct wasm_interp *interp, struct memarg *memarg, - enum valtype type, int N, int sign) -{ - struct memtarget target; - struct val out = {0}; - int i; - - (void)sign; - - out.type = type; - - if (unlikely(!stack_pop_i32(interp, &i))) { - return interp_error(interp, "pop stack"); - } - - if (unlikely(!interp_mem_offset(interp, &N, i, type, memarg, &target))) { - return interp_error(interp, "memory target"); - } - - memcpy(&out.num.i32, target.pos, target.size); - wrap_val(&out, target.size * 8); - debug("loading %d from %ld (copying %d bytes)\n", out.num.i32, - target.pos - interp->memory.start, target.size); - - if (unlikely(!stack_pushval(interp, &out))) { - return interp_error(interp, - "push to stack after load %s", valtype_name(type)); - } - - return 1; -} static INLINE int interp_global_set(struct wasm_interp *interp, int global_ind) { @@ -4238,8 +4590,7 @@ static INLINE int active_pages(struct wasm_interp *interp) static int interp_memory_grow(struct wasm_interp *interp, u8 memidx) { - int pages = 0, prev_size; - unsigned int grow; + int pages = 0, prev_size, grow; (void)memidx; @@ -4279,6 +4630,36 @@ static INLINE int interp_memory_size(struct wasm_interp *interp, u8 memidx) return 1; } +static INLINE int interp_i32_eq(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) { + return interp_error(interp, "binop prep"); + } + + return stack_push_i32(interp, lhs.num.i32 == rhs.num.i32); +} + +static INLINE int interp_i32_wrap_i64(struct wasm_interp *interp) +{ + int64_t n; + if (unlikely(!stack_pop_i64(interp, &n))) + return interp_error(interp, "pop"); + return stack_push_i32(interp, (int)n); +} + +static INLINE int interp_i32_xor(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) { + return interp_error(interp, "binop prep"); + } + + return stack_push_i32(interp, lhs.num.i32 ^ rhs.num.i32); +} + static INLINE int interp_i32_ne(struct wasm_interp *interp) { struct val lhs, rhs, c; @@ -4450,7 +4831,7 @@ static int interp_loop(struct wasm_interp *interp) } static INLINE int table_set(struct wasm_interp *interp, - struct table_inst *table, int ind, struct val *val) + struct table_inst *table, u32 ind, struct val *val) { if (unlikely(ind >= table->num_refs)) { @@ -4478,7 +4859,7 @@ static INLINE int table_set(struct wasm_interp *interp, return 1; } -static int interp_table_set(struct wasm_interp *interp, int tableidx) +static int interp_table_set(struct wasm_interp *interp, u32 tableidx) { struct table_inst *table; struct val val; @@ -4503,10 +4884,11 @@ static int interp_table_set(struct wasm_interp *interp, int tableidx) return table_set(interp, table, ind, &val); } -static int interp_memory_init(struct wasm_interp *interp, int dataidx) +static int interp_memory_init(struct wasm_interp *interp, u32 dataidx) { struct wdata *data; - int count, src, dst, num_data; + int count, src, dst; + u32 num_data; num_data = interp->module->data_section.num_datas; if (unlikely(dataidx >= num_data)) { @@ -4525,10 +4907,7 @@ static int interp_memory_init(struct wasm_interp *interp, int dataidx) if(unlikely(!stack_pop_i32(interp, &dst))) return interp_error(interp, "pop dst"); - debug("memory_init src:%d dst:%d count:%d\n", - src, dst, count); - - if (src + count > data->bytes_len) { + if (src + count > (int)data->bytes_len) { return interp_error(interp, "count %d > data len %d", count, data->bytes_len); } @@ -4538,8 +4917,11 @@ static int interp_memory_init(struct wasm_interp *interp, int dataidx) count, interp->memory.p - interp->memory.start); } - memcpy(interp->memory.start + dst + count, - data->bytes + src + count, + debug("memory_init src:%d dst:%d count:%d\n", + src, dst, count); + + memcpy(interp->memory.start + dst, + data->bytes + src, count); return 1; @@ -4597,13 +4979,13 @@ static int interp_table_init(struct wasm_interp *interp, } for (; num_inits; num_inits--, dst++, src++) { - if (unlikely(src + num_inits > interp->module_inst.num_elements)) { + if (unlikely((u32)src + num_inits > interp->module_inst.num_elements)) { return interp_error(interp, "index oob elem.elem s+n %d (max %d)", src + num_inits, interp->module_inst.num_elements + 1); } - if (unlikely(dst + num_inits > table->num_refs)) { + if (unlikely((u32)dst + num_inits > table->num_refs)) { return interp_error(interp, "index oob tab.elem d+n %d (max %d)", dst + num_inits, table->num_refs + 1); @@ -4681,16 +5063,17 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) case i_selects: return interp_select(interp, &instr->select); - case i_local_get: return interp_local_get(interp, instr->integer); - case i_local_set: return interp_local_set(interp, instr->integer); - case i_local_tee: return interp_local_tee(interp, instr->integer); - case i_global_get: return interp_global_get(interp, instr->integer); - case i_global_set: return interp_global_set(interp, instr->integer); + case i_local_get: return interp_local_get(interp, instr->i32); + case i_local_set: return interp_local_set(interp, instr->i32); + case i_local_tee: return interp_local_tee(interp, instr->i32); + case i_global_get: return interp_global_get(interp, instr->i32); + case i_global_set: return interp_global_set(interp, instr->i32); case i_i32_eqz: return interp_i32_eqz(interp); case i_i32_add: return interp_i32_add(interp); case i_i32_sub: return interp_i32_sub(interp); - case i_i32_const: return interp_i32_const(interp, instr->integer); + case i_i32_const: return interp_i32_const(interp, instr->i32); + case i_i32_div_u: return interp_i32_div_u(interp); case i_i32_ge_u: return interp_i32_ge_u(interp); case i_i32_ge_s: return interp_i32_ge_s(interp); case i_i32_gt_u: return interp_i32_gt_u(interp); @@ -4703,10 +5086,20 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) case i_i32_or: return interp_i32_or(interp); case i_i32_and: return interp_i32_and(interp); case i_i32_mul: return interp_i32_mul(interp); + case i_i32_xor: return interp_i32_xor(interp); case i_i32_ne: return interp_i32_ne(interp); - + case i_i32_eq: return interp_i32_eq(interp); + case i_i32_wrap_i64:return interp_i32_wrap_i64(interp); + + case i_i64_eqz: return interp_i64_eqz(interp); + case i_i64_gt_s: return interp_i64_gt_s(interp); + case i_i64_gt_u: return interp_i64_gt_u(interp); + case i_i64_ge_u: return interp_i64_ge_u(interp); + case i_i64_div_u: return interp_i64_div_u(interp); + case i_i64_mul: return interp_i64_mul(interp); case i_i64_shl: return interp_i64_shl(interp); case i_i64_or: return interp_i64_or(interp); + case i_i64_sub: return interp_i64_sub(interp); case i_i64_const: return interp_i64_const(interp, instr->i64); case i_i64_extend_i32_u: return interp_extend(interp, val_i64, val_i32, 0); @@ -4740,16 +5133,17 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) 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); + case i_end: return interp_end(interp); + case i_call: return interp_call(interp, instr->i32); case i_call_indirect: return interp_call_indirect(interp, &instr->call_indirect); case i_block: return interp_block(interp); - case i_br: return interp_br(interp, instr->integer); - case i_br_if: return interp_br_if(interp, instr->integer); + case i_br: return interp_br(interp, instr->i32); + case i_br_table: return interp_br_table(interp, &instr->br_table); + case i_br_if: return interp_br_if(interp, instr->i32); case i_memory_size: return interp_memory_size(interp, instr->memidx); case i_memory_grow: return interp_memory_grow(interp, instr->memidx); case i_table_op: return interp_error(interp, "todo: interp table_op"); - case i_table_set: return interp_table_set(interp, instr->integer); + case i_table_set: return interp_table_set(interp, instr->i32); case i_return: return interp_return(interp); default: interp_error(interp, "unhandled instruction %s 0x%x", @@ -4809,8 +5203,10 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, struct callframe *frame, struct cursor *code) { struct resolver *resolver; - struct label *label; + //struct label *label; int num_resolvers = 0; + (void)frame; + (void)code; if (unlikely(!(resolver = top_resolver(interp, 0)))) { // no more resolvers, we done. @@ -4828,6 +5224,7 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, } // 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)))) { @@ -4843,6 +5240,7 @@ static enum interp_end interp_code_end(struct wasm_interp *interp, return interp_end_cont; } + */ return interp_end_next; } @@ -4904,7 +5302,7 @@ static int interp_code(struct wasm_interp *interp) static int find_function(struct module *module, const char *name) { struct wexport *export; - int i; + u32 i; for (i = 0; i < module->export_section.num_exports; i++) { export = &module->export_section.exports[i]; @@ -4949,7 +5347,7 @@ void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t a static int count_fn_locals(struct func *func) { - int i, num_locals = 0; + u32 i, num_locals = 0; num_locals += func->functype->params.num_valtypes; @@ -4965,7 +5363,7 @@ static int count_fn_locals(struct func *func) static int calculate_tables_size(struct module *module) { - int i, num_tables, size; + u32 i, num_tables, size; struct table *tables; if (!was_section_parsed(module, section_table)) @@ -4984,10 +5382,9 @@ static int calculate_tables_size(struct module *module) static int alloc_tables(struct wasm_interp *interp) { - int size; struct table *t; struct table_inst *inst; - int i; + u32 i, size; if (!was_section_parsed(interp->module, section_table)) return 1; @@ -5021,7 +5418,7 @@ static int alloc_tables(struct wasm_interp *interp) static int calculate_locals_size(struct module *module) { - int i, locals_size = 0; + u32 i, locals_size = 0; struct func *func; for (i = 0; i < module->num_funcs; i++) { @@ -5037,7 +5434,7 @@ static int calculate_locals_size(struct module *module) static int alloc_locals(struct module *module, struct cursor *mem, struct errors *errs) { - int i, j, num_locals, size, sizes = 0; + u32 i, j, k, num_locals, size, sizes = 0, ind; struct func *func; for (i = 0; i < module->num_funcs; i++) { @@ -5057,9 +5454,23 @@ static int alloc_locals(struct module *module, struct cursor *mem, func->name); } - for (j = 0; j < func->num_locals; j++) { + for (j = 0, ind = 0; j < func->functype->params.num_valtypes; j++, ind++) { func->locals[j].val.type = func->functype->params.valtypes[j]; } + + if (func->type != func_type_wasm) + continue; + + for (j = 0; j < func->wasm_func->num_locals; j++) { + for (k = 0; k < func->wasm_func->locals[j].val.num.u32; k++, ind++) { + debug("initializing function %d local %d to type %s\n", + i, ind, valtype_name( + func->wasm_func->locals[j].val.type)); + + func->locals[ind].val.type = + func->wasm_func->locals[j].val.type; + } + } } debug("alloc_locals sizes %d\n", sizes); @@ -5134,7 +5545,7 @@ static int init_globals(struct wasm_interp *interp) { struct global *globals, *global; struct global_inst *global_insts, *global_inst; - int i; + u32 i; if (!was_section_parsed(interp->module, section_global)) { // nothing to init @@ -5159,7 +5570,7 @@ static int init_globals(struct wasm_interp *interp) static int count_element_insts(struct module *module) { struct elem *elem; - int i, size = 0; + u32 i, size = 0; if (!was_section_parsed(module, section_element)) return 0; @@ -5230,7 +5641,7 @@ static int init_memories(struct wasm_interp *interp) static int init_tables(struct wasm_interp *interp) { struct elem *elem; - int i; + u32 i; if (!was_section_parsed(interp->module, section_table)) return 1; @@ -5254,8 +5665,8 @@ static int init_elements(struct wasm_interp *interp) struct elem *elems, *elem; struct elem_inst *inst; struct expr *init; - int count = 0; - int i, j; + u32 count = 0; + u32 i, j; debug("init elements\n"); diff --git a/src/wasm.h b/src/wasm.h @@ -41,8 +41,8 @@ enum limit_type { }; struct limits { - unsigned int min; - unsigned int max; + u32 min; + u32 max; enum limit_type type; }; @@ -69,7 +69,7 @@ enum reftype { struct resulttype { unsigned char *valtypes; /* enum valtype */ - int num_valtypes; + u32 num_valtypes; }; struct functype { @@ -84,7 +84,7 @@ struct table { struct tablesec { struct table *tables; - int num_tables; + u32 num_tables; }; enum elem_mode { @@ -94,24 +94,26 @@ enum elem_mode { }; struct expr { - unsigned char *code; - int code_len; + u8 *code; + u32 code_len; }; struct refval { - int addr; + u32 addr; }; struct table_inst { struct refval *refs; enum reftype reftype; - int num_refs; + u32 num_refs; }; struct numval { union { int i32; - u64 i64; + u32 u32; + int64_t i64; + uint64_t u64; float f32; double f64; }; @@ -133,9 +135,9 @@ struct elem_inst { struct elem { struct expr offset; - int tableidx; + u32 tableidx; struct expr *inits; - int num_inits; + u32 num_inits; enum elem_mode mode; enum reftype reftype; struct val val; @@ -149,17 +151,17 @@ struct customsec { struct elemsec { struct elem *elements; - int num_elements; + u32 num_elements; }; struct memsec { struct limits *mems; /* memtype */ - int num_mems; + u32 num_mems; }; struct funcsec { - unsigned int *type_indices; - int num_indices; + u32 *type_indices; + u32 num_indices; }; enum mut { @@ -174,12 +176,12 @@ struct globaltype { struct globalsec { struct global *globals; - int num_globals; + u32 num_globals; }; struct typesec { struct functype *functypes; - int num_functypes; + u32 num_functypes; }; enum import_type { @@ -192,7 +194,7 @@ enum import_type { struct importdesc { enum import_type type; union { - unsigned int typeidx; + u32 typeidx; struct limits tabletype; struct limits memtype; struct globaltype globaltype; @@ -208,7 +210,7 @@ struct import { struct importsec { struct import *imports; - int num_imports; + u32 num_imports; }; struct global { @@ -225,7 +227,7 @@ struct local { struct wasm_func { struct expr code; struct local *locals; - int num_locals; + u32 num_locals; }; enum func_type { @@ -239,7 +241,7 @@ struct func { struct builtin *builtin; }; struct local *locals; - int num_locals; + u32 num_locals; struct functype *functype; enum func_type type; const char *name; @@ -247,7 +249,7 @@ struct func { struct codesec { struct wasm_func *funcs; - int num_funcs; + u32 num_funcs; }; enum exportdesc { @@ -259,13 +261,13 @@ enum exportdesc { struct wexport { const char *name; - unsigned int index; + u32 index; enum exportdesc desc; }; struct exportsec { struct wexport *exports; - int num_exports; + u32 num_exports; }; struct section { @@ -499,33 +501,33 @@ struct blocktype { struct block { struct blocktype type; unsigned char *instrs; - int instrs_len; + u32 instrs_len; }; struct memarg { - int offset; - int align; + u32 offset; + u32 align; }; struct br_table { - int num_label_indices; - int label_indices[32]; - int default_label; + u32 num_label_indices; + u32 label_indices[32]; + u32 default_label; }; struct call_indirect { - int tableidx; - int typeidx; + u32 tableidx; + u32 typeidx; }; struct table_init { - int tableidx; - int elemidx; + u32 tableidx; + u32 elemidx; }; struct select_instr { u8 *valtypes; - int num_valtypes; + u32 num_valtypes; }; struct instr { @@ -540,8 +542,10 @@ struct instr { struct block block; double fp_double; float fp_single; - int integer; + int i32; + u32 u32; int64_t i64; + u64 u64; unsigned char memidx; enum reftype reftype; }; @@ -553,14 +557,14 @@ enum datamode { }; struct wdata_active { - int mem_index; + u32 mem_index; struct expr offset_expr; }; struct wdata { struct wdata_active active; - unsigned char *bytes; - int bytes_len; + u8 *bytes; + u32 bytes_len; enum datamode mode; }; @@ -570,7 +574,7 @@ struct datasec { }; struct startsec { - int start_fn; + u32 start_fn; }; struct module { @@ -578,7 +582,7 @@ struct module { unsigned int custom_sections; struct func *funcs; - int num_funcs; + u32 num_funcs; struct customsec custom_section[MAX_CUSTOM_SECTIONS]; struct typesec type_section; @@ -602,7 +606,7 @@ struct label { struct callframe { struct cursor code; - int fn; + u32 fn; }; struct resolver { @@ -620,9 +624,9 @@ struct module_inst { struct global_inst *globals; struct elem_inst *elements; - int num_tables; - int num_globals; - int num_elements; + u32 num_tables; + u32 num_globals; + u32 num_elements; int start_fn; unsigned char *globals_init; diff --git a/wasm/hello-c.c b/wasm/hello-c.c @@ -1,14 +0,0 @@ -#include <stdio.h> - -int add(int a, int b, int c, int d) -{ - return a + b + c + d; -} - -int main(int argc, const char *argv[]) -{ - printf("Hello, world? %d\n", add(1,2,3,4)); - return 0; -} - - diff --git a/wasm/hello-c.wasm b/wasm/hello-c.wasm Binary files differ. diff --git a/wasm/hello.wasm b/wasm/hello.wasm Binary files differ. diff --git a/wasm/hello.wat b/wasm/hello.wat @@ -10,12 +10,8 @@ ) (func $start (result i32) (local i32 i32) - i32.const 65537 - local.set 0 - local.get 0 + i32.const 1 i32.const 2 - call $add - i32.const 3 call $sub ) (export "start" (func $start)) diff --git a/wasm/loop.wat b/wasm/loop.wat @@ -12,15 +12,17 @@ (local i32 i32) i32.const 0 local.set 0 - loop - local.get 0 - i32.const 1 - i32.add - local.set 0 - local.get 0 - i32.const 4 - i32.gt_u - br_if 0 + block + loop + local.get 0 + i32.const 1 + i32.add + local.set 0 + i32.const 4 + local.get 0 + i32.gt_u + br_if 0 + end end i32.const 0 )