commit da8b674172616421722052dbaef75054bf063303
parent 4b5d61d3d8685edd135c268bb7d85972cbe48a50
Author: William Casarin <jb55@jb55.com>
Date: Sat, 17 Jul 2021 07:01:27 -0700
memory stuff
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
M | src/wasm.c | | | 165 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
M | src/wasm.h | | | 2 | +- |
2 files changed, 97 insertions(+), 70 deletions(-)
diff --git a/src/wasm.c b/src/wasm.c
@@ -22,6 +22,7 @@
#define ERR_STACK_SIZE 16
#define NUM_LOCALS 0xFFFF
+#define WASM_PAGE_SIZE 65536
static const int MAX_LABELS = 128;
@@ -395,11 +396,6 @@ static void print_stack(struct cursor *stack)
stack->p = p;
}
-static INLINE int cursor_push_cursor(struct cursor *cur, struct cursor *push)
-{
- return cursor_push(cur, (u8*)push, sizeof(*push));
-}
-
static INLINE int cursor_push_callframe(struct cursor *cur, struct callframe *frame)
{
return cursor_push(cur, (u8*)frame, sizeof(*frame));
@@ -2164,22 +2160,22 @@ fail:
return 0;
}
-static int interp_prep_binop(struct wasm_interp *interp, struct val *a,
- struct val *b, struct val *c, enum valtype typ)
+static int interp_prep_binop(struct wasm_interp *interp, struct val *lhs,
+ struct val *rhs, struct val *c, enum valtype typ)
{
c->type = typ;
- if (!cursor_popval(&interp->stack, a)) {
+ if (!cursor_popval(&interp->stack, rhs)) {
return interp_error(interp, "couldn't pop first val");
}
- if (!cursor_popval(&interp->stack, b)) {
+ if (!cursor_popval(&interp->stack, lhs)) {
return interp_error(interp, "couldn't pop second val");
}
- if (a->type != typ || b->type != typ) {
+ if (lhs->type != typ || rhs->type != typ) {
return interp_error(interp, "type mismatch, %s != %s",
- valtype_name(a->type), valtype_name(b->type));
+ valtype_name(lhs->type), valtype_name(rhs->type));
}
return 1;
@@ -2299,7 +2295,7 @@ static int interp_local_get(struct wasm_interp *interp)
return 0;
}
- return cursor_pushval(&interp->stack, val);
+ return stack_pushval(interp, val);
}
static INLINE void make_i32_val(struct val *val, int v)
@@ -2310,15 +2306,28 @@ static INLINE void make_i32_val(struct val *val, int v)
static INLINE int interp_i32_gt_u(struct wasm_interp *interp)
{
- struct val a, b, c;
+ struct val lhs, rhs, c;
+
+ if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) {
+ return interp_error(interp, "gt_u prep");
+ }
- if (unlikely(!interp_prep_binop(interp, &a, &b, &c, val_i32))) {
+ c.i32 = (unsigned int)lhs.i32 > (unsigned int)rhs.i32;
+
+ return stack_pushval(interp, &c);
+}
+
+static INLINE int interp_i32_lt_s(struct wasm_interp *interp)
+{
+ struct val lhs, rhs, c;
+
+ if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) {
return interp_error(interp, "gt_u prep");
}
- c.i32 = (unsigned int)b.i32 > (unsigned int)a.i32;
+ c.i32 = (signed int)lhs.i32 < (signed int)rhs.i32;
- return cursor_pushval(&interp->stack, &c);
+ return stack_pushval(interp, &c);
}
static INLINE int interp_i32_const(struct wasm_interp *interp)
@@ -3184,31 +3193,75 @@ static int interp_global_get(struct wasm_interp *interp)
return 1;
}
-static int interp_memory_size(struct wasm_interp *interp)
+static INLINE int active_pages(struct wasm_interp *interp)
+{
+ return cursor_count(&interp->memory, WASM_PAGE_SIZE);
+}
+
+static INLINE int has_memory_section(struct module *module)
+{
+ return was_section_parsed(module, section_memory) &&
+ module->memory_section.num_mems > 0;
+}
+
+
+static int interp_memory_grow(struct wasm_interp *interp)
{
- struct limits *mem;
struct cursor *code;
+ int pages, prev_size;
+ unsigned int grow;
u8 memidx;
if (unlikely(!(code = interp_codeptr(interp)))) {
return interp_error(interp, "codeptr");
}
- if (unlikely(!was_section_parsed(interp->module, section_memory) ||
- interp->module->memory_section.num_mems == 0)) {
- return interp_error(interp, "no memory sections");
+ if (!pull_byte(code, &memidx)) {
+ return interp_error(interp, "memidx");
}
- mem = &interp->module->memory_section.mems[0];
+ if (unlikely(!has_memory_section(interp->module))) {
+ return interp_error(interp, "no memory section");
+ }
- if (!stack_push_i32(interp, mem->max / 65536)) {
- return interp_error(interp, "push memory size");
+ if (!stack_pop_i32(interp, &pages)) {
+ return interp_error(interp, "pop pages");
+ }
+
+ grow = pages * WASM_PAGE_SIZE;
+ prev_size = active_pages(interp);
+
+ if (interp->memory.p + grow <= interp->memory.end) {
+ interp->memory.p += grow;
+ pages = prev_size;
+ } else {
+ pages = -1;
+ }
+
+ return stack_push_i32(interp, pages);
+}
+
+static int interp_memory_size(struct wasm_interp *interp)
+{
+ struct cursor *code;
+ u8 memidx;
+
+ if (unlikely(!(code = interp_codeptr(interp)))) {
+ return interp_error(interp, "codeptr");
}
if (!pull_byte(code, &memidx)) {
return interp_error(interp, "memidx");
}
+ if (unlikely(!has_memory_section(interp->module))) {
+ return interp_error(interp, "no memory section");
+ }
+
+ if (!stack_push_i32(interp, active_pages(interp))) {
+ return interp_error(interp, "push memory size");
+ }
+
return 1;
}
@@ -3232,12 +3285,14 @@ static int interp_instr(struct wasm_interp *interp, u8 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_i32_lt_s: return interp_i32_lt_s(interp);
case i_if: return interp_if(interp);
case i_end: return pop_label_checkpoint(interp);
case i_call: return interp_call(interp);
case i_block: return interp_block(interp);
case i_br_if: return interp_br_if(interp);
case i_memory_size: return interp_memory_size(interp);
+ case i_memory_grow: return interp_memory_grow(interp);
default:
interp_error(interp, "unhandled instruction %s 0x%x",
instr_name(tag), tag);
@@ -3341,13 +3396,12 @@ void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t a
int wasm_interp_init(struct wasm_interp *interp, struct module *module)
{
- unsigned char *mem;
- struct limits *mem_limits;
- struct cursor mem_inst;
- int i, ok, fns, errors_size, stack_size, locals_size, offsets_size,
+ unsigned char *mem, *heap;
+
+ unsigned int ok, fns, errors_size, stack_size, locals_size, offsets_size,
callframes_size, resolver_size, labels_size, num_labels_size,
- labels_capacity, num_labels_elemsize, memsize, num_mem_sizes,
- resolver_offsets_size, num_mems, mems_cursor_sizes;
+ labels_capacity, num_labels_elemsize, memsize, memory_pages_size,
+ resolver_offsets_size, num_mems;
memset(interp, 0, sizeof(*interp));
interp->module = module;
@@ -3369,27 +3423,19 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module)
resolver_offsets_size = offsets_size;
callframes_size = sizeof(struct callframe) * 0xFF;
resolver_size = sizeof(struct resolver) * MAX_LABELS;
- mems_cursor_sizes = 0;
num_mems = was_section_parsed(interp->module, section_memory)?
interp->module->memory_section.num_mems : 0;
+ if (num_mems > 1) {
+ printf("more than one memory instance is not supported\n");
+ return 0;
+ }
+
interp->labels.elem_size = sizeof(struct label);
interp->num_labels.elem_size = num_labels_elemsize;
- /* memory sizes */
- num_mem_sizes = 0;
- for (i = 0; i < num_mems; i++) {
- mem_limits = &interp->module->memory_section.mems[i];
- if (mem_limits->type == limit_min) {
- debug("min mems push %d\n", mem_limits->min);
- num_mem_sizes += mem_limits->min;
- } else {
- debug("max mems push %d\n", mem_limits->max);
- num_mem_sizes += mem_limits->max;
- }
- mems_cursor_sizes += sizeof(struct cursor);
- }
+ memory_pages_size = 0x8000UL * WASM_PAGE_SIZE;
memsize =
errors_size +
@@ -3400,12 +3446,13 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module)
offsets_size +
resolver_offsets_size +
callframes_size +
- num_mem_sizes +
- mems_cursor_sizes +
resolver_size;
mem = calloc(1, memsize);
+ heap = malloc(memory_pages_size);
+
make_cursor(mem, mem + memsize, &interp->mem);
+ make_cursor(heap, heap + memory_pages_size, &interp->memory);
// enable error reporting by default
interp->errors.enabled = 1;
@@ -3417,7 +3464,6 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module)
cursor_slice(&interp->mem, &interp->callframes, callframes_size) &&
cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size) &&
cursor_slice(&interp->mem, &interp->resolver_stack, resolver_size) &&
- cursor_slice(&interp->mem, &interp->mems, mems_cursor_sizes) &&
array_alloc(&interp->mem, &interp->labels, labels_capacity) &&
array_alloc(&interp->mem, &interp->num_labels, fns);
@@ -3425,20 +3471,6 @@ int wasm_interp_init(struct wasm_interp *interp, struct module *module)
return interp_error(interp, "not enough memory 1");
}
- /* memory instances */
- num_mem_sizes = 0;
- for (i = 0; i < num_mems; i++) {
- mem_limits = &interp->module->memory_section.mems[i];
- ok = ok && cursor_slice(&interp->mem, &mem_inst, mem_limits->max);
- if (!ok || !cursor_push_cursor(&interp->mems, &mem_inst)) {
- return interp_error(interp, "push mems cursor");
- }
- }
-
- if (!ok) {
- return interp_error(interp, "not enough memory");
- }
-
return 1;
}
@@ -3450,12 +3482,12 @@ void wasm_parser_free(struct wasm_parser *parser)
void wasm_interp_free(struct wasm_interp *interp)
{
free(interp->mem.start);
+ free(interp->memory.start);
}
int interp_wasm_module(struct wasm_interp *interp)
{
- int func, mems, i;
- struct cursor *cursor;
+ int func;
interp->ops = 0;
@@ -3470,12 +3502,7 @@ int interp_wasm_module(struct wasm_interp *interp)
reset_cursor(&interp->resolver_offsets);
reset_cursor(&interp->errors.cur);
reset_cursor(&interp->callframes);
-
- mems = cursor_count(&interp->mems, sizeof(struct cursor));
- for (i = 0; i < mems; i++) {
- cursor = &((struct cursor*)&interp->mems.p)[i];
- reset_cursor(cursor);
- }
+ reset_cursor(&interp->memory);
// don't reset labels for perf!
diff --git a/src/wasm.h b/src/wasm.h
@@ -501,7 +501,7 @@ struct wasm_interp {
struct cursor stack; /* struct val */
struct cursor mem; /* u8/mixed */
struct cursor resolver_offsets; /* int */
- struct cursor mems; /* struct cursor, memory instance blocks */
+ struct cursor memory; /* memory pages (65536 blocks) */
struct array labels; /* struct labels */
struct array num_labels;