commit 63382c476a5eec3ab2e00d7be713d0ad509bc53e
parent e805f76c30a9bd7eaeb9547e3324386dc53de2e7
Author: William Casarin <jb55@jb55.com>
Date: Wed, 21 Jul 2021 12:36:00 -0700
getting there...
Diffstat:
M | src/wasm.c | | | 307 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
M | src/wasm.h | | | 6 | +++--- |
2 files changed, 200 insertions(+), 113 deletions(-)
diff --git a/src/wasm.c b/src/wasm.c
@@ -230,8 +230,10 @@ static void print_val(struct val *val)
case val_f64: printf("%f", val->num.f64); break;
case val_ref_null:
+ break;
case val_ref_func:
case val_ref_extern:
+ printf("%d", val->ref.addr);
break;
}
printf("%s", valtype_literal(val->type));
@@ -265,23 +267,6 @@ static void print_stack(struct cursor *stack)
stack->p = p;
}
-static int builtin_get_args(struct wasm_interp *interp)
-{
- struct val *argv, *argv_buf;
-
- if (!(argv = get_local(interp, 0)))
- return interp_error(interp, "argv");
-
- if (!(argv_buf = get_local(interp, 1)))
- return interp_error(interp, "argv_buf");
-
- print_stack(&interp->stack);
-
- debug("get args %d %d\n", argv->num.i32, argv_buf->num.i32);
-
- return 1;
-}
-
static INLINE int cursor_pushval(struct cursor *cur, struct val *val)
{
return cursor_push(cur, (u8*)val, sizeof(*val));
@@ -332,6 +317,7 @@ 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 struct builtin BUILTINS[] = {
{ .name = "args_get", .fn = builtin_get_args },
@@ -948,14 +934,53 @@ 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 int leb128_read(struct cursor *read, unsigned int *val)
+static INLINE int leb128_read(struct cursor *read, unsigned int *val_)
{
- unsigned char p[5];
- unsigned char *start;
+ int *val = (signed int*)val_;
+ int shift;
+ u8 byte;
- start = read->p;
*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 < (signed int)sizeof(*val)) && (byte & 0x40))
+ *val |= (~0 << shift);
+ return 1;
+}
+
+static INLINE int uleb128_read(struct cursor *read, unsigned int *val)
+{
+ //unsigned char *start;
+ int shift;
+ u8 byte;
+
+ //start = read->p;
+ *val = 0;
+ shift = 0;
+
+ for (;;) {
+ if (!pull_byte(read, &byte)) {
+ return 0;
+ }
+ *val |= (byte & 0x7F) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+
+ return 1;
+}
+
+/*
if (pull_byte(read, &p[0]) && (p[0] & 0x80) == 0) {
*val = LEB128_1(unsigned int);
return 1;
@@ -973,12 +998,12 @@ static int leb128_read(struct cursor *read, unsigned int *val)
*val = LEB128_5(unsigned int);
return 5;
}
+ //printf("%02X & 0xF0\n", p[4] & 0xF0);
}
+ */
/* reset if we're missing */
- read->p = start;
- return 0;
-}
+ //read->p = start;
static INLINE int read_int(struct cursor *read, int *val)
{
@@ -1687,7 +1712,7 @@ static const char *show_instr(struct instr *instr)
static int eval_const_instr(struct instr *instr, struct errors *errs,
struct cursor *stack)
{
- debug("eval_const_instr %s\n", show_instr(instr));
+ //debug("eval_const_instr %s\n", show_instr(instr));
switch ((enum const_instr)instr->tag) {
case ci_global_get:
@@ -1886,7 +1911,7 @@ static int parse_instrs_until(struct expr_parser *p, u8 stop_instr,
if (!pull_byte(p->code, &tag))
return note_error(p->errs, p->code, "oob");
- if (tag == stop_instr ||
+ if ((tag != i_if && tag == stop_instr) ||
(stop_instr == i_if && (tag == i_else || tag == i_end))) {
//debug("parse_instrs_until ending\n");
*instr_len = p->code->p - *parsed_instrs;
@@ -2605,7 +2630,7 @@ fail:
return 0;
}
-static int interp_prep_binop(struct wasm_interp *interp, struct val *lhs,
+static INLINE int interp_prep_binop(struct wasm_interp *interp, struct val *lhs,
struct val *rhs, struct val *c, enum valtype typ)
{
c->type = typ;
@@ -2816,17 +2841,6 @@ static INLINE int interp_i32_const(struct wasm_interp *interp, int c)
return cursor_pushval(&interp->stack, &val);
}
-static struct functype *get_function_type(struct wasm_interp *interp, int ind)
-{
- if (unlikely(!is_valid_fn_index(interp->module, ind))) {
- interp_error(interp, "ind %d >= num_indices %d",
- ind,interp->module->func_section.num_indices);
- return NULL;
- }
-
- return interp->module->funcs[ind].functype;
-}
-
static INLINE int count_local_resolvers(struct wasm_interp *interp, int *count)
{
int offset;
@@ -2927,14 +2941,83 @@ static INLINE int count_resolvers(struct wasm_interp *interp)
return cursor_count(&interp->resolver_stack, sizeof(struct resolver));
}
-static int call_function(struct wasm_interp *interp, int func_index)
+static void make_default_val(struct val *val)
+{
+ switch (val->type) {
+ case val_i32:
+ val->num.i32 = 0;
+ break;
+ case val_i64:
+ val->num.i64 = 0;
+ break;
+ case val_f32:
+ val->num.f32 = 0.0;
+ break;
+ case val_f64:
+ val->num.f64 = 0.0;
+ break;
+ case val_ref_null:
+ case val_ref_func:
+ case val_ref_extern:
+ val->ref.addr = 0;
+ break;
+ }
+}
+
+static int prepare_function_args(struct wasm_interp *interp, struct func *func,
+ int func_index)
{
static char buf[128];
- int i;
- struct functype *functype;
- struct func *func;
- struct val val;
+ struct local *local;
enum valtype paramtype;
+ struct val val;
+ int 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;
+ local = &func->locals[ind];
+
+ if (unlikely(!cursor_popval(&interp->stack, &val))) {
+ return interp_error(interp,
+ "not enough arguments for call to %s: [%s], needed %d args, got %d",
+ get_function_name(interp->module, func_index),
+ functype_str(func->functype, buf, sizeof(buf)),
+ func->functype->params.num_valtypes,
+ ind);
+ }
+
+ if (unlikely(val.type != paramtype)) {
+ return interp_error(interp,
+ "call parameter %d type mismatch. got %s, expected %s",
+ ind+1,
+ valtype_name(val.type),
+ valtype_name(paramtype));
+ }
+
+ debug("setting param %d (%s) to ",
+ ind, valtype_name(local->val.type));
+#ifdef DEBUG
+ print_val(&val); printf("\n");
+#endif
+ memcpy(&func->locals[ind], &val, sizeof(struct val));
+ }
+
+
+ for (; i < func->num_locals - func->functype->params.num_valtypes; i++) {
+ local = &func->locals[i];
+ make_default_val(&local->val);
+ debug("setting local %d (%s) to default\n",
+ i, valtype_name(local->val.type));
+ }
+
+ return 1;
+}
+
+static int call_function(struct wasm_interp *interp, int func_index)
+{
+ struct func *func;
unsigned int offset;
debug("calling %s:%d\n", get_function_name(interp->module, func_index), func_index);
@@ -2953,45 +3036,8 @@ static int call_function(struct wasm_interp *interp, int func_index)
if (unlikely(!cursor_push_int(&interp->resolver_offsets, offset)))
return interp_error(interp, "push resolver offset");
- /* get type signature to know how many locals to push as params */
- if (unlikely(!(functype = get_function_type(interp, func_index)))) {
- return interp_error(interp,
- "couldn't get function type for function '%s' (%d)",
- get_function_name(interp->module, func_index),
- func_index);
- }
-
- /*
- if (func.type == func_type_builtin && !func.builtin->prepare_args(interp)) {
- return interp_error(interp, "prepare '%s' builtin",
- func.builtin->name);
- }
- */
-
- /* push params as locals */
- for (i = 0; i < functype->params.num_valtypes; i++) {
- paramtype = (enum valtype)functype->params.valtypes[i];
-
- if (unlikely(!cursor_popval(&interp->stack, &val))) {
- return interp_error(interp,
- "not enough arguments for call to %s: [%s], needed %d args, got %d",
- get_function_name(interp->module, func_index),
- functype_str(functype, buf, sizeof(buf)),
- functype->params.num_valtypes,
- i);
- }
-
- if (unlikely(val.type != paramtype)) {
- return interp_error(interp,
- "call parameter %d type mismatch. got %s, expected %s",
- i+1,
- valtype_name(val.type),
- valtype_name(paramtype));
- }
-
- if (unlikely(!set_fn_local(interp, func_index, i, &val))) {
- return interp_error(interp, "set param local %d", i);
- }
+ if (!prepare_function_args(interp, func, func_index)) {
+ return interp_error(interp, "prepare args");
}
if (unlikely(!call_func(interp, func, func_index))) {
@@ -3121,7 +3167,7 @@ static int parse_blocktype(struct cursor *cur, struct errors *errs, struct block
blocktype->tag = blocktype_index;
cur->p--;
- if (!leb128_read(cur, &blocktype->type_index)) {
+ if (!read_int(cur, &blocktype->type_index)) {
note_error(errs, cur, "parse_blocktype: read type_index\n");
return 0;
}
@@ -3442,8 +3488,8 @@ 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 leb128_read(code, &memarg->offset) &&
- leb128_read(code, &memarg->align);
+ return read_int(code, &memarg->align) &&
+ read_int(code, &memarg->offset);
}
static int parse_call_indirect(struct cursor *code,
@@ -3510,7 +3556,7 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op)
case i_memory_size:
case i_memory_grow:
- return pull_byte(p->code, &op->memidx);
+ return consume_byte(p->code, 0);
case i_block:
return parse_block(p, &op->block, i_block, i_end);
@@ -3577,6 +3623,7 @@ static int parse_instr(struct expr_parser *p, u8 tag, struct instr *op)
case i_f64_const:
return note_error(p->errs, p->code, "parse float const");
+
// single-tag ops
case i_unreachable:
case i_nop:
@@ -3920,10 +3967,8 @@ static INLINE int interp_br_if(struct wasm_interp *interp, int ind)
return 1;
}
-static struct val *get_global(struct wasm_interp *interp, int ind)
+static struct val *get_global_inst(struct wasm_interp *interp, int ind)
{
- struct globalsec *globsec;
- struct global *global;
struct global_inst *global_inst;
if (unlikely(!was_section_parsed(interp->module, section_global))) {
@@ -3932,19 +3977,16 @@ static struct val *get_global(struct wasm_interp *interp, int ind)
return NULL;
}
- globsec = &interp->module->global_section;
-
if (unlikely(ind >= interp->module_inst.num_globals)) {
interp_error(interp, "invalid global index %d (max %d)", ind,
- globsec->num_globals-1);
+ interp->module_inst.num_globals);
return NULL;
}
- global = &interp->module->global_section.globals[ind];
global_inst = &interp->module_inst.globals[ind];
/* copy initialized global from module to global instance */
- memcpy(&global_inst->val, &global->val, sizeof(global_inst->val));
+ //memcpy(&global_inst->val, &global->val, sizeof(global_inst->val));
return &global_inst->val;
}
@@ -3960,7 +4002,7 @@ static int interp_global_get(struct wasm_interp *interp, int ind)
ind, section->num_globals-1);
}
- if (!(global = get_global(interp, ind))) {
+ if (!(global = get_global_inst(interp, ind))) {
return interp_error(interp, "get global");
}
@@ -4069,30 +4111,55 @@ static int store_val(struct wasm_interp *interp, int i,
return 1;
}
-static int store_simple(struct wasm_interp *interp, int offset, struct val *val)
+static INLINE int store_simple(struct wasm_interp *interp, int offset, struct val *val)
{
struct memarg memarg = {};
return store_val(interp, offset, &memarg, val->type, val, 0);
}
-static int builtin_get_args_sizes(struct wasm_interp *interp)
+static INLINE int store_i32(struct wasm_interp *interp, int offset, int i)
+{
+ struct val val;
+ make_i32_val(&val, i);
+ return store_simple(interp, offset, &val);
+}
+
+static int builtin_get_args(struct wasm_interp *interp)
{
- struct val *argc_addr, *argv_buf_size;
- struct val argc;
+ struct val *argv, *argv_buf;
+
+ if (!(argv = get_local(interp, 0)))
+ return interp_error(interp, "argv");
+
+ if (!(argv_buf = get_local(interp, 1)))
+ return interp_error(interp, "argv_buf");
+
+ if (!stack_push_i32(interp, 0))
+ return interp_error(interp, "push ret");
+
+ debug("get args %d %d\n", argv->num.i32, argv_buf->num.i32);
+
+ return 1;
+}
- make_i32_val(&argc, 1);
+static int builtin_get_args_sizes(struct wasm_interp *interp)
+{
+ struct val *argc_addr, *argv_buf_size_addr;
if (!(argc_addr = get_local(interp, 0)))
return interp_error(interp, "argc");
- if (!(argv_buf_size = get_local(interp, 1)))
+ if (!(argv_buf_size_addr = get_local(interp, 1)))
return interp_error(interp, "argv_buf_size");
- if (!store_simple(interp, argc_addr->num.i32, &argc)) {
+ if (!store_i32(interp, argc_addr->num.i32, 1984))
return interp_error(interp, "store argc");
- }
- debug("get_args_sizes %d %d\n", argc_addr->num.i32, argv_buf_size->num.i32);
+ if (!store_i32(interp, argv_buf_size_addr->num.i32, 1))
+ return interp_error(interp, "store arg buf size");
+
+ debug("get_args_sizes %d %d\n", argc_addr->num.i32,
+ argv_buf_size_addr->num.i32);
return stack_push_i32(interp, 0);
}
@@ -4151,7 +4218,7 @@ static INLINE int interp_global_set(struct wasm_interp *interp, int global_ind)
{
struct val *global, setval;
- if (unlikely(!(global = get_global(interp, global_ind)))) {
+ if (unlikely(!(global = get_global_inst(interp, global_ind)))) {
return interp_error(interp, "couldn't get global %d", global_ind);
}
@@ -4212,6 +4279,17 @@ static INLINE int interp_memory_size(struct wasm_interp *interp, u8 memidx)
return 1;
}
+static INLINE int interp_i32_ne(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_mul(struct wasm_interp *interp)
{
struct val lhs, rhs, c;
@@ -4625,6 +4703,7 @@ 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_ne: return interp_i32_ne(interp);
case i_i64_shl: return interp_i64_shl(interp);
case i_i64_or: return interp_i64_or(interp);
@@ -4706,10 +4785,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)) {
+ if (is_control_instr(tag)) {
+ return 1;
+ }
+
+ if (!parse_instr(parser, instr->tag, instr)) {
return interp_error(interp, "parse instr %s", instr_name(tag));
}
@@ -4740,7 +4821,7 @@ static enum interp_end interp_code_end(struct wasm_interp *interp,
return interp_error(interp, "count local resolvers");
}
- debug("interp_code_end local resolvers: %d\n", num_resolvers);
+ //debug("interp_code_end local resolvers: %d\n", num_resolvers);
if (num_resolvers == 0) {
return interp_end_done;
@@ -4755,6 +4836,7 @@ static enum interp_end interp_code_end(struct wasm_interp *interp,
resolve_label(label, code);
+ debug("loop jumping\n");
if (!interp_jump(interp, label_instr_pos(label))) {
return interp_error(interp, "jump to loop label");
}
@@ -4872,6 +4954,7 @@ static int count_fn_locals(struct func *func)
num_locals += func->functype->params.num_valtypes;
if (func->type == func_type_wasm) {
+ // counts locals of the same type
for (i = 0; i < func->wasm_func->num_locals; i++) {
num_locals += func->wasm_func->locals->val.num.i32;
}
@@ -4954,7 +5037,7 @@ static int calculate_locals_size(struct module *module)
static int alloc_locals(struct module *module, struct cursor *mem,
struct errors *errs)
{
- int i, num_locals, size, sizes = 0;
+ int i, j, num_locals, size, sizes = 0;
struct func *func;
for (i = 0; i < module->num_funcs; i++) {
@@ -4973,6 +5056,10 @@ static int alloc_locals(struct module *module, struct cursor *mem,
"could not alloc locals for %s",
func->name);
}
+
+ for (j = 0; j < func->num_locals; j++) {
+ func->locals[j].val.type = func->functype->params.valtypes[j];
+ }
}
debug("alloc_locals sizes %d\n", sizes);
diff --git a/src/wasm.h b/src/wasm.h
@@ -492,7 +492,7 @@ struct blocktype {
enum blocktype_tag tag;
union {
enum valtype valtype;
- unsigned int type_index;
+ int type_index;
};
};
@@ -503,8 +503,8 @@ struct block {
};
struct memarg {
- unsigned int offset;
- unsigned int align;
+ int offset;
+ int align;
};
struct br_table {