summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm-binary-reader-interpreter.c1428
-rw-r--r--src/wasm-interpreter.c57
-rw-r--r--src/wasm-interpreter.h5
3 files changed, 419 insertions, 1071 deletions
diff --git a/src/wasm-binary-reader-interpreter.c b/src/wasm-binary-reader-interpreter.c
index bcc8193d..661caa58 100644
--- a/src/wasm-binary-reader-interpreter.c
+++ b/src/wasm-binary-reader-interpreter.c
@@ -43,9 +43,9 @@
#define CHECK_DEPTH(ctx, depth) \
do { \
- if ((depth) >= (ctx)->typecheck_label_stack.size) { \
+ if ((depth) >= (ctx)->label_stack.size) { \
print_error((ctx), "invalid depth: %d (max %" PRIzd ")", (depth), \
- ((ctx)->typecheck_label_stack.size)); \
+ ((ctx)->label_stack.size)); \
return WASM_ERROR; \
} \
} while (0)
@@ -99,8 +99,7 @@ static const char* s_opcode_name[] = {
/* clang-format off */
WASM_FOREACH_OPCODE(V)
[WASM_OPCODE_ALLOCA] = "alloca",
- [WASM_OPCODE_DISCARD] = "discard",
- [WASM_OPCODE_DISCARD_KEEP] = "discard_keep",
+ [WASM_OPCODE_DROP_KEEP] = "drop_keep",
/* clang-format on */
};
#undef V
@@ -121,31 +120,14 @@ static const char* s_label_type_name[] = {
"func", "block", "loop", "if", "else",
};
-/* used for the typecheck pass */
-typedef struct TypecheckLabel {
+typedef struct Label {
LabelType label_type;
WasmType type;
uint32_t expr_stack_size;
- uint32_t expr_index; /* the index of the starting op (block/loop/if) */
- uint32_t last_expr_index; /* last index of the true branch in an if */
-} TypecheckLabel;
-WASM_DEFINE_VECTOR(typecheck_label, TypecheckLabel);
-
-/* used for the emit pass */
-typedef struct EmitLabel {
- LabelType label_type;
uint32_t offset; /* branch location in the istream */
uint32_t fixup_offset;
- uint32_t value_stack_size;
- WasmBool has_value;
-} EmitLabel;
-WASM_DEFINE_VECTOR(emit_label, EmitLabel);
-
-typedef struct ExprNode {
- uint32_t index;
- WasmType type;
-} ExprNode;
-WASM_DEFINE_VECTOR(expr_node, ExprNode);
+} Label;
+WASM_DEFINE_VECTOR(label, Label);
typedef struct InterpreterFunc {
uint32_t sig_index;
@@ -164,15 +146,11 @@ typedef struct Context {
WasmInterpreterModule* module;
InterpreterFuncArray funcs;
InterpreterFunc* current_func;
- ExprNodeVector expr_stack;
- TypecheckLabelVector typecheck_label_stack;
- EmitLabelVector emit_label_stack;
+ WasmTypeVector expr_stack;
+ LabelVector label_stack;
Uint32VectorVector func_fixups;
Uint32VectorVector depth_fixups;
- Uint32Vector discarded_exprs; /* bitset */
- uint32_t value_stack_size;
uint32_t depth;
- uint32_t expr_count;
uint32_t start_func_index;
WasmMemoryWriter istream_writer;
uint32_t istream_offset;
@@ -180,13 +158,13 @@ typedef struct Context {
uint32_t table_offset;
} Context;
-static TypecheckLabel* get_typecheck_label(Context* ctx, uint32_t depth) {
- assert(depth < ctx->typecheck_label_stack.size);
- return &ctx->typecheck_label_stack.data[depth];
+static Label* get_label(Context* ctx, uint32_t depth) {
+ assert(depth < ctx->label_stack.size);
+ return &ctx->label_stack.data[depth];
}
-static TypecheckLabel* top_typecheck_label(Context* ctx) {
- return get_typecheck_label(ctx, ctx->typecheck_label_stack.size - 1);
+static Label* top_label(Context* ctx) {
+ return get_label(ctx, ctx->label_stack.size - 1);
}
static uint32_t get_value_count(WasmType result_type) {
@@ -194,18 +172,6 @@ static uint32_t get_value_count(WasmType result_type) {
: 1;
}
-static WasmBool is_expr_discarded(Context* ctx, uint32_t expr_index) {
- uint32_t word_index = expr_index >> 5;
- if (word_index >= ctx->discarded_exprs.size)
- return WASM_FALSE;
-
- uint32_t bit_index = expr_index & 31;
- assert(word_index < ctx->discarded_exprs.size);
- return (ctx->discarded_exprs.data[word_index] & (1U << bit_index))
- ? WASM_TRUE
- : WASM_FALSE;
-}
-
static void on_error(uint32_t offset, const char* message, void* user_data);
static void print_error(Context* ctx, const char* format, ...) {
@@ -250,14 +216,142 @@ static WasmType get_global_index_type(Context* ctx, uint32_t global_index) {
return ctx->module->globals.data[global_index].type;
}
-static uint32_t translate_depth(Context* ctx, size_t size, uint32_t depth) {
- assert(depth < size);
- return size - 1 - depth;
+static uint32_t translate_local_index(Context* ctx, uint32_t local_index) {
+ assert(local_index < ctx->expr_stack.size);
+ return ctx->expr_stack.size - local_index;
}
-static uint32_t translate_local_index(Context* ctx, uint32_t local_index) {
- assert(local_index < ctx->value_stack_size);
- return ctx->value_stack_size - local_index;
+static uint32_t get_istream_offset(Context* ctx) {
+ return ctx->istream_offset;
+}
+
+static WasmResult emit_data_at(Context* ctx,
+ size_t offset,
+ const void* data,
+ size_t size) {
+ return ctx->istream_writer.base.write_data(
+ offset, data, size, ctx->istream_writer.base.user_data);
+}
+
+static WasmResult emit_data(Context* ctx, const void* data, size_t size) {
+ CHECK_RESULT(emit_data_at(ctx, ctx->istream_offset, data, size));
+ ctx->istream_offset += size;
+ return WASM_OK;
+}
+
+static WasmResult emit_opcode(Context* ctx, WasmOpcode opcode) {
+ return emit_data(ctx, &opcode, sizeof(uint8_t));
+}
+
+static WasmResult emit_i8(Context* ctx, uint8_t value) {
+ return emit_data(ctx, &value, sizeof(value));
+}
+
+static WasmResult emit_i32(Context* ctx, uint32_t value) {
+ return emit_data(ctx, &value, sizeof(value));
+}
+
+static WasmResult emit_i64(Context* ctx, uint64_t value) {
+ return emit_data(ctx, &value, sizeof(value));
+}
+
+static WasmResult emit_i32_at(Context* ctx, uint32_t offset, uint32_t value) {
+ return emit_data_at(ctx, offset, &value, sizeof(value));
+}
+
+static WasmResult emit_drop_keep(Context* ctx, uint32_t drop, uint8_t keep) {
+ assert(drop != UINT32_MAX);
+ assert(keep <= 1);
+ if (drop > 0) {
+ if (drop == 1 && keep == 0) {
+ LOGF("%3" PRIzd ": drop\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DROP));
+ } else {
+ LOGF("%3" PRIzd ": drop_keep %u %u\n", ctx->expr_stack.size, drop, keep);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DROP_KEEP));
+ CHECK_RESULT(emit_i32(ctx, drop));
+ CHECK_RESULT(emit_i8(ctx, keep));
+ }
+ }
+ return WASM_OK;
+}
+
+static WasmResult emit_return(Context* ctx, WasmType result_type) {
+ /* drop the locals and params, but keep the return value, if any */
+ uint32_t keep_count = get_value_count(result_type);
+ assert(ctx->expr_stack.size >= keep_count);
+ uint32_t drop_count = ctx->expr_stack.size - keep_count;
+ CHECK_RESULT(emit_drop_keep(ctx, drop_count, keep_count));
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_RETURN));
+ return WASM_OK;
+}
+
+static WasmResult append_fixup(Context* ctx,
+ Uint32VectorVector* fixups_vector,
+ uint32_t index) {
+ if (index >= fixups_vector->size)
+ wasm_resize_uint32_vector_vector(ctx->allocator, fixups_vector, index + 1);
+ Uint32Vector* fixups = &fixups_vector->data[index];
+ uint32_t offset = get_istream_offset(ctx);
+ wasm_append_uint32_value(ctx->allocator, fixups, &offset);
+ return WASM_OK;
+}
+
+static WasmResult emit_br_offset(Context* ctx,
+ uint32_t depth,
+ uint32_t offset) {
+ if (offset == WASM_INVALID_OFFSET)
+ CHECK_RESULT(append_fixup(ctx, &ctx->depth_fixups, depth));
+ CHECK_RESULT(emit_i32(ctx, offset));
+ return WASM_OK;
+}
+
+static WasmResult emit_br(Context* ctx, uint8_t arity, uint32_t depth) {
+ Label* label = get_label(ctx, depth);
+ assert(ctx->expr_stack.size >= label->expr_stack_size + arity);
+ uint32_t drop_count = (ctx->expr_stack.size - label->expr_stack_size) - arity;
+ CHECK_RESULT(emit_drop_keep(ctx, drop_count, arity));
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR));
+ CHECK_RESULT(emit_br_offset(ctx, depth, label->offset));
+ return WASM_OK;
+}
+
+static WasmResult emit_br_table_offset(Context* ctx,
+ uint8_t arity,
+ uint32_t depth) {
+ Label* label = get_label(ctx, depth);
+ assert(ctx->expr_stack.size >= label->expr_stack_size + arity);
+ uint32_t drop_count = (ctx->expr_stack.size - label->expr_stack_size) - arity;
+ CHECK_RESULT(emit_br_offset(ctx, depth, label->offset));
+ CHECK_RESULT(emit_i32(ctx, drop_count));
+ CHECK_RESULT(emit_i8(ctx, arity));
+ return WASM_OK;
+}
+
+static WasmResult fixup_top_label(Context* ctx, uint32_t offset) {
+ uint32_t top = ctx->label_stack.size - 1;
+ if (top >= ctx->depth_fixups.size) {
+ /* nothing to fixup */
+ return WASM_OK;
+ }
+
+ Uint32Vector* fixups = &ctx->depth_fixups.data[top];
+ uint32_t i;
+ for (i = 0; i < fixups->size; ++i)
+ CHECK_RESULT(emit_i32_at(ctx, fixups->data[i], offset));
+ /* reduce the size to 0 in case this gets reused. Keep the allocations for
+ * later use */
+ fixups->size = 0;
+ return WASM_OK;
+}
+
+static WasmResult emit_func_offset(Context* ctx,
+ InterpreterFunc* func,
+ uint32_t func_index) {
+ if (func->offset == WASM_INVALID_OFFSET)
+ CHECK_RESULT(append_fixup(ctx, &ctx->func_fixups, func_index));
+ CHECK_RESULT(emit_i32(ctx, func->offset));
+ return WASM_OK;
}
static void on_error(uint32_t offset, const char* message, void* user_data) {
@@ -510,42 +604,6 @@ static WasmResult on_function_bodies_count(uint32_t count, void* user_data) {
return WASM_OK;
}
-/* defined below so they can reference s_binary_reader{,_emit} */
-static WasmResult begin_function_body_pass(uint32_t index,
- uint32_t pass,
- void* user_data);
-static WasmResult end_function_body_pass(uint32_t index,
- uint32_t pass,
- void* user_data);
-
-/* Code generation happens per function in two passes. First, the function is
- * type-checked, bottom up. While this is done, a bitset ("discarded_exprs") is
- * maintained.
- *
- * There are three different but related meanings for a bit being set in
- * |discarded_exprs|:
- *
- * 1) if the operator is a block, loop or if: the bit is set if the block does
- * not use its value. This is used when emitting a br to determine whether its
- * value should be discarded.
- *
- * 2) if the operator is br_if: the bit is set if the br_if has a value. This
- * is used to determine whether the br_if value needs to be discarded if the
- * branch is not taken.
- *
- * 3) otherwise: the bit is set if the expression is subsequently discarded
- * (e.g. a set_local whose value is not used.)
- *
- * The second pass is the emit pass, where instructions are written to an
- * instruction stream, to be executed by the stack machine interpreter.
- *
- * Two passes are needed because you can't determine whether a value is used in
- * one pass. It would be possible to generate code in one pass, but it would
- * use a very large stack for blocks with many discarded expressions.
- */
-
-/*** typecheck pass ***********************************************************/
-
static WasmResult type_mismatch(Context* ctx,
WasmType expected_type,
WasmType type,
@@ -583,81 +641,93 @@ static WasmResult unify_and_check_type(Context* ctx,
return check_type(ctx, *dest_type, type, desc);
}
-static uint32_t translate_typecheck_depth(Context* ctx, uint32_t depth) {
- return translate_depth(ctx, ctx->typecheck_label_stack.size, depth);
+static uint32_t translate_depth(Context* ctx, uint32_t depth) {
+ assert(depth < ctx->label_stack.size);
+ return ctx->label_stack.size - 1 - depth;
}
-static void push_typecheck_label(Context* ctx,
- LabelType label_type,
- WasmType type) {
- TypecheckLabel* label =
- wasm_append_typecheck_label(ctx->allocator, &ctx->typecheck_label_stack);
+static void push_label(Context* ctx,
+ LabelType label_type,
+ WasmType type,
+ uint32_t offset,
+ uint32_t fixup_offset) {
+ Label* label = wasm_append_label(ctx->allocator, &ctx->label_stack);
label->label_type = label_type;
label->type = type;
label->expr_stack_size = ctx->expr_stack.size;
- label->expr_index = ctx->expr_count;
- LOGF(" : +depth %" PRIzd ":%s\n", ctx->typecheck_label_stack.size - 1,
+ label->offset = offset;
+ label->fixup_offset = fixup_offset;
+ LOGF(" : +depth %" PRIzd ":%s\n", ctx->label_stack.size - 1,
s_type_names[type]);
}
-static void pop_typecheck_label(Context* ctx) {
- LOGF(" : -depth %" PRIzd "\n", ctx->typecheck_label_stack.size - 1);
- assert(ctx->typecheck_label_stack.size > 0);
- ctx->typecheck_label_stack.size--;
+static void pop_label(Context* ctx) {
+ LOGF(" : -depth %" PRIzd "\n", ctx->label_stack.size - 1);
+ assert(ctx->label_stack.size > 0);
+ ctx->label_stack.size--;
+ /* reduce the depth_fixups stack as well, but it may be smaller than
+ * label_stack so only do it conditionally. */
+ if (ctx->depth_fixups.size > ctx->label_stack.size) {
+ uint32_t from = ctx->label_stack.size;
+ uint32_t to = ctx->depth_fixups.size;
+ uint32_t i;
+ for (i = from; i < to; ++i)
+ wasm_destroy_uint32_vector(ctx->allocator, &ctx->depth_fixups.data[i]);
+ ctx->depth_fixups.size = ctx->label_stack.size;
+ }
}
static void push_expr(Context* ctx, WasmType type, WasmOpcode opcode) {
+ /* TODO: refactor to remove opcode param */
if (type != WASM_TYPE_VOID) {
- LOGF("%3" PRIzd ": push %s:%s (#%u)\n", ctx->expr_stack.size,
- s_opcode_name[opcode], s_type_names[type], ctx->expr_count);
- ExprNode* expr;
- expr = wasm_append_expr_node(ctx->allocator, &ctx->expr_stack);
- expr->index = ctx->expr_count;
- expr->type = type;
+ Label* label = top_label(ctx);
+ if (ctx->expr_stack.size > label->expr_stack_size) {
+ WasmType top_type = ctx->expr_stack.data[ctx->expr_stack.size - 1];
+ if (top_type == WASM_TYPE_ANY)
+ return;
+ }
+
+ LOGF("%3" PRIzd ": push %s:%s\n", ctx->expr_stack.size,
+ s_opcode_name[opcode], s_type_names[type]);
+ wasm_append_type_value(ctx->allocator, &ctx->expr_stack, &type);
}
- ctx->expr_count++;
}
-static WasmType pop_expr(Context* ctx) {
- assert(ctx->expr_stack.size > 0);
- ExprNode* expr = &ctx->expr_stack.data[ctx->expr_stack.size - 1];
-
- LOGF("%3" PRIzd ": pop %s (#%u)\n", ctx->expr_stack.size,
- s_type_names[expr->type], expr->index);
+static WasmType top_expr(Context* ctx) {
+ Label* label = top_label(ctx);
+ assert(ctx->expr_stack.size > label->expr_stack_size);
+ return ctx->expr_stack.data[ctx->expr_stack.size - 1];
+}
- WasmType type = expr->type;
+static WasmType pop_expr(Context* ctx) {
+ WasmType type = top_expr(ctx);
+ LOGF("%3" PRIzd ": pop %s\n", ctx->expr_stack.size, s_type_names[type]);
ctx->expr_stack.size--;
return type;
}
-static WasmType pop_expr_if(Context* ctx, WasmBool cond) {
+static WasmType top_expr_if(Context* ctx, WasmBool cond) {
if (cond)
- return pop_expr(ctx);
+ return top_expr(ctx);
return WASM_TYPE_VOID;
}
-static void set_expr_discarded(Context* ctx, uint32_t expr_index) {
- LOGF(" : set_expr_discarded #%u\n", expr_index);
- uint32_t word_index = expr_index >> 5;
- size_t new_size = word_index + 1;
- if (new_size > ctx->discarded_exprs.capacity)
- wasm_reserve_uint32s(ctx->allocator, &ctx->discarded_exprs, new_size);
- size_t old_size = ctx->discarded_exprs.size;
- if (new_size > old_size) {
- memset(&ctx->discarded_exprs.data[old_size], 0,
- (new_size - old_size) * sizeof(uint32_t));
- ctx->discarded_exprs.size = new_size;
+static WasmResult check_end(Context* ctx, WasmType* top_type) {
+ Label* label = top_label(ctx);
+ assert(ctx->expr_stack.size >= label->expr_stack_size);
+ size_t stack_size = ctx->expr_stack.size - label->expr_stack_size;
+ if (stack_size == 0) {
+ *top_type = WASM_TYPE_VOID;
+ return WASM_OK;
}
- uint32_t bit_index = expr_index & 31;
- ctx->discarded_exprs.data[word_index] |= 1U << bit_index;
-}
+ WasmType type = top_expr(ctx);
+ *top_type = type;
+ if (type == WASM_TYPE_ANY || stack_size == 1)
+ return WASM_OK;
-static void set_expr_discarded_unless_void(Context* ctx,
- uint32_t expr_index,
- WasmType type) {
- if (type != WASM_TYPE_VOID)
- set_expr_discarded(ctx, expr_index);
+ print_error(ctx, "maximum arity is 1, got %" PRIzd ".", stack_size);
+ return WASM_ERROR;
}
static WasmResult begin_function_body(uint32_t index, void* user_data) {
@@ -665,51 +735,53 @@ static WasmResult begin_function_body(uint32_t index, void* user_data) {
InterpreterFunc* func = get_func(ctx, index);
WasmInterpreterFuncSignature* sig = get_signature(ctx, func->sig_index);
+ func->offset = get_istream_offset(ctx);
+ func->local_decl_count = 0;
+ func->local_count = 0;
+
ctx->current_func = func;
- ctx->expr_stack.size = 0;
- ctx->typecheck_label_stack.size = 0;
- ctx->discarded_exprs.size = 0;
+ ctx->depth_fixups.size = 0;
+ ctx->expr_stack.size = sig->param_types.size;
+ ctx->label_stack.size = 0;
ctx->depth = 0;
- ctx->expr_count = 0;
- /* append param types */
+ /* fixup function references */
uint32_t i;
+ Uint32Vector* fixups = &ctx->func_fixups.data[index];
+ for (i = 0; i < fixups->size; ++i)
+ CHECK_RESULT(emit_i32_at(ctx, fixups->data[i], func->offset));
+
+ /* append param types */
for (i = 0; i < sig->param_types.size; ++i) {
wasm_append_type_value(ctx->allocator, &func->param_and_local_types,
&sig->param_types.data[i]);
}
/* push implicit func label (equivalent to return) */
- push_typecheck_label(ctx, LABEL_TYPE_FUNC, sig->result_type);
-
+ push_label(ctx, LABEL_TYPE_FUNC, sig->result_type, WASM_INVALID_OFFSET,
+ WASM_INVALID_OFFSET);
return WASM_OK;
}
static WasmResult end_function_body(uint32_t index, void* user_data) {
Context* ctx = user_data;
- uint32_t discard_max = 0;
-
- pop_typecheck_label(ctx);
-
WasmInterpreterFuncSignature* sig =
get_func_signature(ctx, ctx->current_func);
- if (sig->result_type == WASM_TYPE_VOID) {
- /* discard all expr */
- discard_max = ctx->expr_stack.size;
- } else if (ctx->expr_stack.size > 0) {
- /* discard everything except the last expr */
- discard_max = ctx->expr_stack.size - 1;
- } else {
- return WASM_ERROR;
- }
-
- uint32_t i;
- for (i = 0; i < discard_max; ++i) {
- ExprNode* expr = &ctx->expr_stack.data[i];
- set_expr_discarded_unless_void(ctx, expr->index, expr->type);
- }
+ WasmType top_type;
+ CHECK_RESULT(check_end(ctx, &top_type));
+ CHECK_RESULT(check_type(ctx, sig->result_type, top_type, "implicit return"));
+ CHECK_RESULT(emit_return(ctx, sig->result_type));
+ pop_label(ctx);
ctx->current_func = NULL;
+ ctx->expr_stack.size = 0;
+ return WASM_OK;
+}
+
+static WasmResult on_local_decl_count(uint32_t count, void* user_data) {
+ Context* ctx = user_data;
+ InterpreterFunc* func = ctx->current_func;
+ func->local_decl_count = count;
return WASM_OK;
}
@@ -718,96 +790,111 @@ static WasmResult on_local_decl(uint32_t decl_index,
WasmType type,
void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": alloca\n", ctx->expr_stack.size);
InterpreterFunc* func = ctx->current_func;
+ func->local_count += count;
uint32_t i;
- for (i = 0; i < count; ++i)
+ for (i = 0; i < count; ++i) {
wasm_append_type_value(ctx->allocator, &func->param_and_local_types, &type);
+ push_expr(ctx, type, WASM_OPCODE_ALLOCA);
+ }
+
+ if (decl_index == func->local_decl_count - 1) {
+ /* last local declaration, allocate space for all locals. */
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_ALLOCA));
+ CHECK_RESULT(emit_i32(ctx, func->local_count));
+ /* fixup the function label's expr_stack_size to include these values. */
+ Label* label = top_label(ctx);
+ assert(label->label_type == LABEL_TYPE_FUNC);
+ label->expr_stack_size += func->local_count;
+ }
return WASM_OK;
}
static WasmResult on_unary_expr(WasmOpcode opcode, void* user_data) {
Context* ctx = user_data;
+ const char* opcode_name = s_opcode_name[opcode];
+ LOGF("%3" PRIzd ": %s\n", ctx->expr_stack.size, opcode_name);
WasmType value = pop_expr(ctx);
- CHECK_RESULT(
- check_type(ctx, s_opcode_type1[opcode], value, s_opcode_name[opcode]));
+ CHECK_RESULT(check_type(ctx, s_opcode_type1[opcode], value, opcode_name));
+ CHECK_RESULT(emit_opcode(ctx, opcode));
push_expr(ctx, s_opcode_rtype[opcode], opcode);
return WASM_OK;
}
static WasmResult on_binary_expr(WasmOpcode opcode, void* user_data) {
Context* ctx = user_data;
+ const char* opcode_name = s_opcode_name[opcode];
+ LOGF("%3" PRIzd ": %s\n", ctx->expr_stack.size, opcode_name);
WasmType right = pop_expr(ctx);
WasmType left = pop_expr(ctx);
- /* TODO use opcode name here */
- CHECK_RESULT(
- check_type(ctx, s_opcode_type1[opcode], left, s_opcode_name[opcode]));
- CHECK_RESULT(
- check_type(ctx, s_opcode_type2[opcode], right, s_opcode_name[opcode]));
+ CHECK_RESULT(check_type(ctx, s_opcode_type1[opcode], left, opcode_name));
+ CHECK_RESULT(check_type(ctx, s_opcode_type2[opcode], right, opcode_name));
+ CHECK_RESULT(emit_opcode(ctx, opcode));
push_expr(ctx, s_opcode_rtype[opcode], opcode);
return WASM_OK;
}
static WasmResult on_block_expr(void* user_data) {
Context* ctx = user_data;
- LOGF("%3" PRIzd ": block (#%u)\n", ctx->expr_stack.size, ctx->expr_count);
- push_typecheck_label(ctx, LABEL_TYPE_BLOCK, WASM_TYPE_ANY);
- ctx->expr_count++;
+ LOGF("%3" PRIzd ": block\n", ctx->expr_stack.size);
+ push_label(ctx, LABEL_TYPE_BLOCK, WASM_TYPE_ANY, WASM_INVALID_OFFSET,
+ WASM_INVALID_OFFSET);
return WASM_OK;
}
static WasmResult on_loop_expr(void* user_data) {
Context* ctx = user_data;
- LOGF("%3" PRIzd ": loop (#%u)\n", ctx->expr_stack.size, ctx->expr_count);
- push_typecheck_label(ctx, LABEL_TYPE_LOOP, WASM_TYPE_VOID);
- ctx->expr_count++;
+ LOGF("%3" PRIzd ": loop\n", ctx->expr_stack.size);
+ push_label(ctx, LABEL_TYPE_LOOP, WASM_TYPE_VOID, get_istream_offset(ctx),
+ WASM_INVALID_OFFSET);
return WASM_OK;
}
static WasmResult on_if_expr(void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": if\n", ctx->expr_stack.size);
WasmType cond = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, cond, "if"));
- LOGF("%3" PRIzd ": if (#%u)\n", ctx->expr_stack.size, ctx->expr_count);
- push_typecheck_label(ctx, LABEL_TYPE_IF, WASM_TYPE_ANY);
- ctx->expr_count++;
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_UNLESS));
+ uint32_t fixup_offset = get_istream_offset(ctx);
+ CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
+ push_label(ctx, LABEL_TYPE_IF, WASM_TYPE_ANY, WASM_INVALID_OFFSET,
+ fixup_offset);
return WASM_OK;
}
static WasmResult on_else_expr(void* user_data) {
Context* ctx = user_data;
- TypecheckLabel* label = top_typecheck_label(ctx);
+ LOGF("%3" PRIzd ": else\n", ctx->expr_stack.size);
+ Label* label = top_label(ctx);
if (!label || label->label_type != LABEL_TYPE_IF) {
print_error(ctx, "unexpected else operator");
return WASM_ERROR;
}
- LOGF("%3" PRIzd ": else (#%u)\n", ctx->expr_stack.size, ctx->expr_count);
-
- if (label->expr_stack_size < ctx->expr_stack.size) {
- ExprNode* last_expr = &ctx->expr_stack.data[ctx->expr_stack.size - 1];
- label->last_expr_index = last_expr->index;
- CHECK_RESULT(unify_and_check_type(ctx, &label->type, last_expr->type,
- "if true branch"));
-
- /* discard everything except the last expr; we don't know if we'll need to
- * discard that one until after we process the false branch */
- uint32_t i;
- for (i = label->expr_stack_size; i < ctx->expr_stack.size - 1; ++i) {
- ExprNode* expr = &ctx->expr_stack.data[i];
- set_expr_discarded_unless_void(ctx, expr->index, expr->type);
- }
- }
+ WasmType top_type;
+ CHECK_RESULT(check_end(ctx, &top_type));
+ CHECK_RESULT(
+ unify_and_check_type(ctx, &label->type, top_type, "if true branch"));
label->label_type = LABEL_TYPE_ELSE;
+ uint32_t fixup_cond_offset = label->fixup_offset;
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR));
+ label->fixup_offset = get_istream_offset(ctx);
+ CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
+ CHECK_RESULT(emit_i32_at(ctx, fixup_cond_offset, get_istream_offset(ctx)));
+ /* reset the expr stack for the other branch arm */
ctx->expr_stack.size = label->expr_stack_size;
return WASM_OK;
}
static WasmResult on_end_expr(void* user_data) {
Context* ctx = user_data;
- TypecheckLabel* label = top_typecheck_label(ctx);
- if (!label) {
+ LOGF("%3" PRIzd ": end\n", ctx->expr_stack.size);
+ Label* label = top_label(ctx);
+ if (!label || label->label_type == LABEL_TYPE_FUNC) {
print_error(ctx, "unexpected end operator");
return WASM_ERROR;
}
@@ -815,56 +902,33 @@ static WasmResult on_end_expr(void* user_data) {
if (label->label_type == LABEL_TYPE_IF)
label->type = WASM_TYPE_VOID;
- if (label->expr_stack_size < ctx->expr_stack.size) {
- ExprNode* last_expr = &ctx->expr_stack.data[ctx->expr_stack.size - 1];
- WasmType old_type = label->type;
- CHECK_RESULT(unify_and_check_type(ctx, &label->type, last_expr->type,
- s_label_type_name[label->label_type]));
- if (label->label_type == LABEL_TYPE_ELSE &&
- get_value_count(old_type) > get_value_count(label->type)) {
- /* we unified the types between the true and false branches; the true
- * branch had a value and the false branch didn't, so we need to discard
- * the true branch's value */
- set_expr_discarded(ctx, label->last_expr_index);
- }
-
- /* discard everything except the last expr */
- uint32_t i;
- for (i = label->expr_stack_size; i < ctx->expr_stack.size - 1; ++i) {
- ExprNode* expr = &ctx->expr_stack.data[i];
- set_expr_discarded_unless_void(ctx, expr->index, expr->type);
- }
-
- if (label->type == WASM_TYPE_VOID) {
- /* discard the last child expr if this block/if/loop is void */
- set_expr_discarded_unless_void(ctx, last_expr->index, last_expr->type);
- }
- } else {
- /* the block/loop/if was empty */
- label->type = WASM_TYPE_VOID;
- }
+ WasmType top_type;
+ CHECK_RESULT(check_end(ctx, &top_type));
+ CHECK_RESULT(unify_and_check_type(ctx, &label->type, top_type,
+ s_label_type_name[label->label_type]));
- if (label->type == WASM_TYPE_VOID) {
- /* the "discarded" bit is overloaded for the initial block/loop/if
- * operators; in that case it means that there is no value expected to be
- * returned, so if a br operator yields a value, it should be immediately
- * discarded */
- set_expr_discarded(ctx, label->expr_index);
+ if (label->label_type == LABEL_TYPE_IF ||
+ label->label_type == LABEL_TYPE_ELSE) {
+ uint32_t fixup_true_offset = label->fixup_offset;
+ CHECK_RESULT(emit_i32_at(ctx, fixup_true_offset, get_istream_offset(ctx)));
}
+ fixup_top_label(ctx, get_istream_offset(ctx));
ctx->expr_stack.size = label->expr_stack_size;
- pop_typecheck_label(ctx);
+ pop_label(ctx);
push_expr(ctx, label->type, WASM_OPCODE_END);
return WASM_OK;
}
static WasmResult on_br_expr(uint8_t arity, uint32_t depth, void* user_data) {
Context* ctx = user_data;
- WasmType value = pop_expr_if(ctx, arity == 1);
+ LOGF("%3" PRIzd ": br\n", ctx->expr_stack.size);
+ WasmType value = top_expr_if(ctx, arity > 0);
CHECK_DEPTH(ctx, depth);
- depth = translate_typecheck_depth(ctx, depth);
- TypecheckLabel* label = get_typecheck_label(ctx, depth);
+ depth = translate_depth(ctx, depth);
+ Label* label = get_label(ctx, depth);
CHECK_RESULT(unify_and_check_type(ctx, &label->type, value, "br"));
+ CHECK_RESULT(emit_br(ctx, arity, depth));
push_expr(ctx, WASM_TYPE_ANY, WASM_OPCODE_BR);
return WASM_OK;
}
@@ -873,16 +937,23 @@ static WasmResult on_br_if_expr(uint8_t arity,
uint32_t depth,
void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": br_if\n", ctx->expr_stack.size);
WasmType cond = pop_expr(ctx);
- WasmType value = pop_expr_if(ctx, arity == 1);
+ WasmType value = top_expr_if(ctx, arity > 0);
CHECK_DEPTH(ctx, depth);
- depth = translate_typecheck_depth(ctx, depth);
- TypecheckLabel* label = get_typecheck_label(ctx, depth);
+ depth = translate_depth(ctx, depth);
+ Label* label = get_label(ctx, depth);
CHECK_RESULT(unify_and_check_type(ctx, &label->type, value, "br_if"));
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, cond, "br_if"));
- /* the "discarded" bit is overloaded for br_if; if set, the br_if value is
- * non-void; i.e. should be discarded if the branch is not taken */
- set_expr_discarded_unless_void(ctx, ctx->expr_count, value);
+ /* flip the br_if so if <cond> is true it can drop values from the stack */
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_UNLESS));
+ uint32_t fixup_br_offset = get_istream_offset(ctx);
+ CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
+ CHECK_RESULT(emit_br(ctx, arity, depth));
+ CHECK_RESULT(emit_i32_at(ctx, fixup_br_offset, get_istream_offset(ctx)));
+ /* clean up the value (if any), when the branch isn't taken */
+ CHECK_RESULT(emit_drop_keep(ctx, arity, 0));
+ ctx->expr_stack.size -= arity;
push_expr(ctx, WASM_TYPE_VOID, WASM_OPCODE_BR_IF);
return WASM_OK;
}
@@ -893,16 +964,28 @@ static WasmResult on_br_table_expr(uint8_t arity,
uint32_t default_target_depth,
void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": br_table\n", ctx->expr_stack.size);
WasmType key = pop_expr(ctx);
- WasmType value = pop_expr_if(ctx, arity == 1);
+ WasmType value = top_expr_if(ctx, arity > 0);
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, key, "br_table"));
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_TABLE));
+ CHECK_RESULT(emit_i32(ctx, num_targets));
+ uint32_t fixup_table_offset = get_istream_offset(ctx);
+ CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
+ /* not necessary for the interpreter, but it makes it easier to disassemble.
+ * This opcode specifies how many bytes of data follow. */
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DATA));
+ CHECK_RESULT(emit_i32(ctx, (num_targets + 1) * WASM_TABLE_ENTRY_SIZE));
+ CHECK_RESULT(emit_i32_at(ctx, fixup_table_offset, get_istream_offset(ctx)));
+
uint32_t i;
for (i = 0; i <= num_targets; ++i) {
uint32_t depth = i != num_targets ? target_depths[i] : default_target_depth;
- uint32_t translated_depth = translate_typecheck_depth(ctx, depth);
- TypecheckLabel* label = get_typecheck_label(ctx, translated_depth);
+ depth = translate_depth(ctx, depth);
+ Label* label = get_label(ctx, depth);
CHECK_RESULT(unify_and_check_type(ctx, &label->type, value, "br_table"));
+ CHECK_RESULT(emit_br_table_offset(ctx, arity, depth));
}
push_expr(ctx, WASM_TYPE_ANY, WASM_OPCODE_BR_TABLE);
@@ -911,6 +994,7 @@ static WasmResult on_br_table_expr(uint8_t arity,
static WasmResult on_call_expr(uint32_t func_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": call\n", ctx->expr_stack.size);
assert(func_index < ctx->funcs.size);
InterpreterFunc* func = get_func(ctx, func_index);
WasmInterpreterFuncSignature* sig = get_func_signature(ctx, func);
@@ -921,12 +1005,15 @@ static WasmResult on_call_expr(uint32_t func_index, void* user_data) {
CHECK_RESULT(check_type(ctx, sig->param_types.data[i - 1], arg, "call"));
}
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_FUNCTION));
+ CHECK_RESULT(emit_func_offset(ctx, func, func_index));
push_expr(ctx, sig->result_type, WASM_OPCODE_CALL_FUNCTION);
return WASM_OK;
}
static WasmResult on_call_import_expr(uint32_t import_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": call_import\n", ctx->expr_stack.size);
assert(import_index < ctx->module->imports.size);
WasmInterpreterImport* import = get_import(ctx, import_index);
WasmInterpreterFuncSignature* sig = get_signature(ctx, import->sig_index);
@@ -938,14 +1025,16 @@ static WasmResult on_call_import_expr(uint32_t import_index, void* user_data) {
check_type(ctx, sig->param_types.data[i - 1], arg, "call_import"));
}
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_IMPORT));
+ CHECK_RESULT(emit_i32(ctx, import_index));
push_expr(ctx, sig->result_type, WASM_OPCODE_CALL_IMPORT);
return WASM_OK;
}
static WasmResult on_call_indirect_expr(uint32_t sig_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": call_indirect\n", ctx->expr_stack.size);
WasmInterpreterFuncSignature* sig = get_signature(ctx, sig_index);
-
WasmType entry_index = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, entry_index, "call_indirect"));
@@ -956,90 +1045,120 @@ static WasmResult on_call_indirect_expr(uint32_t sig_index, void* user_data) {
check_type(ctx, sig->param_types.data[i - 1], arg, "call_indirect"));
}
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_INDIRECT));
+ CHECK_RESULT(emit_i32(ctx, sig_index));
push_expr(ctx, sig->result_type, WASM_OPCODE_CALL_INDIRECT);
return WASM_OK;
}
static WasmResult on_drop_expr(void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": drop\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DROP));
pop_expr(ctx);
return WASM_OK;
}
static WasmResult on_i32_const_expr(uint32_t value, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": i32.const\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_I32_CONST));
+ CHECK_RESULT(emit_i32(ctx, value));
push_expr(ctx, WASM_TYPE_I32, WASM_OPCODE_I32_CONST);
return WASM_OK;
}
static WasmResult on_i64_const_expr(uint64_t value, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": i64.const\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_I64_CONST));
+ CHECK_RESULT(emit_i64(ctx, value));
push_expr(ctx, WASM_TYPE_I64, WASM_OPCODE_I64_CONST);
return WASM_OK;
}
static WasmResult on_f32_const_expr(uint32_t value_bits, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": f32.const\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_F32_CONST));
+ CHECK_RESULT(emit_i32(ctx, value_bits));
push_expr(ctx, WASM_TYPE_F32, WASM_OPCODE_F32_CONST);
return WASM_OK;
}
static WasmResult on_f64_const_expr(uint64_t value_bits, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": f64.const\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_F64_CONST));
+ CHECK_RESULT(emit_i64(ctx, value_bits));
push_expr(ctx, WASM_TYPE_F64, WASM_OPCODE_F64_CONST);
return WASM_OK;
}
static WasmResult on_get_global_expr(uint32_t global_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": get_global\n", ctx->expr_stack.size);
CHECK_GLOBAL(ctx, global_index);
WasmType type = get_global_index_type(ctx, global_index);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GET_GLOBAL));
+ CHECK_RESULT(emit_i32(ctx, global_index));
push_expr(ctx, type, WASM_OPCODE_GET_GLOBAL);
return WASM_OK;
}
static WasmResult on_set_global_expr(uint32_t global_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": set_global\n", ctx->expr_stack.size);
CHECK_GLOBAL(ctx, global_index);
WasmType type = get_global_index_type(ctx, global_index);
WasmType value = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, type, value, "set_global"));
- ctx->expr_count++;
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_SET_GLOBAL));
+ CHECK_RESULT(emit_i32(ctx, global_index));
return WASM_OK;
}
static WasmResult on_get_local_expr(uint32_t local_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": get_local\n", ctx->expr_stack.size);
CHECK_LOCAL(ctx, local_index);
WasmType type = get_local_index_type(ctx->current_func, local_index);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GET_LOCAL));
+ CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
push_expr(ctx, type, WASM_OPCODE_GET_LOCAL);
return WASM_OK;
}
static WasmResult on_set_local_expr(uint32_t local_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": set_local\n", ctx->expr_stack.size);
CHECK_LOCAL(ctx, local_index);
WasmType type = get_local_index_type(ctx->current_func, local_index);
WasmType value = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, type, value, "set_local"));
- ctx->expr_count++;
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_SET_LOCAL));
+ CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
return WASM_OK;
}
static WasmResult on_tee_local_expr(uint32_t local_index, void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": tee_local\n", ctx->expr_stack.size);
CHECK_LOCAL(ctx, local_index);
WasmType type = get_local_index_type(ctx->current_func, local_index);
WasmType value = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, type, value, "tee_local"));
- push_expr(ctx, type, WASM_OPCODE_TEE_LOCAL);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_TEE_LOCAL));
+ CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
return WASM_OK;
}
static WasmResult on_grow_memory_expr(void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": grow_memory\n", ctx->expr_stack.size);
WasmType value = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, value, "grow_memory"));
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GROW_MEMORY));
push_expr(ctx, WASM_TYPE_I32, WASM_OPCODE_GROW_MEMORY);
return WASM_OK;
}
@@ -1049,8 +1168,11 @@ static WasmResult on_load_expr(WasmOpcode opcode,
uint32_t offset,
void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": %s\n", ctx->expr_stack.size, s_opcode_name[opcode]);
WasmType addr = pop_expr(ctx);
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, addr, s_opcode_name[opcode]));
+ CHECK_RESULT(emit_opcode(ctx, opcode));
+ CHECK_RESULT(emit_i32(ctx, offset));
push_expr(ctx, s_opcode_rtype[opcode], opcode);
return WASM_OK;
}
@@ -1060,41 +1182,50 @@ static WasmResult on_store_expr(WasmOpcode opcode,
uint32_t offset,
void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": %s\n", ctx->expr_stack.size, s_opcode_name[opcode]);
WasmType value = pop_expr(ctx);
WasmType addr = pop_expr(ctx);
WasmType type = s_opcode_rtype[opcode];
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, addr, s_opcode_name[opcode]));
CHECK_RESULT(check_type(ctx, type, value, s_opcode_name[opcode]));
+ CHECK_RESULT(emit_opcode(ctx, opcode));
+ CHECK_RESULT(emit_i32(ctx, offset));
push_expr(ctx, type, opcode);
return WASM_OK;
}
static WasmResult on_current_memory_expr(void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": current_memory\n", ctx->expr_stack.size);
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CURRENT_MEMORY));
push_expr(ctx, WASM_TYPE_I32, WASM_OPCODE_CURRENT_MEMORY);
return WASM_OK;
}
static WasmResult on_nop_expr(void* user_data) {
Context* ctx = user_data;
- push_expr(ctx, WASM_TYPE_VOID, WASM_OPCODE_NOP);
+ WASM_USE(ctx);
+ LOGF("%3" PRIzd ": nop\n", ctx->expr_stack.size);
return WASM_OK;
}
static WasmResult on_return_expr(void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": return\n", ctx->expr_stack.size);
WasmInterpreterFuncSignature* sig =
get_func_signature(ctx, ctx->current_func);
if (get_value_count(sig->result_type)) {
- WasmType value = pop_expr(ctx);
+ WasmType value = top_expr(ctx);
CHECK_RESULT(check_type(ctx, sig->result_type, value, "return"));
}
+ CHECK_RESULT(emit_return(ctx, sig->result_type));
push_expr(ctx, WASM_TYPE_ANY, WASM_OPCODE_RETURN);
return WASM_OK;
}
static WasmResult on_select_expr(void* user_data) {
Context* ctx = user_data;
+ LOGF("%3" PRIzd ": select\n", ctx->expr_stack.size);
WasmType cond = pop_expr(ctx);
WasmType right = pop_expr(ctx);
WasmType left = pop_expr(ctx);
@@ -1102,726 +1233,16 @@ static WasmResult on_select_expr(void* user_data) {
CHECK_RESULT(unify_and_check_type(ctx, &type, left, "select"));
CHECK_RESULT(unify_and_check_type(ctx, &type, right, "select"));
CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, cond, "select"));
+ CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_SELECT));
push_expr(ctx, type, WASM_OPCODE_SELECT);
return WASM_OK;
}
static WasmResult on_unreachable_expr(void* user_data) {
Context* ctx = user_data;
- push_expr(ctx, WASM_TYPE_ANY, WASM_OPCODE_UNREACHABLE);
- return WASM_OK;
-}
-
-/*** emit pass ****************************************************************/
-
-static uint32_t get_istream_offset(Context* ctx) {
- return ctx->istream_offset;
-}
-
-static WasmResult emit_data_at(Context* ctx,
- size_t offset,
- const void* data,
- size_t size) {
- return ctx->istream_writer.base.write_data(
- offset, data, size, ctx->istream_writer.base.user_data);
-}
-
-static WasmResult emit_data(Context* ctx, const void* data, size_t size) {
- CHECK_RESULT(emit_data_at(ctx, ctx->istream_offset, data, size));
- ctx->istream_offset += size;
- return WASM_OK;
-}
-
-static WasmResult emit_opcode(Context* ctx, WasmOpcode opcode) {
- return emit_data(ctx, &opcode, sizeof(uint8_t));
-}
-
-static WasmResult emit_i8(Context* ctx, uint8_t value) {
- return emit_data(ctx, &value, sizeof(value));
-}
-
-static WasmResult emit_i32(Context* ctx, uint32_t value) {
- return emit_data(ctx, &value, sizeof(value));
-}
-
-static WasmResult emit_i64(Context* ctx, uint64_t value) {
- return emit_data(ctx, &value, sizeof(value));
-}
-
-static WasmResult emit_i32_at(Context* ctx, uint32_t offset, uint32_t value) {
- return emit_data_at(ctx, offset, &value, sizeof(value));
-}
-
-static void adjust_value_stack(Context* ctx, int32_t amount) {
- uint32_t old_size = ctx->value_stack_size;
- uint32_t new_size = old_size + (uint32_t)amount;
- assert((amount <= 0 && new_size <= old_size) ||
- (amount > 0 && new_size > old_size));
- WASM_USE(old_size);
- WASM_USE(new_size);
- ctx->value_stack_size += (uint32_t)amount;
-#ifndef NDEBUG
- if (ctx->emit_label_stack.size > 0) {
- assert(ctx->value_stack_size >=
- ctx->emit_label_stack.data[ctx->emit_label_stack.size - 1]
- .value_stack_size);
- } else {
- assert(ctx->value_stack_size >=
- ctx->current_func->param_and_local_types.size);
- }
-#endif
-}
-
-static void adjust_value_stack_for_nonlocal_continuation(Context* ctx) {
- /* adjust stack up; these operations type-check as ANY, so they can be used in
- * any operation. No value will actually be pushed, and the expressions that
- * use the result won't ever be executed. But it will make the stack the
- * "normal" size, so we won't have to special case it anywhere else. */
- adjust_value_stack(ctx, is_expr_discarded(ctx, ctx->expr_count) ? 0 : 1);
-}
-
-static EmitLabel* get_emit_label(Context* ctx, uint32_t depth) {
- assert(depth < ctx->emit_label_stack.size);
- return &ctx->emit_label_stack.data[depth];
-}
-
-static EmitLabel* top_emit_label(Context* ctx) {
- return get_emit_label(ctx, ctx->emit_label_stack.size - 1);
-}
-
-static uint32_t translate_emit_depth(Context* ctx, uint32_t depth) {
- return translate_depth(ctx, ctx->emit_label_stack.size, depth);
-}
-
-static void push_emit_label(Context* ctx,
- LabelType label_type,
- uint32_t offset,
- uint32_t fixup_offset,
- WasmBool has_value) {
- EmitLabel* label =
- wasm_append_emit_label(ctx->allocator, &ctx->emit_label_stack);
- label->label_type = label_type;
- label->offset = offset;
- label->value_stack_size = ctx->value_stack_size;
- label->has_value = has_value;
- label->fixup_offset = fixup_offset;
- LOGF(" : +depth %" PRIzd "\n", ctx->emit_label_stack.size - 1);
-}
-
-static void pop_emit_label(Context* ctx) {
- LOGF(" : -depth %" PRIzd "\n", ctx->emit_label_stack.size - 1);
- assert(ctx->emit_label_stack.size > 0);
- ctx->emit_label_stack.size--;
- /* reduce the depth_fixups stack as well, but it may be smaller than
- * emit_label_stack so only do it conditionally. */
- if (ctx->depth_fixups.size > ctx->emit_label_stack.size) {
- uint32_t from = ctx->emit_label_stack.size;
- uint32_t to = ctx->depth_fixups.size;
- uint32_t i;
- for (i = from; i < to; ++i)
- wasm_destroy_uint32_vector(ctx->allocator, &ctx->depth_fixups.data[i]);
- ctx->depth_fixups.size = ctx->emit_label_stack.size;
- }
-}
-
-static WasmResult fixup_top_emit_label(Context* ctx, uint32_t offset) {
- uint32_t top = ctx->emit_label_stack.size - 1;
- if (top >= ctx->depth_fixups.size) {
- /* nothing to fixup */
- return WASM_OK;
- }
-
- Uint32Vector* fixups = &ctx->depth_fixups.data[top];
- uint32_t i;
- for (i = 0; i < fixups->size; ++i)
- CHECK_RESULT(emit_i32_at(ctx, fixups->data[i], offset));
- /* reduce the size to 0 in case this gets reused. Keep the allocations for
- * later use */
- fixups->size = 0;
- return WASM_OK;
-}
-
-static WasmResult emit_discard(Context* ctx) {
- LOGF("%3" PRIzd ": discard\n", ctx->value_stack_size);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DISCARD));
- adjust_value_stack(ctx, -1);
- return WASM_OK;
-}
-
-static WasmResult maybe_emit_discard(Context* ctx, uint32_t expr_index) {
- WasmBool should_discard = is_expr_discarded(ctx, expr_index);
- if (should_discard)
- return emit_discard(ctx);
- return WASM_OK;
-}
-
-static WasmResult emit_discard_keep(Context* ctx,
- uint32_t discard,
- uint8_t keep) {
- assert(discard != UINT32_MAX);
- assert(keep <= 1);
- if (discard > 0) {
- if (discard == 1 && keep == 0) {
- LOGF("%3" PRIzd ": discard\n", ctx->value_stack_size);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DISCARD));
- } else {
- LOGF("%3" PRIzd ": discard_keep %u %u\n", ctx->value_stack_size, discard,
- keep);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DISCARD_KEEP));
- CHECK_RESULT(emit_i32(ctx, discard));
- CHECK_RESULT(emit_i8(ctx, keep));
- }
- }
- return WASM_OK;
-}
-
-static WasmResult emit_return(Context* ctx, WasmType result_type) {
- uint32_t keep_count = get_value_count(result_type);
- uint32_t discard_count = ctx->value_stack_size - keep_count;
- CHECK_RESULT(emit_discard_keep(ctx, discard_count, keep_count));
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_RETURN));
- return WASM_OK;
-}
-
-static WasmResult append_fixup(Context* ctx,
- Uint32VectorVector* fixups_vector,
- uint32_t index) {
- if (index >= fixups_vector->size)
- wasm_resize_uint32_vector_vector(ctx->allocator, fixups_vector, index + 1);
- Uint32Vector* fixups = &fixups_vector->data[index];
- uint32_t offset = get_istream_offset(ctx);
- wasm_append_uint32_value(ctx->allocator, fixups, &offset);
- return WASM_OK;
-}
-
-static WasmResult emit_br_offset(Context* ctx,
- uint32_t depth,
- uint32_t offset) {
- if (offset == WASM_INVALID_OFFSET)
- CHECK_RESULT(append_fixup(ctx, &ctx->depth_fixups, depth));
- CHECK_RESULT(emit_i32(ctx, offset));
- return WASM_OK;
-}
-
-static WasmResult emit_br(Context* ctx, uint32_t depth) {
- EmitLabel* label = get_emit_label(ctx, depth);
- assert(ctx->value_stack_size >= label->value_stack_size);
- uint8_t keep_count = label->has_value ? 1 : 0;
- uint32_t discard_count =
- (ctx->value_stack_size - label->value_stack_size) - keep_count;
- CHECK_RESULT(emit_discard_keep(ctx, discard_count, keep_count));
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR));
- CHECK_RESULT(emit_br_offset(ctx, depth, label->offset));
- return WASM_OK;
-}
-
-static WasmResult emit_br_table_offset(Context* ctx, uint32_t depth) {
- EmitLabel* label = get_emit_label(ctx, depth);
- uint8_t keep_count = label->has_value ? 1 : 0;
- uint32_t discard_count =
- (ctx->value_stack_size - label->value_stack_size) - keep_count;
- CHECK_RESULT(emit_br_offset(ctx, depth, label->offset));
- CHECK_RESULT(emit_i32(ctx, discard_count));
- CHECK_RESULT(emit_i8(ctx, keep_count));
- return WASM_OK;
-}
-
-static WasmResult emit_func_offset(Context* ctx,
- InterpreterFunc* func,
- uint32_t func_index) {
- if (func->offset == WASM_INVALID_OFFSET)
- CHECK_RESULT(append_fixup(ctx, &ctx->func_fixups, func_index));
- CHECK_RESULT(emit_i32(ctx, func->offset));
- return WASM_OK;
-}
-
-static WasmResult begin_emit_function_body(uint32_t index, void* user_data) {
- Context* ctx = user_data;
- InterpreterFunc* func = get_func(ctx, index);
- WasmInterpreterFuncSignature* sig = get_signature(ctx, func->sig_index);
-
- func->offset = get_istream_offset(ctx);
- func->local_decl_count = 0;
- func->local_count = 0;
-
- ctx->current_func = func;
- ctx->emit_label_stack.size = 0;
- ctx->depth_fixups.size = 0;
- ctx->value_stack_size = sig->param_types.size;
- ctx->depth = 0;
- ctx->expr_count = 0;
-
- /* fixup function references */
- uint32_t i;
- Uint32Vector* fixups = &ctx->func_fixups.data[index];
- for (i = 0; i < fixups->size; ++i)
- CHECK_RESULT(emit_i32_at(ctx, fixups->data[i], func->offset));
-
- push_emit_label(ctx, LABEL_TYPE_FUNC, WASM_INVALID_OFFSET, 0,
- sig->result_type != WASM_TYPE_VOID);
-
- return WASM_OK;
-}
-
-static WasmResult end_emit_function_body(uint32_t index, void* user_data) {
- Context* ctx = user_data;
- WasmInterpreterFuncSignature* sig =
- get_func_signature(ctx, ctx->current_func);
- fixup_top_emit_label(ctx, get_istream_offset(ctx));
- EmitLabel* label = top_emit_label(ctx);
- ctx->value_stack_size = label->value_stack_size;
- adjust_value_stack(ctx, label->has_value ? 1 : 0);
- CHECK_RESULT(emit_return(ctx, sig->result_type));
- pop_emit_label(ctx);
- ctx->current_func = NULL;
- ctx->value_stack_size = 0;
- return WASM_OK;
-}
-
-static WasmResult on_emit_local_decl_count(uint32_t count, void* user_data) {
- Context* ctx = user_data;
- ctx->current_func->local_decl_count = count;
- return WASM_OK;
-}
-
-static WasmResult on_emit_local_decl(uint32_t decl_index,
- uint32_t count,
- WasmType type,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_ALLOCA]);
- InterpreterFunc* func = ctx->current_func;
- func->local_count += count;
-
- if (decl_index == func->local_decl_count - 1) {
- /* last local declaration, allocate space for all locals. */
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_ALLOCA));
- CHECK_RESULT(emit_i32(ctx, func->local_count));
- adjust_value_stack(ctx, func->local_count);
-
- /* adjust the "return" label to include the locals in the value stack; this
- * way they'll be discarded when the function returns. */
- EmitLabel* label = top_emit_label(ctx);
- assert(label->label_type == LABEL_TYPE_FUNC);
- label->value_stack_size += func->local_count;
- }
- return WASM_OK;
-}
-
-static WasmResult on_emit_unary_expr(WasmOpcode opcode, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size, s_opcode_name[opcode]);
- CHECK_RESULT(emit_opcode(ctx, opcode));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_binary_expr(WasmOpcode opcode, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size, s_opcode_name[opcode]);
- adjust_value_stack(ctx, -1);
- CHECK_RESULT(emit_opcode(ctx, opcode));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_block_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_BLOCK]);
- push_emit_label(ctx, LABEL_TYPE_BLOCK, WASM_INVALID_OFFSET, 0,
- !is_expr_discarded(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_loop_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_LOOP]);
- push_emit_label(ctx, LABEL_TYPE_LOOP, get_istream_offset(ctx), 0, WASM_FALSE);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_if_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_IF]);
-
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_UNLESS));
- adjust_value_stack(ctx, -1);
- uint32_t fixup_offset = get_istream_offset(ctx);
- CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
-
- push_emit_label(ctx, LABEL_TYPE_IF, WASM_INVALID_OFFSET, fixup_offset,
- !is_expr_discarded(ctx, ctx->expr_count));
-
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_else_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_ELSE]);
- EmitLabel* label = top_emit_label(ctx);
- assert(label->label_type == LABEL_TYPE_IF);
- label->label_type = LABEL_TYPE_ELSE;
- uint32_t fixup_cond_offset = label->fixup_offset;
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR));
- label->fixup_offset = get_istream_offset(ctx);
- CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
- CHECK_RESULT(emit_i32_at(ctx, fixup_cond_offset, get_istream_offset(ctx)));
- /* reset the value stack for the other branch arm */
- ctx->value_stack_size = label->value_stack_size;
- return WASM_OK;
-}
-
-static WasmResult on_emit_end_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_END]);
- EmitLabel* label = top_emit_label(ctx);
- switch (label->label_type) {
- case LABEL_TYPE_LOOP:
- break;
-
- case LABEL_TYPE_IF:
- case LABEL_TYPE_ELSE: {
- uint32_t fixup_true_offset = label->fixup_offset;
- CHECK_RESULT(
- emit_i32_at(ctx, fixup_true_offset, get_istream_offset(ctx)));
- break;
- }
-
- default:
- break;
- }
- fixup_top_emit_label(ctx, get_istream_offset(ctx));
- ctx->value_stack_size = label->value_stack_size;
- adjust_value_stack(ctx, label->has_value ? 1 : 0);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- pop_emit_label(ctx);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_br_expr(uint8_t arity,
- uint32_t depth,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_BR]);
- CHECK_RESULT(emit_br(ctx, translate_emit_depth(ctx, depth)));
- adjust_value_stack_for_nonlocal_continuation(ctx);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_br_if_expr(uint8_t arity,
- uint32_t depth,
- void* user_data) {
- /* flip the br_if so if <cond> is true it can discard values from the stack */
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_BR_IF]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_UNLESS));
- adjust_value_stack(ctx, -1); /* account for br_unless consuming <cond> */
- uint32_t fixup_br_offset = get_istream_offset(ctx);
- CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
- CHECK_RESULT(emit_br(ctx, translate_emit_depth(ctx, depth)));
- CHECK_RESULT(emit_i32_at(ctx, fixup_br_offset, get_istream_offset(ctx)));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_br_table_expr(uint8_t arity,
- uint32_t num_targets,
- uint32_t* target_depths,
- uint32_t default_target_depth,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_BR_TABLE]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_TABLE));
- CHECK_RESULT(emit_i32(ctx, num_targets));
- uint32_t fixup_table_offset = get_istream_offset(ctx);
- CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
- adjust_value_stack(ctx, -1);
-
- /* not necessary for the interpreter, but it makes it easier to disassemble.
- * This opcode specifies how many bytes of data follow. */
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_DATA));
- CHECK_RESULT(emit_i32(ctx, (num_targets + 1) * WASM_TABLE_ENTRY_SIZE));
- CHECK_RESULT(emit_i32_at(ctx, fixup_table_offset, get_istream_offset(ctx)));
-
- /* write the branch table as (offset, discard count) pairs */
- uint32_t i;
- for (i = 0; i <= num_targets; ++i) {
- uint32_t depth = i != num_targets ? target_depths[i] : default_target_depth;
- CHECK_RESULT(emit_br_table_offset(ctx, translate_emit_depth(ctx, depth)));
- }
-
- adjust_value_stack_for_nonlocal_continuation(ctx);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_call_expr(uint32_t func_index, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_CALL_FUNCTION]);
- InterpreterFunc* func = get_func(ctx, func_index);
- WasmInterpreterFuncSignature* sig = get_func_signature(ctx, func);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_FUNCTION));
- CHECK_RESULT(emit_func_offset(ctx, func, func_index));
- adjust_value_stack(ctx,
- get_value_count(sig->result_type) - sig->param_types.size);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_call_import_expr(uint32_t import_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_CALL_IMPORT]);
- WasmInterpreterImport* import = get_import(ctx, import_index);
- WasmInterpreterFuncSignature* sig = get_signature(ctx, import->sig_index);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_IMPORT));
- CHECK_RESULT(emit_i32(ctx, import_index));
- adjust_value_stack(ctx,
- get_value_count(sig->result_type) - sig->param_types.size);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_call_indirect_expr(uint32_t sig_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_CALL_INDIRECT]);
- WasmInterpreterFuncSignature* sig = get_signature(ctx, sig_index);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CALL_INDIRECT));
- CHECK_RESULT(emit_i32(ctx, sig_index));
- adjust_value_stack(ctx,
- get_value_count(sig->result_type) - sig->param_types.size);
- adjust_value_stack(ctx, -1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_drop_expr(void *user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_DROP]);
- CHECK_RESULT(emit_discard(ctx));
- return WASM_OK;
-}
-
-static WasmResult on_emit_i32_const_expr(uint32_t value, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_I32_CONST]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_I32_CONST));
- CHECK_RESULT(emit_i32(ctx, value));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_i64_const_expr(uint64_t value, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_I64_CONST]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_I64_CONST));
- CHECK_RESULT(emit_i64(ctx, value));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_f32_const_expr(uint32_t value_bits, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_F32_CONST]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_F32_CONST));
- CHECK_RESULT(emit_i32(ctx, value_bits));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_f64_const_expr(uint64_t value_bits, void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_F64_CONST]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_F64_CONST));
- CHECK_RESULT(emit_i64(ctx, value_bits));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_get_global_expr(uint32_t global_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_GET_GLOBAL]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GET_GLOBAL));
- CHECK_RESULT(emit_i32(ctx, global_index));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_get_local_expr(uint32_t local_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_GET_LOCAL]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GET_LOCAL));
- CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_set_global_expr(uint32_t global_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_SET_GLOBAL]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_SET_GLOBAL));
- CHECK_RESULT(emit_i32(ctx, global_index));
- adjust_value_stack(ctx, -1);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_set_local_expr(uint32_t local_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_SET_LOCAL]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_SET_LOCAL));
- CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
- adjust_value_stack(ctx, -1);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_tee_local_expr(uint32_t local_index,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_TEE_LOCAL]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_TEE_LOCAL));
- CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_grow_memory_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_GROW_MEMORY]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_GROW_MEMORY));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_load_expr(WasmOpcode opcode,
- uint32_t alignment_log2,
- uint32_t offset,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size, s_opcode_name[opcode]);
- CHECK_RESULT(emit_opcode(ctx, opcode));
- CHECK_RESULT(emit_i32(ctx, offset));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_store_expr(WasmOpcode opcode,
- uint32_t alignment_log2,
- uint32_t offset,
- void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size, s_opcode_name[opcode]);
- CHECK_RESULT(emit_opcode(ctx, opcode));
- CHECK_RESULT(emit_i32(ctx, offset));
- adjust_value_stack(ctx, -1);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_current_memory_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_CURRENT_MEMORY]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_CURRENT_MEMORY));
- adjust_value_stack(ctx, 1);
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_nop_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_NOP]);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_return_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_RETURN]);
- WasmInterpreterFuncSignature* sig =
- get_func_signature(ctx, ctx->current_func);
- CHECK_RESULT(emit_return(ctx, sig->result_type));
- adjust_value_stack_for_nonlocal_continuation(ctx);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_select_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_SELECT]);
- CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_SELECT));
- CHECK_RESULT(maybe_emit_discard(ctx, ctx->expr_count));
- adjust_value_stack(ctx, -2);
- ctx->expr_count++;
- return WASM_OK;
-}
-
-static WasmResult on_emit_unreachable_expr(void* user_data) {
- Context* ctx = user_data;
- LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
- s_opcode_name[WASM_OPCODE_UNREACHABLE]);
+ LOGF("%3" PRIzd ": unreachable\n", ctx->expr_stack.size);
CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_UNREACHABLE));
- adjust_value_stack_for_nonlocal_continuation(ctx);
- ctx->expr_count++;
+ push_expr(ctx, WASM_TYPE_ANY, WASM_OPCODE_UNREACHABLE);
return WASM_OK;
}
@@ -1872,8 +1293,8 @@ static WasmBinaryReader s_binary_reader = {
.on_start_function = on_start_function,
.on_function_bodies_count = on_function_bodies_count,
- .begin_function_body_pass = begin_function_body_pass,
.begin_function_body = begin_function_body,
+ .on_local_decl_count = on_local_decl_count,
.on_local_decl = on_local_decl,
.on_binary_expr = on_binary_expr,
.on_block_expr = on_block_expr,
@@ -1910,7 +1331,6 @@ static WasmBinaryReader s_binary_reader = {
.on_unreachable_expr = on_unreachable_expr,
.end_function_body = end_function_body,
.end_function_bodies_section = end_function_bodies_section,
- .end_function_body_pass = end_function_body_pass,
.end_elem_segment_init_expr = end_elem_segment_init_expr,
.on_elem_segment_function_index = on_elem_segment_function_index,
@@ -1924,82 +1344,14 @@ static WasmBinaryReader s_binary_reader = {
.on_init_expr_i64_const_expr = on_init_expr_i64_const_expr,
};
-static WasmBinaryReader s_binary_reader_emit = {
- .on_error = on_error,
- .begin_function_body_pass = begin_function_body_pass,
- .begin_function_body = begin_emit_function_body,
- .on_local_decl_count = on_emit_local_decl_count,
- .on_local_decl = on_emit_local_decl,
- .on_binary_expr = on_emit_binary_expr,
- .on_block_expr = on_emit_block_expr,
- .on_br_expr = on_emit_br_expr,
- .on_br_if_expr = on_emit_br_if_expr,
- .on_br_table_expr = on_emit_br_table_expr,
- .on_call_expr = on_emit_call_expr,
- .on_call_import_expr = on_emit_call_import_expr,
- .on_call_indirect_expr = on_emit_call_indirect_expr,
- .on_compare_expr = on_emit_binary_expr,
- .on_convert_expr = on_emit_unary_expr,
- .on_current_memory_expr = on_emit_current_memory_expr,
- .on_drop_expr = on_emit_drop_expr,
- .on_else_expr = on_emit_else_expr,
- .on_end_expr = on_emit_end_expr,
- .on_f32_const_expr = on_emit_f32_const_expr,
- .on_f64_const_expr = on_emit_f64_const_expr,
- .on_get_global_expr = on_emit_get_global_expr,
- .on_get_local_expr = on_emit_get_local_expr,
- .on_grow_memory_expr = on_emit_grow_memory_expr,
- .on_i32_const_expr = on_emit_i32_const_expr,
- .on_i64_const_expr = on_emit_i64_const_expr,
- .on_if_expr = on_emit_if_expr,
- .on_load_expr = on_emit_load_expr,
- .on_loop_expr = on_emit_loop_expr,
- .on_nop_expr = on_emit_nop_expr,
- .on_return_expr = on_emit_return_expr,
- .on_select_expr = on_emit_select_expr,
- .on_set_global_expr = on_emit_set_global_expr,
- .on_set_local_expr = on_emit_set_local_expr,
- .on_store_expr = on_emit_store_expr,
- .on_tee_local_expr = on_emit_tee_local_expr,
- .on_unary_expr = on_emit_unary_expr,
- .on_unreachable_expr = on_emit_unreachable_expr,
- .end_function_body = end_emit_function_body,
- .end_function_body_pass = end_function_body_pass,
-};
-
-static WasmResult begin_function_body_pass(uint32_t index,
- uint32_t pass,
- void* user_data) {
- LOGF("*** func %d pass %d ***\n", index, pass);
- Context* ctx = user_data;
- assert(pass < 2);
- *ctx->reader = pass == 0 ? s_binary_reader : s_binary_reader_emit;
- ctx->reader->user_data = user_data;
- return WASM_OK;
-}
-
-static WasmResult end_function_body_pass(uint32_t index,
- uint32_t pass,
- void* user_data) {
- Context* ctx = user_data;
- /* reset the reader to its original callbacks */
- if (pass == 1)
- *ctx->reader = s_binary_reader;
- ctx->reader->user_data = user_data;
- return WASM_OK;
-}
-
static void wasm_destroy_interpreter_func(WasmAllocator* allocator,
InterpreterFunc* func) {
wasm_destroy_type_vector(allocator, &func->param_and_local_types);
}
static void destroy_context(Context* ctx) {
- wasm_destroy_uint32_vector(ctx->allocator, &ctx->discarded_exprs);
- wasm_destroy_expr_node_vector(ctx->allocator, &ctx->expr_stack);
- wasm_destroy_emit_label_vector(ctx->allocator, &ctx->emit_label_stack);
- wasm_destroy_typecheck_label_vector(ctx->allocator,
- &ctx->typecheck_label_stack);
+ wasm_destroy_type_vector(ctx->allocator, &ctx->expr_stack);
+ wasm_destroy_label_vector(ctx->allocator, &ctx->label_stack);
WASM_DESTROY_ARRAY_AND_ELEMENTS(ctx->allocator, ctx->funcs, interpreter_func);
WASM_DESTROY_VECTOR_AND_ELEMENTS(ctx->allocator, ctx->depth_fixups,
uint32_vector);
@@ -2032,7 +1384,7 @@ WasmResult wasm_read_binary_interpreter(WasmAllocator* allocator,
reader = s_binary_reader;
reader.user_data = &ctx;
- const uint32_t num_function_passes = 2;
+ const uint32_t num_function_passes = 1;
WasmResult result = wasm_read_binary(allocator, data, size, &reader,
num_function_passes, options);
if (WASM_SUCCEEDED(result)) {
diff --git a/src/wasm-interpreter.c b/src/wasm-interpreter.c
index 4a8813f5..393a37a8 100644
--- a/src/wasm-interpreter.c
+++ b/src/wasm-interpreter.c
@@ -28,8 +28,7 @@ static const char* s_opcode_name[] = {
[WASM_OPCODE_ALLOCA] = "alloca",
[WASM_OPCODE_BR_UNLESS] = "br_unless",
[WASM_OPCODE_DATA] = "data",
- [WASM_OPCODE_DISCARD] = "discard",
- [WASM_OPCODE_DISCARD_KEEP] = "discard_keep",
+ [WASM_OPCODE_DROP_KEEP] = "drop_keep",
};
#undef V
@@ -372,12 +371,12 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double)
#define POP_I64() (POP().i64)
#define POP_F32() (POP().f32_bits)
#define POP_F64() (POP().f64_bits)
-#define DISCARD_KEEP(discard, keep) \
- do { \
- assert((keep) <= 1); \
- if ((keep) == 1) \
- PICK((discard) + 1) = TOP(); \
- vs_top -= (discard); \
+#define DROP_KEEP(drop, keep) \
+ do { \
+ assert((keep) <= 1); \
+ if ((keep) == 1) \
+ PICK((drop) + 1) = TOP(); \
+ vs_top -= (drop); \
} while (0)
#define GOTO(offset) pc = &istream[offset]
@@ -587,10 +586,10 @@ static WASM_INLINE uint64_t read_u64(const uint8_t** pc) {
static WASM_INLINE void read_table_entry_at(const uint8_t* pc,
uint32_t* out_offset,
- uint32_t* out_discard,
+ uint32_t* out_drop,
uint8_t* out_keep) {
*out_offset = read_u32_at(pc + WASM_TABLE_ENTRY_OFFSET_OFFSET);
- *out_discard = read_u32_at(pc + WASM_TABLE_ENTRY_DISCARD_OFFSET);
+ *out_drop = read_u32_at(pc + WASM_TABLE_ENTRY_DROP_OFFSET);
*out_keep = *(pc + WASM_TABLE_ENTRY_KEEP_OFFSET);
}
@@ -657,10 +656,10 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
(key >= num_targets ? num_targets : key) * WASM_TABLE_ENTRY_SIZE;
const uint8_t* entry = istream + table_offset + key_offset;
uint32_t new_pc;
- uint32_t discard_count;
+ uint32_t drop_count;
uint8_t keep_count;
- read_table_entry_at(entry, &new_pc, &discard_count, &keep_count);
- DISCARD_KEEP(discard_count, keep_count);
+ read_table_entry_at(entry, &new_pc, &drop_count, &keep_count);
+ DROP_KEEP(drop_count, keep_count);
GOTO(new_pc);
break;
}
@@ -715,8 +714,7 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
case WASM_OPCODE_SET_LOCAL: {
WasmInterpreterValue value = POP();
- /* -1 because we just popped a value off the stack */
- PICK(read_u32(&pc) - 1) = value;
+ PICK(read_u32(&pc)) = value;
break;
}
@@ -1502,14 +1500,14 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module,
break;
}
- case WASM_OPCODE_DISCARD:
+ case WASM_OPCODE_DROP:
(void)POP();
break;
- case WASM_OPCODE_DISCARD_KEEP: {
- uint32_t discard_count = read_u32(&pc);
+ case WASM_OPCODE_DROP_KEEP: {
+ uint32_t drop_count = read_u32(&pc);
uint8_t keep_count = *pc++;
- DISCARD_KEEP(discard_count, keep_count);
+ DROP_KEEP(drop_count, keep_count);
break;
}
@@ -1575,7 +1573,7 @@ void wasm_trace_pc(WasmInterpreterModule* module,
case WASM_OPCODE_RETURN:
case WASM_OPCODE_UNREACHABLE:
case WASM_OPCODE_CURRENT_MEMORY:
- case WASM_OPCODE_DISCARD:
+ case WASM_OPCODE_DROP:
wasm_writef(stream, "%s\n", s_opcode_name[opcode]);
break;
@@ -1845,7 +1843,7 @@ void wasm_trace_pc(WasmInterpreterModule* module,
read_u32_at(pc), TOP().i32);
break;
- case WASM_OPCODE_DISCARD_KEEP:
+ case WASM_OPCODE_DROP_KEEP:
wasm_writef(stream, "%s $%u $%u\n", s_opcode_name[opcode],
read_u32_at(pc), *(pc + 4));
break;
@@ -1905,7 +1903,7 @@ void wasm_disassemble_module(WasmInterpreterModule* module,
case WASM_OPCODE_RETURN:
case WASM_OPCODE_UNREACHABLE:
case WASM_OPCODE_CURRENT_MEMORY:
- case WASM_OPCODE_DISCARD:
+ case WASM_OPCODE_DROP:
wasm_writef(stream, "%s\n", s_opcode_name[opcode]);
break;
@@ -2120,11 +2118,10 @@ void wasm_disassemble_module(WasmInterpreterModule* module,
read_u32(&pc));
break;
- case WASM_OPCODE_DISCARD_KEEP: {
- uint32_t discard = read_u32(&pc);
+ case WASM_OPCODE_DROP_KEEP: {
+ uint32_t drop = read_u32(&pc);
uint32_t keep = *pc++;
- wasm_writef(stream, "%s $%u $%u\n", s_opcode_name[opcode], discard,
- keep);
+ wasm_writef(stream, "%s $%u $%u\n", s_opcode_name[opcode], drop, keep);
break;
}
@@ -2139,11 +2136,11 @@ void wasm_disassemble_module(WasmInterpreterModule* module,
for (i = 0; i < num_entries; ++i) {
wasm_writef(stream, "%4" PRIzd "| ", pc - istream);
uint32_t offset;
- uint32_t discard;
+ uint32_t drop;
uint8_t keep;
- read_table_entry_at(pc, &offset, &discard, &keep);
- wasm_writef(stream, " entry %d: offset: %u discard: %u keep: %u\n",
- i, offset, discard, keep);
+ read_table_entry_at(pc, &offset, &drop, &keep);
+ wasm_writef(stream, " entry %d: offset: %u drop: %u keep: %u\n", i,
+ offset, drop, keep);
pc += WASM_TABLE_ENTRY_SIZE;
}
} else {
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index df643718..b0b733d5 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -67,7 +67,7 @@ typedef enum WasmInterpreterResult {
#define WASM_INVALID_OFFSET ((uint32_t)~0)
#define WASM_TABLE_ENTRY_SIZE (sizeof(uint32_t) * 2 + sizeof(uint8_t))
#define WASM_TABLE_ENTRY_OFFSET_OFFSET 0
-#define WASM_TABLE_ENTRY_DISCARD_OFFSET sizeof(uint32_t)
+#define WASM_TABLE_ENTRY_DROP_OFFSET sizeof(uint32_t)
#define WASM_TABLE_ENTRY_KEEP_OFFSET (sizeof(uint32_t) * 2)
enum {
@@ -75,8 +75,7 @@ enum {
WASM_OPCODE_ALLOCA = WASM_LAST_OPCODE,
WASM_OPCODE_BR_UNLESS,
WASM_OPCODE_DATA,
- WASM_OPCODE_DISCARD,
- WASM_OPCODE_DISCARD_KEEP,
+ WASM_OPCODE_DROP_KEEP,
WASM_LAST_INTERPRETER_OPCODE,
};
WASM_STATIC_ASSERT(WASM_LAST_INTERPRETER_OPCODE <= 256);