commit 94b5055bb6aa96b3241863171524f6ee0e5b8525
parent c8682805e9cddd0dd893ce24bc751b587770c0a8
Author: William Casarin <jb55@jb55.com>
Date: Sat, 10 Jul 2021 13:40:24 -0700
initial if branching stuff
Diffstat:
8 files changed, 553 insertions(+), 71 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,5 +1,5 @@
-CFLAGS = -Wno-error=unused-function -DDEBUG -O2 -g -std=gnu90 -Wall -Wextra -Werror \
+CFLAGS = -Wno-error=unused-function -O2 -g -std=gnu90 -Wall -Wextra -Werror \
-Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes \
-Wmissing-declarations -Wdeclaration-after-statement
diff --git a/default.nix b/default.nix
@@ -1,4 +1,4 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
- buildInputs = with pkgs; [ gdb wabt emscripten wasmtime ];
+ buildInputs = with pkgs; [ gdb wabt emscripten wasmtime cloc ];
}
diff --git a/src/cursor.h b/src/cursor.h
@@ -16,6 +16,33 @@ struct cursor {
unsigned char *end;
};
+struct array {
+ struct cursor cur;
+ unsigned int elem_size;
+};
+
+static inline void make_cursor(u8 *start, u8 *end, struct cursor *cursor)
+{
+ cursor->start = start;
+ cursor->p = start;
+ cursor->end = end;
+}
+
+static inline void make_array(struct array *a, u8* start, u8 *end, unsigned int elem_size)
+{
+ make_cursor(start, end, &a->cur);
+ a->elem_size = elem_size;
+}
+
+static inline unsigned char *array_index(struct array *a, int ind)
+{
+ u8 *p = a->cur.start + a->elem_size * ind;
+ if (unlikely(p >= a->cur.end)) {
+ return NULL;
+ }
+ return p;
+}
+
static inline int cursor_eof(struct cursor *c)
{
return c->p == c->end;
@@ -43,19 +70,6 @@ static inline void copy_cursor(struct cursor *src, struct cursor *dest)
dest->end = src->end;
}
-static inline void make_cursor(u8 *start, u8 *end, struct cursor *cursor)
-{
- cursor->start = start;
- cursor->p = start;
- cursor->end = end;
-}
-
-static inline int cursor_index(struct cursor *cursor, int elem_size)
-{
- return (cursor->p - cursor->start) / elem_size;
-}
-
-
static inline int pull_byte(struct cursor *cursor, u8 *c)
{
if (unlikely(cursor->p + 1 > cursor->end))
@@ -113,11 +127,23 @@ static inline int pull_data_into_cursor(struct cursor *cursor,
return 1;
}
+static inline int cursor_pop(struct cursor *cur, u8 *data, int len)
+{
+ if (unlikely(cur->p - len < cur->start)) {
+ printf("cursor_pop oob\n");
+ return 0;
+ }
+
+ cur->p -= len;
+ memcpy(cur->p, data, len);
+
+ return 1;
+}
-static inline int push_data(struct cursor *cursor, u8 *data, int len)
+static inline int cursor_push(struct cursor *cursor, u8 *data, int len)
{
if (unlikely(cursor->p + len > cursor->end)) {
- printf("push_data oob\n");
+ printf("cursor_push oob\n");
return 0;
}
@@ -127,9 +153,9 @@ static inline int push_data(struct cursor *cursor, u8 *data, int len)
return 1;
}
-static inline int push_int(struct cursor *cursor, int i)
+static inline int cursor_push_int(struct cursor *cursor, int i)
{
- return push_data(cursor, (u8*)&i, sizeof(i));
+ return cursor_push(cursor, (u8*)&i, sizeof(i));
}
static inline size_t cursor_count(struct cursor *cursor, size_t elem_size)
@@ -192,9 +218,9 @@ static inline int pull_int(struct cursor *cursor, int *i)
return pull_data(cursor, (u8*)i, sizeof(*i));
}
-static inline int push_u16(struct cursor *cursor, u16 i)
+static inline int cursor_push_u16(struct cursor *cursor, u16 i)
{
- return push_data(cursor, (u8*)&i, sizeof(i));
+ return cursor_push(cursor, (u8*)&i, sizeof(i));
}
static inline void *index_cursor(struct cursor *cursor, unsigned int index, int elem_size)
@@ -211,12 +237,12 @@ static inline void *index_cursor(struct cursor *cursor, unsigned int index, int
static inline int push_sized_str(struct cursor *cursor, const char *str, int len)
{
- return push_data(cursor, (u8*)str, len);
+ return cursor_push(cursor, (u8*)str, len);
}
static inline int push_str(struct cursor *cursor, const char *str)
{
- return push_data(cursor, (u8*)str, strlen(str));
+ return cursor_push(cursor, (u8*)str, strlen(str));
}
static inline int push_c_str(struct cursor *cursor, const char *str)
diff --git a/src/net.c b/src/net.c
@@ -22,7 +22,7 @@ static int push_fetch_response_packet(struct cursor *c,
if (!ok) return 0;
ok = push_varint(c, resp->data_len);
if (!ok) return 0;
- return push_data(c, resp->data, resp->data_len);
+ return cursor_push(c, resp->data, resp->data_len);
}
static int pull_fetch_response_packet(struct cursor *c, struct cursor *buf,
diff --git a/src/parse.c b/src/parse.c
@@ -259,7 +259,7 @@ static int push_token_data(struct token_cursor *tokens,
tokdebug("sym %.*s", str->len, str->data);
}
#endif
- ok = push_data(&tokens->c, token_data, token_data_size);
+ ok = cursor_push(&tokens->c, token_data, token_data_size);
if (!ok) return 0;
#ifdef DEBUG
printf("\n");
@@ -641,7 +641,7 @@ static int pull_token(struct token_cursor *tokens,
tokens->err = TE_UNEXPECTED_TOKEN;
tokens->err_data.lex.expected = expected_type;
tokens->err_data.lex.got = type;
- tokens->err_data.pos = cursor_index(&temp.c, 1);
+ tokens->err_data.pos = cursor_count(&temp.c, 1);
return 0;
}
@@ -973,8 +973,8 @@ static int parse_attributes(struct token_cursor *tokens,
ok = parse_attribute(tokens, &attr);
if (!ok) break;
- index = cursor_index(attributes, sizeof(attr));
- ok = push_data(attributes, (u8*)&attr, sizeof(attr));
+ index = cursor_count(attributes, sizeof(attr));
+ ok = cursor_push(attributes, (u8*)&attr, sizeof(attr));
if (!ok) {
printf("attribute data overflow\n");
@@ -1016,7 +1016,7 @@ static int push_cell(struct cursor *cells, struct cell *cell, u16 *cell_index)
int index;
int ok;
- index = cursor_index(cells, sizeof(*cell));
+ index = cursor_count(cells, sizeof(*cell));
tokdebug("push_cell %d (%zu) %s\n", index, cells->p - cells->start, cell_type_str(cell->type));
@@ -1026,7 +1026,7 @@ static int push_cell(struct cursor *cells, struct cell *cell, u16 *cell_index)
return 0;
}
- ok = push_data(cells, (u8*)cell, sizeof(*cell));
+ ok = cursor_push(cells, (u8*)cell, sizeof(*cell));
if (!ok) return 0;
if (cell_index)
@@ -1053,7 +1053,7 @@ static int push_cell_child(struct cell *parent, u16 child_ind)
child_inds.p += parent->n_children * sizeof(parent->children[0]);
- ok = push_u16(&child_inds, child_ind);
+ ok = cursor_push_u16(&child_inds, child_ind);
if (!ok) return 0;
parent->n_children++;
@@ -1107,7 +1107,7 @@ static int parse_cell_attrs(struct parser *parser, u16 *index, struct cell *cell
tokdebug("parse_attributes %d\n", ok);
for (i = attr_inds[0]; i <= attr_inds[1]; i++) {
- ok = push_u16(&cell_attr_inds, i);
+ ok = cursor_push_u16(&cell_attr_inds, i);
if (!ok) return 0;
cell->n_attributes++;
}
diff --git a/src/protoverse.c b/src/protoverse.c
@@ -23,7 +23,7 @@ static void print_all_cells(struct parser *parser)
int i, j;
int ncells;
- ncells = cursor_index(parser->cells, sizeof(struct cell));
+ ncells = cursor_count(parser->cells, sizeof(struct cell));
printf("ncells %d\n", ncells);
for (i = 0; i < ncells; i++) {
cell = get_cell(parser->cells, i);
diff --git a/src/wasm.c b/src/wasm.c
@@ -16,6 +16,8 @@
#define ERR_STACK_SIZE 16
#define NUM_LOCALS 0xFFFF
+static const int MAX_LABELS = 128;
+
struct parse_error {
int pos;
char *msg;
@@ -122,30 +124,43 @@ static void print_stack(struct cursor *stack)
stack->p = p;
}
+static inline int array_push(struct array *a, void *data)
+{
+ return cursor_push(&a->cur, (u8*)data, a->elem_size);
+}
+
+static inline int array_pop_u32(struct array *a, u32 *out)
+{
+ return cursor_pop(&a->cur, (u8*)out, a->elem_size);
+}
+
static inline int cursor_pushval(struct cursor *cur, struct val *val)
{
- return push_data(cur, (unsigned char*)val, sizeof(*val));
+ return cursor_push(cur, (u8*)val, sizeof(*val));
}
-static inline int cursor_pushcode(struct cursor *cur, struct cursor *code)
+static inline int cursor_push_callframe(struct cursor *cur, struct callframe *frame)
{
- return push_data(cur, (unsigned char*)code, sizeof(*code));
+ return cursor_push(cur, (u8*)frame, sizeof(*frame));
}
-static inline struct cursor *cursor_topcode(struct cursor *cur)
+static inline struct callframe *top_callframe(struct cursor *cur)
{
assert(cur->p > cur->start);
- return ((struct cursor*)cur->p) - 1;
+ return ((struct callframe*)cur->p) - 1;
}
static inline struct cursor *interp_codeptr(struct wasm_interp *interp)
{
- return cursor_topcode(&interp->code_stack);
+ struct callframe *frame;
+ frame = top_callframe(&interp->callframes);
+ if (!frame) return 0;
+ return &frame->code;
}
-static inline int cursor_popcode(struct cursor *cur, struct cursor *code)
+static inline int cursor_pop_callframe(struct cursor *cur, struct callframe *frame)
{
- return cursor_popdata(cur, (unsigned char*)code, sizeof(*code));
+ return cursor_popdata(cur, (unsigned char*)frame, sizeof(*frame));
}
static inline int cursor_popint(struct cursor *cur, int *i)
@@ -202,7 +217,7 @@ static void note_error_(struct wasm_parser *p, const char *fmt, ...)
new_err = (struct parse_error *)p->mem.p;
- if (!push_data(&p->mem, (unsigned char*)&err, sizeof(err))) {
+ if (!cursor_push(&p->mem, (unsigned char*)&err, sizeof(err))) {
fprintf(stderr, "arena OOM when pushing data, ");
fprintf(stderr, "mem->p at %ld, remaining %ld, data size %ld\n",
p->mem.p - p->mem.start,
@@ -1751,12 +1766,24 @@ static inline int interp_i32_const(struct wasm_interp *interp)
return cursor_pushval(&interp->stack, &val);
}
-static inline int get_import_offset(struct module *module)
+static inline int imports_count(struct module *module)
{
return !was_section_parsed(module, section_import) ? 0 :
module->import_section.num_imports;
}
+static inline int code_count(struct module *module)
+{
+ // I guess not having any code and is technically possible?
+ return !was_section_parsed(module, section_code) ? 0 :
+ module->code_section.num_funcs;
+}
+
+static inline int functions_count(struct module *module)
+{
+ return imports_count(module) + code_count(module);
+}
+
static inline struct func *get_function(struct module *module, int ind)
{
// TODO: imports
@@ -1764,7 +1791,7 @@ static inline struct func *get_function(struct module *module, int ind)
return NULL;
}
- return &module->code_section.funcs[ind - get_import_offset(module)];
+ return &module->code_section.funcs[ind - imports_count(module)];
}
static inline struct functype *get_function_type(struct module *module, int ind)
@@ -1773,7 +1800,7 @@ static inline struct functype *get_function_type(struct module *module, int ind)
return NULL;
}
- ind = module->func_section.type_indices[ind - get_import_offset(module)];
+ ind = module->func_section.type_indices[ind - imports_count(module)];
if (ind >= module->type_section.num_functypes) {
return NULL;
}
@@ -1787,10 +1814,12 @@ static int prepare_call(struct wasm_interp *interp, int func_index)
struct functype *functype;
struct func *func;
struct val val;
- struct cursor code;
+ struct callframe callframe;
enum valtype paramtype;
unsigned int offset;
+ debug("calling %s\n", get_function_name(interp->module, func_index));
+
if (!(func = get_function(interp->module, func_index))) {
interp_error(interp, "function %d oob/not found (%d funcs)",
func_index,
@@ -1800,7 +1829,7 @@ static int prepare_call(struct wasm_interp *interp, int func_index)
/* record locals offset for indexing locals in the next function */
offset = cursor_count(&interp->locals, sizeof(struct val));
- if (!push_int(&interp->locals_offsets, offset)) {
+ if (!cursor_push_int(&interp->locals_offsets, offset)) {
interp_error(interp, "push locals offset");
return 0;
}
@@ -1836,9 +1865,11 @@ static int prepare_call(struct wasm_interp *interp, int func_index)
}
}
- /* update current function and push it to the codestack as well */
- make_cursor(func->code.code, func->code.code + func->code.code_len, &code);
- if (!cursor_pushcode(&interp->code_stack, &code)) {
+ /* update current function and push it to the callframe as well */
+ make_cursor(func->code.code, func->code.code + func->code.code_len, &callframe.code);
+ callframe.fn = func_index;
+
+ if (!cursor_push_callframe(&interp->callframes, &callframe)) {
interp_error(interp, "oob cursor_pushcode");
return 0;
}
@@ -1866,9 +1897,372 @@ static int interp_call(struct wasm_interp *interp)
return interp_code(interp);
}
+
+static int parse_blocktype(struct cursor *cur, struct blocktype *blocktype)
+{
+ unsigned char byte;
+
+ if (!pull_byte(cur, &byte)) {
+ cursor_print_around(cur, 10);
+ printf("parse_blocktype: oob\n");
+ return 0;
+ }
+
+ if (byte == 0x40) {
+ blocktype->tag = blocktype_empty;
+ } else if (is_valtype(byte)) {
+ blocktype->tag = blocktype_valtype;
+ blocktype->valtype = (enum valtype)byte;
+ } else {
+ blocktype->tag = blocktype_index;
+ cur->p--;
+
+ if (!leb128_read(cur, &blocktype->type_index)) {
+ printf("parse_blocktype: read type_index\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+// if we don't have a resolved label, we need to recursively consume
+// instructions until we get to the i_end or i_else, etc
+static int consume_instr(struct wasm_interp *interp, u8 *tag)
+{
+ u8 byte;
+
+ if (!pull_byte(&interp->cur, tag)) {
+ interp_error(interp, "oob");
+ return 0;
+ }
+
+ switch ((enum instr_tag)*tag) {
+ // two-byte instrs
+ case i_memory_size:
+ case i_memory_grow:
+ return pull_byte(&interp->cur, &byte);
+
+ case i_block:
+ case i_loop:
+ case i_if:
+ case i_else:
+ case i_end:
+ case i_br:
+ case i_br_if:
+ case i_br_table:
+ case i_call:
+ case i_call_indirect:
+ case i_local_get:
+ case i_local_set:
+ case i_local_tee:
+ case i_global_get:
+ case i_global_set:
+ case i_i32_load:
+ case i_i64_load:
+ case i_f32_load:
+ case i_f64_load:
+ case i_i32_load8_s:
+ case i_i32_load8_u:
+ case i_i32_load16_s:
+ case i_i32_load16_u:
+ case i_i64_load8_s:
+ case i_i64_load8_u:
+ case i_i64_load16_s:
+ case i_i64_load16_u:
+ case i_i64_load32_s:
+ case i_i64_load32_u:
+ case i_i32_store:
+ case i_i64_store:
+ case i_f32_store:
+ case i_f64_store:
+ case i_i32_store8:
+ case i_i32_store16:
+ case i_i64_store8:
+ case i_i64_store16:
+ case i_i64_store32:
+ case i_i32_const:
+ case i_i64_const:
+ case i_f32_const:
+ case i_f64_const:
+ interp_error(interp, "consume dynamic-size op");
+ return 0;
+
+ // single-tag ops
+ case i_unreachable:
+ case i_nop:
+ case i_return:
+ case i_drop:
+ case i_select:
+ case i_i32_eqz:
+ case i_i32_eq:
+ case i_i32_ne:
+ case i_i32_lt_s:
+ case i_i32_lt_u:
+ case i_i32_gt_s:
+ case i_i32_gt_u:
+ case i_i32_le_s:
+ case i_i32_le_u:
+ case i_i32_ge_s:
+ case i_i32_ge_u:
+ case i_i64_eqz:
+ case i_i64_eq:
+ case i_i64_ne:
+ case i_i64_lt_s:
+ case i_i64_lt_u:
+ case i_i64_gt_s:
+ case i_i64_gt_u:
+ case i_i64_le_s:
+ case i_i64_le_u:
+ case i_i64_ge_s:
+ case i_i64_ge_u:
+ case i_f32_eq:
+ case i_f32_ne:
+ case i_f32_lt:
+ case i_f32_gt:
+ case i_f32_le:
+ case i_f32_ge:
+ case i_f64_eq:
+ case i_f64_ne:
+ case i_f64_lt:
+ case i_f64_gt:
+ case i_f64_le:
+ case i_f64_ge:
+ case i_i32_clz:
+ case i_i32_add:
+ case i_i32_sub:
+ case i_i32_mul:
+ case i_i32_div_s:
+ case i_i32_div_u:
+ case i_i32_rem_s:
+ case i_i32_rem_u:
+ case i_i32_and:
+ case i_i32_or:
+ case i_i32_xor:
+ case i_i32_shl:
+ case i_i32_shr_s:
+ case i_i32_shr_u:
+ case i_i32_rotl:
+ case i_i32_rotr:
+ case i_i64_clz:
+ case i_i64_ctz:
+ case i_i64_popcnt:
+ case i_i64_add:
+ case i_i64_sub:
+ case i_i64_mul:
+ case i_i64_div_s:
+ case i_i64_div_u:
+ case i_i64_rem_s:
+ case i_i64_rem_u:
+ case i_i64_and:
+ case i_i64_or:
+ case i_i64_xor:
+ case i_i64_shl:
+ case i_i64_shr_s:
+ case i_i64_shr_u:
+ case i_i64_rotl:
+ case i_i64_rotr:
+ return 1;
+ }
+
+ interp_error(interp, "unhandled tag: 0x%x", *tag);
+ return 0;
+}
+
+static inline struct label *index_label(struct array *a, int fn, int ind)
+{
+ return (struct label*)array_index(a, (MAX_LABELS * fn) + ind);
+}
+
+static inline int label_is_resolved(struct label *label)
+{
+ return label->instr_pos & 0x80000000;
+}
+
+static int resolve_label(struct wasm_interp *interp)
+{
+ struct label *label;
+ struct callframe *frame;
+ u32 label_ind = 0;
+
+ if (!cursor_pop(&interp->resolver_stack, (u8*)&label_ind, sizeof(label_ind))) {
+ interp_error(interp, "couldn't pop jump resolver stack");
+ return 0;
+ }
+
+ frame = top_callframe(&interp->callframes);
+ assert(frame);
+
+ label = index_label(&interp->labels, frame->fn, label_ind);
+ assert(label);
+ assert(!label_is_resolved(label));
+
+ label->jump = interp->cur.p - interp->cur.start;
+ label->instr_pos |= 0x80000000;
+
+ return 1;
+}
+
+// consume instructions to resolve labels
+static int consume_instrs_until(struct wasm_interp *interp, u8 stop_instr)
+{
+ u8 tag = 0;
+
+ for (;;) {
+ if (!consume_instr(interp, &tag)) {
+ interp_error(interp, "consume 0x%x", tag);
+ return 0;
+ }
+
+ if (tag == stop_instr) {
+ resolve_label(interp);
+ return 1;
+ }
+ }
+}
+
+static inline u32 label_instr_pos(struct label *label)
+{
+ return label->instr_pos & 0x7FFFFFFF;
+}
+
+static inline void set_label_pos(struct label *label, u32 pos)
+{
+ assert(!(pos & 0x80000000));
+ label->instr_pos = pos;
+}
+
+static inline u16 *func_num_labels(struct wasm_interp *interp, int fn)
+{
+ u16 *num = (u16*)array_index(&interp->num_labels, fn);
+ assert(num);
+ assert(*num <= MAX_LABELS);
+ return num;
+}
+
+static int find_label(struct wasm_interp *interp, int fn, u32 instr_pos)
+{
+ u16 *num_labels, i;
+ struct label *label;
+
+ num_labels = func_num_labels(interp, fn);
+ label = index_label(&interp->labels, fn, 0);
+ assert(label);
+
+ for (i = 0; i < *num_labels; label++) {
+ assert((u8*)label < interp->labels.cur.end);
+ if (label_instr_pos(label) == instr_pos)
+ return i;
+ i++;
+ }
+
+ return -1;
+}
+
+// upsert an unresolved label
+static int upsert_label(struct wasm_interp *interp, int fn, u32 instr_pos, int *ind)
+{
+ struct label *label;
+ u16 *num_labels;
+
+ num_labels = func_num_labels(interp, fn);
+
+ if (*num_labels > 0 && ((*ind = find_label(interp, fn, instr_pos)) == 0)) {
+ // we already have the label
+ return 1;
+ }
+
+ if (*num_labels + 1 > MAX_LABELS) {
+ interp_error(interp, "too many labels in %s (> %d)",
+ get_function_name(interp->module, fn), MAX_LABELS);
+ return 0;
+ }
+
+ *ind = *num_labels;
+ label = index_label(&interp->labels, fn, *ind);
+ assert(label);
+
+ set_label_pos(label, instr_pos);
+ *num_labels = *num_labels + 1;
+
+ return 2;
+}
+
+static int branch_jump(struct wasm_interp *interp, u8 end_tag)
+{
+ u32 instr_pos;
+ int ind;
+
+ int fns;
+ struct label *label;
+ struct callframe *frame;
+
+ fns = functions_count(interp->module);
+ frame = top_callframe(&interp->callframes);
+
+ assert(frame);
+ assert(frame->fn < fns);
+ assert(interp->cur.start == frame->code.start);
+
+ label = index_label(&interp->labels, frame->fn, 0);
+ assert(label);
+
+ if (label_is_resolved(label)) {
+ interp->cur.p = interp->cur.start + label->jump;
+ assert(interp->cur.p < interp->cur.end);
+ return 1;
+ }
+
+ instr_pos = interp->cur.p - interp->cur.start;
+ if (!upsert_label(interp, frame->fn, instr_pos, &ind)) {
+ interp_error(interp, "upsert label");
+ return 0;
+ }
+
+ if (!cursor_push_u16(&interp->resolver_stack, ind)) {
+ interp_error(interp, "push label index to resolver stack oob");
+ return 0;
+ }
+
+ // consume instructions, use resolver stack to resolve jumps
+ if (!consume_instrs_until(interp, end_tag)) {
+ interp_error(interp, "consume instrs");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int interp_if(struct wasm_interp *interp)
+{
+ struct val cond;
+ struct blocktype blocktype;
+
+ if (!parse_blocktype(&interp->cur, &blocktype)) {
+ interp_error(interp, "couldn't parse blocktype");
+ return 0;
+ }
+
+ if (!cursor_popval(&interp->stack, &cond)) {
+ interp_error(interp, "if pop val");
+ return 0;
+ }
+
+ if (cond.i32 == 1) {
+ return 1;
+ }
+
+ if (!branch_jump(interp, i_end)) {
+ return 0;
+ }
+
+ return 0;
+}
+
static int interp_instr(struct wasm_interp *interp, unsigned char tag)
{
interp->ops++;
+ debug("executing 0x%0x\n", tag);
switch (tag) {
case i_unreachable: return 1;
@@ -1879,6 +2273,7 @@ static int interp_instr(struct wasm_interp *interp, unsigned char tag)
case i_i32_sub: return interp_i32_sub(interp);
case i_i32_const: return interp_i32_const(interp);
case i_i32_gt_u: return interp_i32_gt_u(interp);
+ case i_if: return interp_if(interp);
case i_call: return interp_call(interp);
default:
interp_error(interp, "unhandled instruction 0x%x", tag);
@@ -1890,7 +2285,7 @@ static int interp_instr(struct wasm_interp *interp, unsigned char tag)
int interp_code(struct wasm_interp *interp)
{
- struct cursor code;
+ struct callframe frame;
unsigned char tag;
int offset;
@@ -1902,7 +2297,7 @@ int interp_code(struct wasm_interp *interp)
}
if (tag == i_end) {
- cursor_popcode(&interp->code_stack, &code);
+ cursor_pop_callframe(&interp->callframes, &frame);
cursor_popint(&interp->locals_offsets, &offset);
break;
}
@@ -1954,6 +2349,11 @@ static int cursor_slice(struct cursor *mem, struct cursor *slice, size_t size)
return 1;
}
+static inline int array_alloc(struct cursor *mem, struct array *a, int elems)
+{
+ return cursor_slice(mem, &a->cur, elems * a->elem_size);
+}
+
void wasm_interp_init(struct wasm_interp *interp)
{
static unsigned char *stack, *mem;
@@ -1973,9 +2373,21 @@ void wasm_interp_free(struct wasm_interp *interp)
free(interp->mem.start);
}
+static int alloc_labels(struct wasm_interp *interp, int fns)
+{
+ const int capacity = fns * MAX_LABELS;
+
+ interp->labels.elem_size = sizeof(struct label);
+ interp->num_labels.elem_size = sizeof(u16);
+
+ return array_alloc(&interp->mem, &interp->labels, capacity) &&
+ array_alloc(&interp->mem, &interp->num_labels, fns);
+
+}
+
int interp_wasm_module(struct wasm_interp *interp, struct module *module)
{
- int ok, func;
+ int ok, func, fns;
interp->module = module;
interp->ops = 0;
@@ -1989,10 +2401,15 @@ int interp_wasm_module(struct wasm_interp *interp, struct module *module)
interp->stack.p = interp->stack.start;
interp->mem.p = interp->mem.start;
+ fns = functions_count(module);
+
ok =
- cursor_slice(&interp->mem, &interp->locals, sizeof(struct val) * NUM_LOCALS) &&
- cursor_slice(&interp->mem, &interp->locals_offsets, sizeof(int) * 255) &&
- cursor_slice(&interp->mem, &interp->code_stack, sizeof(struct cursor) * 255);
+ cursor_slice(&interp->mem, &interp->locals,
+ sizeof(struct val) * NUM_LOCALS) &&
+ cursor_slice(&interp->mem, &interp->locals_offsets, sizeof(int) * 255) &&
+ cursor_slice(&interp->mem, &interp->callframes, sizeof(struct callframe) * 255) &&
+ cursor_slice(&interp->mem, &interp->resolver_stack, sizeof(u32) * MAX_LABELS) &&
+ alloc_labels(interp, fns);
assert(ok);
diff --git a/src/wasm.h b/src/wasm.h
@@ -293,6 +293,39 @@ enum instr_tag {
i_i32_add = 0x6A,
i_i32_sub = 0x6B,
+ i_i32_mul = 0x6C,
+ i_i32_div_s = 0x6D,
+ i_i32_div_u = 0x6E,
+ i_i32_rem_s = 0x6F,
+ i_i32_rem_u = 0x70,
+ i_i32_and = 0x71,
+ i_i32_or = 0x72,
+ i_i32_xor = 0x73,
+ i_i32_shl = 0x74,
+ i_i32_shr_s = 0x75,
+ i_i32_shr_u = 0x76,
+ i_i32_rotl = 0x77,
+ i_i32_rotr = 0x78,
+
+ i_i64_clz = 0x79,
+ i_i64_ctz = 0x7A,
+ i_i64_popcnt = 0x7B,
+ i_i64_add = 0x7C,
+ i_i64_sub = 0x7D,
+ i_i64_mul = 0x7E,
+ i_i64_div_s = 0x7F,
+ i_i64_div_u = 0x80,
+ i_i64_rem_s = 0x81,
+ i_i64_rem_u = 0x82,
+ i_i64_and = 0x83,
+ i_i64_or = 0x84,
+ i_i64_xor = 0x85,
+ i_i64_shl = 0x86,
+ i_i64_shr_s = 0x87,
+ i_i64_shr_u = 0x88,
+ i_i64_rotl = 0x89,
+ i_i64_rotr = 0x8A,
+
/* TODO: more instrs */
};
@@ -307,20 +340,7 @@ struct blocktype {
enum blocktype_tag tag;
union {
enum valtype valtype;
- unsigned int index;
- };
-};
-
-struct block_instr {
- struct blocktype blocktype;
- struct instr *instrs;
- int num_instrs;
-};
-
-struct instr {
- enum instr_tag tag;
- union {
- struct block_instr block;
+ unsigned int type_index;
};
};
@@ -364,17 +384,36 @@ struct module {
struct datasec data_section;
};
+// make sure the struct is packed so that
+struct label {
+ u32 instr_pos; // resolved status is stored in HOB of pos
+ u32 jump;
+};
+
+struct callframe {
+ struct cursor code;
+ int fn;
+};
+
struct wasm_interp {
struct module *module;
size_t ops;
struct cursor cur; /* code */
- struct cursor code_stack; /* struct cursor */
+ struct cursor callframes; /* struct cursor */
struct cursor stack; /* struct val */
struct cursor mem; /* u8/mixed */
struct cursor locals; /* struct val */
struct cursor locals_offsets; /* int */
+ struct array labels; /* struct labels */
+ struct array num_labels;
+
+ // resolve stack for the current function. every time a control
+ // instruction is encountered, the label index is pushed. When an
+ // instruction is popped, we can resolve the label
+ struct cursor resolver_stack; /* u32 */
+
struct parser_error *errors;
};