diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-ast-checker.c | 9 | ||||
-rw-r--r-- | src/wasm-ast-writer.c | 1 | ||||
-rw-r--r-- | src/wasm-binary-reader-ast.c | 9 | ||||
-rw-r--r-- | src/wasm-binary-reader-interpreter.c | 49 | ||||
-rw-r--r-- | src/wasm-binary-writer.c | 4 | ||||
-rw-r--r-- | src/wasm-common.c | 7 | ||||
-rw-r--r-- | src/wasm-common.h | 1 |
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*); |