commit e669c2d69908ffea1de08f9da01abe041b28fe62
parent a0686835b5209e4ec4b3b4a5856f4859229edba9
Author: William Casarin <jb55@jb55.com>
Date: Tue, 20 Jul 2021 14:42:35 -0700
hello-c executes to end, but is still broken
Diffstat:
3 files changed, 238 insertions(+), 93 deletions(-)
diff --git a/src/cursor.h b/src/cursor.h
@@ -166,17 +166,24 @@ static inline int pull_data_into_cursor(struct cursor *cursor,
return 1;
}
-
-static inline int cursor_drop(struct cursor *cur, int len)
+static inline int cursor_dropn(struct cursor *cur, int size, int n)
{
- if (unlikely(cur->p - len < cur->start)) {
+ if (n == 0)
+ return 1;
+
+ if (unlikely(cur->p - size*n < cur->start)) {
return 0;
}
- cur->p -= len;
+ cur->p -= size*n;
return 1;
}
+static inline int cursor_drop(struct cursor *cur, int size)
+{
+ return cursor_dropn(cur, size, 1);
+}
+
static inline unsigned char *cursor_top(struct cursor *cur, int len)
{
if (unlikely(cur->p - len < cur->start)) {
diff --git a/src/wasm.c b/src/wasm.c
@@ -26,6 +26,8 @@
static const int MAX_LABELS = 128;
+static int interp_code(struct wasm_interp *interp);
+
struct expr_parser {
struct wasm_interp *interp; // optional...
struct cursor *code;
@@ -566,6 +568,7 @@ static char *instr_name(enum instr_tag tag)
case i_table_op: return "table_op";
case i_table_get: return "table_get";
case i_table_set: return "table_set";
+ case i_selects: return "selects";
}
snprintf(unk, sizeof(unk), "0x%02x", tag);
@@ -581,14 +584,15 @@ static INLINE int was_section_parsed(struct module *module,
return module->parsed & (1 << section);
}
-
static INLINE int cursor_push_callframe(struct cursor *cur, struct callframe *frame)
{
+ //debug("pushing callframe %d fn:%d\n", ++callframe_cnt, frame->fn);
return cursor_push(cur, (u8*)frame, sizeof(*frame));
}
static INLINE int cursor_drop_callframe(struct cursor *cur)
{
+ //debug("dropping callframe %d fn:%d\n", callframe_cnt--, top_callframe(cur)->fn);
return cursor_drop(cur, sizeof(struct callframe));
}
@@ -613,10 +617,10 @@ void print_error_backtrace(struct errors *errors)
while (errs.p < errors->cur.p) {
if (!cursor_pull_error(&errs, &err)) {
- fprintf(stderr, "backtrace: couldn't pull error\n");
+ printf("backtrace: couldn't pull error\n");
return;
}
- fprintf(stderr, "%08x:%s\n", err.pos, err.msg);
+ printf("%08x:%s\n", err.pos, err.msg);
}
}
@@ -1442,7 +1446,6 @@ static int cursor_push_nullval(struct cursor *stack)
return cursor_pushval(stack, &val);
}
-#ifdef DEBUG
static const char *show_instr(struct instr *instr)
{
struct cursor buf;
@@ -1526,6 +1529,9 @@ static const char *show_instr(struct instr *instr)
cursor_push_str(&buf, tmp);
break;
+ case i_selects:
+ break;
+
case i_br_table:
break;
@@ -1685,7 +1691,6 @@ static const char *show_instr(struct instr *instr)
cursor_push_byte(&buf, 0);
return buffer;
}
-#endif
static int eval_const_instr(struct instr *instr, struct errors *errs,
struct cursor *stack)
@@ -2836,6 +2841,39 @@ static struct functype *get_function_type(struct wasm_interp *interp, int ind)
return interp->module->funcs[ind].functype;
}
+static INLINE int count_local_resolvers(struct wasm_interp *interp, int *count)
+{
+ int offset;
+ u8 *p;
+ *count = 0;
+ if (unlikely(!cursor_top_int(&interp->resolver_offsets, &offset))) {
+ return interp_error(interp, "no top resolver offset?");
+ }
+ p = interp->resolver_stack.start + offset * sizeof(struct resolver);
+ if (unlikely(p < interp->resolver_stack.start ||
+ p >= interp->resolver_stack.end)) {
+ return interp_error(interp, "resolver offset oob?");
+ }
+ *count = (interp->resolver_stack.p - p) / sizeof(struct resolver);
+ return 1;
+}
+
+static INLINE int drop_callframe(struct wasm_interp *interp)
+{
+ int count, offset;
+
+ if (!count_local_resolvers(interp, &count) != 0) {
+ return interp_error(interp, "unclean callframe drop, still have"
+ " %d unpopped labels", count);
+ }
+
+ if (!cursor_popint(&interp->resolver_offsets, &offset)) {
+ return interp_error(interp, "pop resolver_offsets");
+ }
+
+ return cursor_drop_callframe(&interp->callframes);
+}
+
static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *func, int fn)
{
struct callframe callframe;
@@ -2844,12 +2882,24 @@ static INLINE int call_wasm_func(struct wasm_interp *interp, struct wasm_func *f
make_cursor(func->code.code, func->code.code + func->code.code_len, &callframe.code);
callframe.fn = fn;
+ assert(func->code.code_len > 0);
+
if (unlikely(!cursor_push_callframe(&interp->callframes, &callframe)))
return interp_error(interp, "oob cursor_pushcode");
+ if (unlikely(!interp_code(interp))) {
+ return interp_error(interp, "call %s:%d",
+ get_function_name(interp->module, fn),
+ fn);
+ }
+
+ if (unlikely(!drop_callframe(interp)))
+ return interp_error(interp, "drop callframe");
+
return 1;
}
+
static INLINE int call_builtin_func(struct wasm_interp *interp, struct builtin *builtin, int fn)
{
struct callframe callframe = {};
@@ -2864,7 +2914,10 @@ static INLINE int call_builtin_func(struct wasm_interp *interp, struct builtin *
if (!builtin->fn(interp))
return interp_error(interp, "builtin trap");
- return cursor_drop_callframe(&interp->callframes);
+ if (unlikely(!drop_callframe(interp)))
+ return interp_error(interp, "pop callframe");
+
+ return 1;
}
static INLINE int call_func(struct wasm_interp *interp, struct func *func, int fn)
@@ -2888,23 +2941,7 @@ static INLINE int count_resolvers(struct wasm_interp *interp)
return cursor_count(&interp->resolver_stack, sizeof(struct resolver));
}
-static INLINE int count_local_resolvers(struct wasm_interp *interp, int *count)
-{
- int offset;
- u8 *p;
- if (unlikely(!cursor_top_int(&interp->resolver_offsets, &offset))) {
- return interp_error(interp, "no top resolver offset?");
- }
- p = interp->resolver_stack.start + offset * sizeof(struct resolver);
- if (unlikely(p < interp->resolver_stack.start ||
- p >= interp->resolver_stack.end)) {
- return interp_error(interp, "resolver offset oob?");
- }
- *count = (interp->resolver_stack.p - p) / sizeof(struct resolver);
- return 1;
-}
-
-static int prepare_call(struct wasm_interp *interp, int func_index)
+static int call_function(struct wasm_interp *interp, int func_index)
{
static char buf[128];
int i;
@@ -2978,35 +3015,24 @@ static int prepare_call(struct wasm_interp *interp, int func_index)
return 1;
}
-static int interp_code(struct wasm_interp *interp);
-
static int interp_call(struct wasm_interp *interp, int func_index)
{
#ifdef DEBUG
- struct callframe *prev_frame;
+ struct callframe prev_frame;
- prev_frame = top_callframe(&interp->callframes);
+ assert(top_callframe(&interp->callframes));
+ memcpy(&prev_frame, top_callframe(&interp->callframes), sizeof(struct callframe));
#endif
- if (unlikely(!prepare_call(interp, func_index))) {
- interp_error(interp, "prepare");
- return 0;
+ if (unlikely(!call_function(interp, func_index))) {
+ return interp_error(interp, "prepare");
}
- if (unlikely(!interp_code(interp))) {
- return interp_error(interp, "call %s:%d",
- get_function_name(interp->module, func_index),
- func_index);
- }
-
- if (unlikely(!cursor_drop_callframe(&interp->callframes)))
- return interp_error(interp, "pop callframe");
-
debug("returning from %s:%d to %s:%d\n",
get_function_name(interp->module, func_index),
func_index,
- prev_frame ? get_function_name(interp->module, prev_frame->fn) : "",
- prev_frame ? prev_frame->fn : -1);
+ get_function_name(interp->module, prev_frame.fn),
+ prev_frame.fn);
return 1;
}
@@ -3085,6 +3111,10 @@ static int interp_call_indirect(struct wasm_interp *interp, struct call_indirect
ref, interp->module->num_funcs-1);
}
+ debug("calling %s:%d indirectly",
+ get_function_name(interp->module, ref->addr),
+ ref->addr);
+
return interp_call(interp, ref->addr);
}
@@ -3161,14 +3191,17 @@ static INLINE int resolve_label(struct label *label, struct cursor *code)
static INLINE int pop_resolver(struct wasm_interp *interp,
struct resolver *resolver)
{
+ /*
#ifdef DEBUG
int num_resolvers;
#endif
+*/
if (!cursor_pop(&interp->resolver_stack, (u8*)resolver, sizeof(*resolver))) {
return interp_error(interp, "pop resolver");
}
+ /*
#ifdef DEBUG
if (unlikely(!count_local_resolvers(interp, &num_resolvers))) {
return interp_error(interp, "local resolvers fn start");
@@ -3182,6 +3215,7 @@ static INLINE int pop_resolver(struct wasm_interp *interp,
count_resolvers(interp),
num_resolvers
);
+ */
return 1;
}
@@ -3263,8 +3297,10 @@ static int upsert_label(struct wasm_interp *interp, int fn,
return 0;
}
+ /*
debug("upsert_label: %d labels for %s:%d\n",
*num_labels, get_function_name(interp->module, fn), fn);
+ */
*ind = *num_labels;
if (unlikely(!(label = index_label(&interp->labels, fn, *ind))))
@@ -3296,9 +3332,11 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe
struct resolver resolver;
struct callframe *frame;
+/*
#ifdef DEBUG
int num_resolvers;
#endif
+*/
resolver.start_tag = start_tag;
resolver.end_tag = end_tag;
@@ -3330,6 +3368,7 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe
return interp_error(interp, "push label index to resolver stack oob");
}
+ /*
#ifdef DEBUG
if (unlikely(!count_local_resolvers(interp, &num_resolvers))) {
return interp_error(interp, "local resolvers fn start");
@@ -3341,6 +3380,7 @@ static int push_label_checkpoint(struct wasm_interp *interp, struct label **labe
instr_name(resolver.end_tag),
cursor_count(&interp->resolver_stack, sizeof(resolver)),
num_resolvers);
+ */
return 1;
}
@@ -3451,14 +3491,37 @@ static int parse_br_table(struct cursor *code, struct errors *errs,
return 1;
}
-static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op)
+static int parse_select(struct cursor *code, struct errors *errs, u8 tag,
+ struct select_instr *select)
{
+ if (tag == i_select) {
+ select->num_valtypes = 0;
+ select->valtypes = NULL;
+ return 1;
+ }
+
+ if (unlikely(!read_int(code, &select->num_valtypes))) {
+ return note_error(errs, code,
+ "couldn't parse select valtype vec count");
+ }
+ select->valtypes = code->p;
+ code->p += select->num_valtypes;
+
+ return 1;
+}
+
+static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op)
+{
op->pos = p->code->p - 1 - p->code->start;
op->tag = tag;
switch (tag) {
// two-byte instrs
+ case i_select:
+ case i_selects:
+ return parse_select(p->code, p->errs, tag, &op->select);
+
case i_memory_size:
case i_memory_grow:
return pull_byte(p->code, &op->memidx);
@@ -3487,7 +3550,11 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op)
case i_ref_func:
case i_table_set:
case i_table_get:
- return leb128_read(p->code, (unsigned int*)&op->integer);
+ if (!read_int(p->code, &op->integer)) {
+ return note_error(p->errs, p->code,
+ "couldn't read int");
+ }
+ return 1;
case i_i32_load:
case i_i64_load:
@@ -3529,7 +3596,6 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op)
case i_nop:
case i_return:
case i_drop:
- case i_select:
case i_i32_eqz:
case i_i32_eq:
case i_i32_ne:
@@ -4438,8 +4504,6 @@ static int interp_table_init(struct wasm_interp *interp,
elem_inst = &interp->module_inst.elements[src];
- debug("table set count %d src %d dst %d\n",
- num_inits, src, dst);
if (!table_set(interp, table, dst, &elem_inst->val)) {
return interp_error(interp,
"table set failed for table %d ind %d");
@@ -4449,6 +4513,50 @@ static int interp_table_init(struct wasm_interp *interp,
return 1;
}
+static int interp_select(struct wasm_interp *interp, struct select_instr *select)
+{
+ struct val top, bottom;
+ int c;
+
+ (void)select;
+
+ if (unlikely(!stack_pop_i32(interp, &c)))
+ return interp_error(interp, "pop select");
+
+ if (unlikely(!stack_popval(interp, &top)))
+ return interp_error(interp, "pop val top");
+
+ if (unlikely(!stack_popval(interp, &bottom)))
+ return interp_error(interp, "pop val bottom");
+
+ if (unlikely(top.type != bottom.type))
+ return interp_error(interp, "type mismatch, %s != %s",
+ valtype_name(top.type),
+ valtype_name(bottom.type));
+
+ if (c != 0)
+ return stack_pushval(interp, &bottom);
+ else
+ return stack_pushval(interp, &top);
+}
+
+static int interp_return(struct wasm_interp *interp)
+{
+ int count;
+
+ if (unlikely(!count_local_resolvers(interp, &count))) {
+ return interp_error(interp, "failed to count fn labels?");
+ }
+
+ if (unlikely(!cursor_dropn(&interp->resolver_stack,
+ sizeof(struct resolver), count))) {
+ return interp_error(interp, "failed to drop %d local labels",
+ count);
+ }
+
+ return i_return;
+}
+
static int interp_instr(struct wasm_interp *interp, struct instr *instr)
{
interp->ops++;
@@ -4462,6 +4570,9 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr)
switch (instr->tag) {
case i_unreachable: return interp_error(interp, "unreachable");
case i_nop: return 1;
+ case i_select:
+ 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);
@@ -4531,7 +4642,7 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr)
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_return: return 1;
+ case i_return: return interp_return(interp);
default:
interp_error(interp, "unhandled instruction %s 0x%x",
instr_name(instr->tag), instr->tag);
@@ -4565,10 +4676,12 @@ static INLINE int interp_parse_instr(struct wasm_interp *interp,
}
instr->tag = tag;
+ instr->pos = code->p - 1 - code->start;
+ instr->tag = tag;
if (!is_control_instr(tag) &&
!parse_instr(parser, instr->tag, instr)) {
- return interp_error(interp, "parse instr");
+ return interp_error(interp, "parse instr %s", instr_name(tag));
}
return 1;
@@ -4587,7 +4700,7 @@ static enum interp_end interp_code_end(struct wasm_interp *interp,
{
struct resolver *resolver;
struct label *label;
- int offset, num_resolvers = 0;
+ int num_resolvers = 0;
if (unlikely(!(resolver = top_resolver(interp, 0)))) {
// no more resolvers, we done.
@@ -4601,9 +4714,6 @@ static enum interp_end interp_code_end(struct wasm_interp *interp,
debug("interp_code_end local resolvers: %d\n", num_resolvers);
if (num_resolvers == 0) {
- if (!cursor_popint(&interp->resolver_offsets, &offset)) {
- return interp_error(interp, "pop resolver_offsets");
- }
return interp_end_done;
}
@@ -4640,6 +4750,7 @@ static int interp_code(struct wasm_interp *interp)
struct expr_parser parser;
struct cursor *code;
struct callframe *frame;
+ int ret;
make_interp_expr_parser(interp, &parser);
@@ -4653,6 +4764,8 @@ static int interp_code(struct wasm_interp *interp)
}
if (unlikely(!interp_parse_instr(interp, code, &parser, &instr))) {
+ cursor_print_around(code, 5);
+ debug("end ? %d\n", top_callframe(&interp->callframes)->fn);
return interp_error(interp, "parse instr");
}
@@ -4665,10 +4778,13 @@ static int interp_code(struct wasm_interp *interp)
}
}
- if (unlikely(!interp_instr(interp, &instr))) {
+ if (unlikely(!(ret = interp_instr(interp, &instr)))) {
return interp_error(interp, "interp instr %s",
- instr_name(instr.tag));
+ show_instr(&instr));
}
+
+ if (ret == i_return)
+ return 1;
}
return 1;
@@ -4740,6 +4856,9 @@ static int calculate_tables_size(struct module *module)
int i, num_tables, size;
struct table *tables;
+ if (!was_section_parsed(module, section_table))
+ return 0;
+
tables = module->table_section.tables;
num_tables = module->table_section.num_tables;
size = num_tables * sizeof(struct table_inst);
@@ -4758,6 +4877,9 @@ static int alloc_tables(struct wasm_interp *interp)
struct table_inst *inst;
int i;
+ if (!was_section_parsed(interp->module, section_table))
+ return 1;
+
interp->module_inst.num_tables =
interp->module->table_section.num_tables;
@@ -4964,6 +5086,14 @@ static int init_memories(struct wasm_interp *interp)
struct wdata *data;
int i;
+ debug("init memories\n");
+
+ if (!was_section_parsed(interp->module, section_data))
+ return 1;
+
+ if (!was_section_parsed(interp->module, section_memory))
+ return 1;
+
for (i = 0; i < interp->module->data_section.num_datas; i++) {
data = &interp->module->data_section.datas[i];
@@ -4983,6 +5113,9 @@ static int init_tables(struct wasm_interp *interp)
struct elem *elem;
int i;
+ if (!was_section_parsed(interp->module, section_table))
+ return 1;
+
for (i = 0; i < interp->module->element_section.num_elements; i++) {
elem = &interp->module->element_section.elements[i];
@@ -5005,8 +5138,10 @@ static int init_elements(struct wasm_interp *interp)
int count = 0;
int i, j;
+ debug("init elements\n");
+
if (!was_section_parsed(interp->module, section_element))
- return 0;
+ return 1;
elems = interp->module->element_section.elements;
@@ -5089,6 +5224,28 @@ static int instantiate_module(struct wasm_interp *interp)
return 1;
}
+static int reset_memory(struct wasm_interp *interp)
+{
+ int pages, num_mems;
+
+ num_mems = was_section_parsed(interp->module, section_memory)?
+ interp->module->memory_section.num_mems : 0;
+
+ reset_cursor(&interp->memory);
+
+ if (num_mems == 1) {
+ pages = interp->module->memory_section.mems[0].min;
+ if (!cursor_malloc(&interp->memory, pages * WASM_PAGE_SIZE)) {
+ return interp_error(interp,
+ "could not alloc %d memory pages",
+ pages);
+ }
+ assert(interp->memory.p > interp->memory.start);
+ }
+
+ return 1;
+}
+
int wasm_interp_init(struct wasm_interp *interp, struct module *module)
{
unsigned char *mem, *heap, *start;
@@ -5225,6 +5382,12 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module)
return interp_error(interp, "not enough memory");
}
+ if (!reset_memory(interp))
+ return interp_error(interp, "reset memory");
+
+ if (!instantiate_module(interp))
+ return interp_error(interp, "instantiate module");
+
return 1;
}
@@ -5239,28 +5402,6 @@ void wasm_interp_free(struct wasm_interp *interp)
free(interp->memory.start);
}
-static int reset_memory(struct wasm_interp *interp)
-{
- int pages, num_mems;
-
- num_mems = was_section_parsed(interp->module, section_memory)?
- interp->module->memory_section.num_mems : 0;
-
- reset_cursor(&interp->memory);
-
- if (num_mems == 1) {
- pages = interp->module->memory_section.mems[0].min;
- if (!cursor_malloc(&interp->memory, pages * WASM_PAGE_SIZE)) {
- return interp_error(interp,
- "could not alloc %d memory pages",
- pages);
- }
- assert(interp->memory.p > interp->memory.start);
- }
-
- return 1;
-}
-
int interp_wasm_module(struct wasm_interp *interp)
{
interp->ops = 0;
@@ -5277,21 +5418,11 @@ int interp_wasm_module(struct wasm_interp *interp)
reset_cursor(&interp->errors.cur);
reset_cursor(&interp->callframes);
- if (!reset_memory(interp))
- return interp_error(interp, "reset memory");
-
- if (!instantiate_module(interp))
- return interp_error(interp, "instantiate module");
-
// don't reset labels for perf!
//interp->mem.p = interp->mem.start;
- if (!prepare_call(interp, interp->module_inst.start_fn)) {
- return interp_error(interp, "preparing start function");
- }
-
- if (interp_code(interp)) {
+ if (call_function(interp, interp->module_inst.start_fn)) {
debug("interp success!!\n");
} else if (interp->quitting) {
debug("finished running via process exit\n");
diff --git a/src/wasm.h b/src/wasm.h
@@ -291,6 +291,7 @@ enum instr_tag {
/* parametric instructions */
i_drop = 0x1A,
i_select = 0x1B,
+ i_selects = 0x1C,
/* variable instructions */
i_local_get = 0x20,
@@ -522,6 +523,11 @@ struct table_init {
int elemidx;
};
+struct select_instr {
+ u8 *valtypes;
+ int num_valtypes;
+};
+
struct instr {
enum instr_tag tag;
int pos;
@@ -530,6 +536,7 @@ struct instr {
struct table_init table_init;
struct call_indirect call_indirect;
struct memarg memarg;
+ struct select_instr select;
struct block block;
double fp_double;
float fp_single;
@@ -633,7 +640,6 @@ struct wasm_interp {
struct cursor callframes; /* struct callframe */
struct cursor stack; /* struct val */
struct cursor mem; /* u8/mixed */
- struct cursor resolver_offsets; /* int */
struct cursor memory; /* memory pages (65536 blocks) */
@@ -644,6 +650,7 @@ struct wasm_interp {
// instruction is encountered, the label index is pushed. When an
// instruction is popped, we can resolve the label
struct cursor resolver_stack; /* struct resolver */
+ struct cursor resolver_offsets; /* int */
};
struct builtin {