summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm-ast-checker.c9
-rw-r--r--src/wasm-ast-writer.c1
-rw-r--r--src/wasm-binary-reader-ast.c9
-rw-r--r--src/wasm-binary-reader-interpreter.c49
-rw-r--r--src/wasm-binary-writer.c4
-rw-r--r--src/wasm-common.c7
-rw-r--r--src/wasm-common.h1
7 files changed, 61 insertions, 19 deletions
diff --git a/src/wasm-ast-checker.c b/src/wasm-ast-checker.c
index 70381331..9729e05a 100644
--- a/src/wasm-ast-checker.c
+++ b/src/wasm-ast-checker.c
@@ -740,8 +740,15 @@ static void check_func(Context* ctx,
check_duplicate_bindings(ctx, &func->param_bindings, "parameter");
check_duplicate_bindings(ctx, &func->local_bindings, "local");
- check_expr_list(ctx, &func->loc, func->first_expr, wasm_get_result_type(func),
+ WasmType result_type = wasm_get_result_type(func);
+ /* The function has an implicit label; branching to it is equivalent to the
+ * returning from the function. */
+ LabelNode node;
+ WasmLabel label = wasm_empty_string_slice();
+ push_label(ctx, &func->loc, &node, &label, result_type, "func");
+ check_expr_list(ctx, &func->loc, func->first_expr, result_type,
" of function result");
+ pop_label(ctx);
ctx->current_func = NULL;
}
diff --git a/src/wasm-ast-writer.c b/src/wasm-ast-writer.c
index 79409e5b..ff0a1d93 100644
--- a/src/wasm-ast-writer.c
+++ b/src/wasm-ast-writer.c
@@ -599,6 +599,7 @@ static void write_func(Context* ctx,
&func->local_bindings);
}
write_newline(ctx, NO_FORCE_NEWLINE);
+ ctx->depth = 1; /* for the implicit "return" label */
write_expr_list(ctx, func->first_expr);
write_close_newline(ctx);
}
diff --git a/src/wasm-binary-reader-ast.c b/src/wasm-binary-reader-ast.c
index 97e3fd5b..b29c06e8 100644
--- a/src/wasm-binary-reader-ast.c
+++ b/src/wasm-binary-reader-ast.c
@@ -68,13 +68,15 @@ static const char* s_opcode_name[] = {WASM_FOREACH_OPCODE(V)};
#endif
typedef enum LabelType {
+ LABEL_TYPE_FUNC,
LABEL_TYPE_BLOCK,
LABEL_TYPE_IF,
LABEL_TYPE_ELSE,
LABEL_TYPE_LOOP,
} LabelType;
-static const char* s_label_type_name[] = {"block", "if", "else", "loop"};
+static const char* s_label_type_name[] = {"func", "block", "if", "else",
+ "loop"};
typedef struct LabelNode {
LabelType type;
@@ -421,12 +423,14 @@ static WasmResult begin_function_body(uint32_t index, void* user_data) {
ctx->current_func = ctx->module->funcs.data[index];
ctx->expr_stack_size = 0;
LOGF("func %d\n", index);
+ push_label(ctx, LABEL_TYPE_FUNC, NULL);
return WASM_OK;
}
static WasmResult end_function_body(uint32_t index, void* user_data) {
Context* ctx = user_data;
pop_into_expr_list(ctx, NULL, &ctx->current_func->first_expr);
+ CHECK_RESULT(pop_label(ctx));
ctx->current_func = NULL;
return WASM_OK;
}
@@ -1092,7 +1096,8 @@ static WasmBinaryReader s_binary_reader = {
};
static void wasm_destroy_label_node(WasmAllocator* allocator, LabelNode* node) {
- wasm_destroy_expr(allocator, node->expr);
+ if (node->expr)
+ wasm_destroy_expr(allocator, node->expr);
}
WasmResult wasm_read_binary_ast(struct WasmAllocator* allocator,
diff --git a/src/wasm-binary-reader-interpreter.c b/src/wasm-binary-reader-interpreter.c
index db710055..19d12e28 100644
--- a/src/wasm-binary-reader-interpreter.c
+++ b/src/wasm-binary-reader-interpreter.c
@@ -100,6 +100,7 @@ WASM_DEFINE_VECTOR(uint32, Uint32);
WASM_DEFINE_VECTOR(uint32_vector, Uint32Vector);
typedef enum LabelType {
+ LABEL_TYPE_FUNC,
LABEL_TYPE_BLOCK,
LABEL_TYPE_LOOP,
LABEL_TYPE_IF,
@@ -107,7 +108,7 @@ typedef enum LabelType {
} LabelType;
static const char* s_label_type_name[] = {
- "block", "loop", "if", "else",
+ "func", "block", "loop", "if", "else",
};
/* used for the typecheck pass */
@@ -524,6 +525,9 @@ static WasmResult begin_function_body(uint32_t index, void* user_data) {
&sig->param_types.data[i]);
}
+ /* push implicit func label (equivalent to return) */
+ push_typecheck_label(ctx, LABEL_TYPE_FUNC, sig->result_type);
+
return WASM_OK;
}
@@ -531,6 +535,8 @@ 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) {
@@ -1012,11 +1018,11 @@ static uint32_t translate_emit_depth(Context* ctx, uint32_t depth) {
return translate_depth(ctx, ctx->emit_label_stack.size, depth);
}
-static WasmResult push_emit_label(Context* ctx,
- LabelType label_type,
- uint32_t offset,
- uint32_t fixup_offset,
- WasmBool has_value) {
+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;
@@ -1025,7 +1031,6 @@ static WasmResult push_emit_label(Context* ctx,
label->has_value = has_value;
label->fixup_offset = fixup_offset;
LOGF(" : +depth %" PRIzd "\n", ctx->emit_label_stack.size - 1);
- return WASM_OK;
}
static void pop_emit_label(Context* ctx) {
@@ -1177,6 +1182,9 @@ static WasmResult begin_emit_function_body(uint32_t index, void* user_data) {
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;
}
@@ -1184,7 +1192,12 @@ 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;
@@ -1211,6 +1224,12 @@ static WasmResult on_emit_local_decl(uint32_t decl_index,
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;
}
@@ -1238,8 +1257,8 @@ 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]);
- CHECK_RESULT(push_emit_label(ctx, LABEL_TYPE_BLOCK, WASM_INVALID_OFFSET, 0,
- !is_expr_discarded(ctx, ctx->expr_count)));
+ push_emit_label(ctx, LABEL_TYPE_BLOCK, WASM_INVALID_OFFSET, 0,
+ !is_expr_discarded(ctx, ctx->expr_count));
ctx->expr_count++;
return WASM_OK;
}
@@ -1249,10 +1268,9 @@ static WasmResult on_emit_loop_expr(void* user_data) {
LOGF("%3" PRIzd ": %s\n", ctx->value_stack_size,
s_opcode_name[WASM_OPCODE_LOOP]);
- CHECK_RESULT(push_emit_label(ctx, LABEL_TYPE_LOOP, WASM_INVALID_OFFSET, 0,
- !is_expr_discarded(ctx, ctx->expr_count)));
- CHECK_RESULT(push_emit_label(ctx, LABEL_TYPE_LOOP, get_istream_offset(ctx), 0,
- WASM_FALSE));
+ push_emit_label(ctx, LABEL_TYPE_LOOP, WASM_INVALID_OFFSET, 0,
+ !is_expr_discarded(ctx, ctx->expr_count));
+ push_emit_label(ctx, LABEL_TYPE_LOOP, get_istream_offset(ctx), 0, WASM_FALSE);
ctx->expr_count++;
return WASM_OK;
@@ -1268,9 +1286,8 @@ static WasmResult on_emit_if_expr(void* user_data) {
uint32_t fixup_offset = get_istream_offset(ctx);
CHECK_RESULT(emit_i32(ctx, WASM_INVALID_OFFSET));
- CHECK_RESULT(push_emit_label(ctx, LABEL_TYPE_IF, WASM_INVALID_OFFSET,
- fixup_offset,
- !is_expr_discarded(ctx, ctx->expr_count)));
+ 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;
diff --git a/src/wasm-binary-writer.c b/src/wasm-binary-writer.c
index f7f58b56..385c773a 100644
--- a/src/wasm-binary-writer.c
+++ b/src/wasm-binary-writer.c
@@ -760,8 +760,12 @@ static void write_func_locals(WasmContext* ctx,
static void write_func(WasmContext* ctx,
const WasmModule* module,
const WasmFunc* func) {
+ WasmLabelNode node;
+ WasmLabel label = wasm_empty_string_slice();
write_func_locals(ctx, module, func, &func->local_types);
+ push_label(ctx, &node, &label);
write_expr_list(ctx, module, func, func->first_expr);
+ pop_label(ctx, &label);
}
static void write_module(WasmContext* ctx, const WasmModule* module) {
diff --git a/src/wasm-common.c b/src/wasm-common.c
index 4341ee8e..c471eb55 100644
--- a/src/wasm-common.c
+++ b/src/wasm-common.c
@@ -46,6 +46,13 @@ uint32_t wasm_get_opcode_alignment(WasmOpcode opcode, uint32_t alignment) {
return alignment;
}
+WasmStringSlice wasm_empty_string_slice(void) {
+ WasmStringSlice result;
+ result.start = "";
+ result.length = 0;
+ return result;
+}
+
WasmBool wasm_string_slices_are_equal(const WasmStringSlice* a,
const WasmStringSlice* b) {
return a->start && b->start && a->length == b->length &&
diff --git a/src/wasm-common.h b/src/wasm-common.h
index 4d984c3a..2655e5bf 100644
--- a/src/wasm-common.h
+++ b/src/wasm-common.h
@@ -346,6 +346,7 @@ WasmBool wasm_is_naturally_aligned(WasmOpcode opcode, uint32_t alignment);
* |opcode|, else return |alignment| */
uint32_t wasm_get_opcode_alignment(WasmOpcode opcode, uint32_t alignment);
+WasmStringSlice wasm_empty_string_slice(void);
WasmBool wasm_string_slices_are_equal(const WasmStringSlice*,
const WasmStringSlice*);
void wasm_destroy_string_slice(struct WasmAllocator*, WasmStringSlice*);