diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-ast-checker.c | 124 | ||||
-rw-r--r-- | src/wasm-ast-parser-lexer-shared.c | 5 | ||||
-rw-r--r-- | src/wasm-ast-parser-lexer-shared.h | 7 | ||||
-rw-r--r-- | src/wasm-ast-parser.y | 31 | ||||
-rw-r--r-- | src/wasm-binary-reader-interpreter.c | 146 | ||||
-rw-r--r-- | src/wasm-common.h | 3 | ||||
-rw-r--r-- | src/wasm-interpreter.c | 15 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 5 |
8 files changed, 194 insertions, 142 deletions
diff --git a/src/wasm-ast-checker.c b/src/wasm-ast-checker.c index e6f25c9d..658c2010 100644 --- a/src/wasm-ast-checker.c +++ b/src/wasm-ast-checker.c @@ -179,7 +179,8 @@ static WasmResult check_func_var(Context* ctx, static WasmResult check_global_var(Context* ctx, const WasmVar* var, - const WasmGlobal** out_global) { + const WasmGlobal** out_global, + int* out_global_index) { int index; if (WASM_FAILED(check_var(ctx, &ctx->current_module->global_bindings, ctx->current_module->globals.size, var, "global", @@ -189,6 +190,8 @@ static WasmResult check_global_var(Context* ctx, if (out_global) *out_global = ctx->current_module->globals.data[index]; + if (out_global_index) + *out_global_index = index; return WASM_OK; } @@ -683,7 +686,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) { } case WASM_EXPR_TYPE_DROP: { - WasmType type = top_type(ctx); + WasmCheckType type = top_type(ctx); transform_stack(ctx, &expr->loc, "drop", 1, 0, type); break; } @@ -691,7 +694,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) { case WASM_EXPR_TYPE_GET_GLOBAL: { const WasmGlobal* global; if (WASM_SUCCEEDED( - check_global_var(ctx, &expr->get_global.var, &global))) { + check_global_var(ctx, &expr->get_global.var, &global, NULL))) { push_type(ctx, global->type); } break; @@ -804,7 +807,7 @@ static void check_expr(Context* ctx, const WasmExpr* expr) { WasmCheckType type = WASM_TYPE_I32; const WasmGlobal* global; if (WASM_SUCCEEDED( - check_global_var(ctx, &expr->set_global.var, &global))) { + check_global_var(ctx, &expr->set_global.var, &global, NULL))) { type = global->type; } transform_stack(ctx, &expr->loc, "set_global", 1, 0, type); @@ -885,6 +888,10 @@ static void check_func(Context* ctx, const WasmLocation* loc, const WasmFunc* func) { ctx->current_func = func; + if (wasm_get_result_type(ctx->current_module, func) == WASM_TYPE_MULTIPLE) { + print_error(ctx, CHECK_STYLE_FULL, loc, + "multiple result values not currently supported."); + } if (wasm_decl_has_func_type(&func->decl)) { const WasmFuncType* func_type; if (WASM_SUCCEEDED( @@ -909,44 +916,15 @@ static void check_func(Context* ctx, ctx->current_func = NULL; } -static WasmResult check_const_expr(Context* ctx, - const WasmExpr* expr, - const char* desc, - WasmCheckType* out_type) { - if (expr->next == NULL) { - switch (expr->type) { - case WASM_EXPR_TYPE_CONST: - if (out_type) - *out_type = expr->const_.type; - return WASM_OK; - - case WASM_EXPR_TYPE_GET_GLOBAL: { - const WasmGlobal* ref_global = NULL; - if (WASM_SUCCEEDED( - check_global_var(ctx, &expr->get_global.var, &ref_global))) { - if (out_type) - *out_type = ref_global->type; - return WASM_OK; - } - return WASM_ERROR; - } - - default: - break; - } - } - - print_error(ctx, CHECK_STYLE_FULL, &expr->loc, - "invalid %s, must be a constant expression; either *.const or " - "get_global.", - desc); - return WASM_ERROR; -} - static WasmResult eval_const_expr_i32(Context* ctx, const WasmExpr* expr, const char* desc, uint32_t* out_value) { + if (expr->next != NULL) { + expr = expr->next; + goto invalid_expr; + } + switch (expr->type) { case WASM_EXPR_TYPE_CONST: if (expr->const_.type != WASM_TYPE_I32) { @@ -960,7 +938,8 @@ static WasmResult eval_const_expr_i32(Context* ctx, case WASM_EXPR_TYPE_GET_GLOBAL: { const WasmGlobal* global = NULL; - if (WASM_FAILED(check_global_var(ctx, &expr->get_global.var, &global))) + if (WASM_FAILED( + check_global_var(ctx, &expr->get_global.var, &global, NULL))) return WASM_ERROR; if (global->type != WASM_TYPE_I32) { @@ -974,6 +953,7 @@ static WasmResult eval_const_expr_i32(Context* ctx, return eval_const_expr_i32(ctx, global->init_expr, desc, out_value); } + invalid_expr: default: print_error( ctx, CHECK_STYLE_FULL, &expr->loc, @@ -986,11 +966,48 @@ static WasmResult eval_const_expr_i32(Context* ctx, static void check_global(Context* ctx, const WasmLocation* loc, - const WasmGlobal* global) { - WasmCheckType type; - if (WASM_SUCCEEDED(check_const_expr( - ctx, global->init_expr, "global initializer expression", &type))) { - check_type(ctx, loc, type, global->type, "global initializer expression"); + const WasmGlobal* global, + int global_index) { + WasmCheckType type = WASM_CHECK_TYPE_VOID; + WasmBool invalid_expr = WASM_TRUE; + WasmExpr* expr = global->init_expr; + + if (expr->next == NULL) { + switch (expr->type) { + case WASM_EXPR_TYPE_CONST: + type = expr->const_.type; + invalid_expr = WASM_FALSE; + break; + + case WASM_EXPR_TYPE_GET_GLOBAL: { + const WasmGlobal* ref_global = NULL; + int ref_global_index; + if (WASM_SUCCEEDED(check_global_var(ctx, &expr->get_global.var, + &ref_global, &ref_global_index))) { + type = ref_global->type; + /* globals can only reference previously defined globals */ + if (ref_global_index >= global_index) { + print_error(ctx, CHECK_STYLE_FULL, loc, + "global can only be defined in terms of a previously " + "defined global."); + } + } + invalid_expr = WASM_FALSE; + break; + } + + default: + break; + } + } + + if (invalid_expr) { + print_error(ctx, CHECK_STYLE_FULL, loc, + "invalid global initializer expression. Must be *.const or " + "get_global."); + } else { + check_type(ctx, &expr->loc, type, global->type, + "global initializer expression"); } } @@ -1046,6 +1063,12 @@ static void check_elem_segments(Context* ctx, const WasmModule* module) { if (field->type != WASM_MODULE_FIELD_TYPE_ELEM_SEGMENT) continue; + if (!table) { + print_error(ctx, CHECK_STYLE_FULL, &field->loc, + "elem segment cannot be specified without table section"); + break; + } + WasmElemSegment* elem_segment = &field->elem_segment; uint32_t offset = 0; if (WASM_SUCCEEDED(eval_const_expr_i32( @@ -1058,7 +1081,7 @@ static void check_elem_segments(Context* ctx, const WasmModule* module) { } uint64_t max = - table->elem_limits.has_max ? table->elem_limits.max : UINT32_MAX; + table->elem_limits.has_max ? table->elem_limits.initial : UINT32_MAX; if (offset + elem_segment->vars.size > max) { print_error(ctx, CHECK_STYLE_FULL, &field->loc, @@ -1086,6 +1109,12 @@ static void check_data_segments(Context* ctx, const WasmModule* module) { if (field->type != WASM_MODULE_FIELD_TYPE_DATA_SEGMENT) continue; + if (!memory) { + print_error(ctx, CHECK_STYLE_FULL, &field->loc, + "data segment cannot be specified without memory section"); + break; + } + WasmDataSegment* data_segment = &field->data_segment; uint32_t offset = 0; if (WASM_SUCCEEDED(eval_const_expr_i32( @@ -1097,7 +1126,7 @@ static void check_data_segments(Context* ctx, const WasmModule* module) { offset, last_end); } - uint32_t max = memory->page_limits.has_max ? memory->page_limits.max + uint32_t max = memory->page_limits.has_max ? memory->page_limits.initial : WASM_MAX_PAGES; const uint64_t memory_max_size = max * WASM_PAGE_SIZE; if (offset + data_segment->size > memory_max_size) { @@ -1118,6 +1147,7 @@ static void check_module(Context* ctx, const WasmModule* module) { WasmBool seen_export_memory = WASM_FALSE; WasmBool seen_table = WASM_FALSE; WasmBool seen_start = WASM_FALSE; + int global_index = 0; ctx->current_module = module; @@ -1129,7 +1159,7 @@ static void check_module(Context* ctx, const WasmModule* module) { break; case WASM_MODULE_FIELD_TYPE_GLOBAL: - check_global(ctx, &field->loc, &field->global); + check_global(ctx, &field->loc, &field->global, global_index++); break; case WASM_MODULE_FIELD_TYPE_IMPORT: diff --git a/src/wasm-ast-parser-lexer-shared.c b/src/wasm-ast-parser-lexer-shared.c index 2093624b..2ff81fd3 100644 --- a/src/wasm-ast-parser-lexer-shared.c +++ b/src/wasm-ast-parser-lexer-shared.c @@ -100,6 +100,7 @@ void wasm_destroy_func_fields(struct WasmAllocator* allocator, case WASM_FUNC_FIELD_TYPE_PARAM_TYPES: case WASM_FUNC_FIELD_TYPE_LOCAL_TYPES: + case WASM_FUNC_FIELD_TYPE_RESULT_TYPES: wasm_destroy_type_vector(allocator, &func_field->types); break; @@ -107,10 +108,6 @@ void wasm_destroy_func_fields(struct WasmAllocator* allocator, case WASM_FUNC_FIELD_TYPE_BOUND_LOCAL: wasm_destroy_string_slice(allocator, &func_field->bound_type.name); break; - - case WASM_FUNC_FIELD_TYPE_RESULT_TYPE: - /* nothing to free */ - break; } wasm_free(allocator, func_field); diff --git a/src/wasm-ast-parser-lexer-shared.h b/src/wasm-ast-parser-lexer-shared.h index bba39a54..f516d8fd 100644 --- a/src/wasm-ast-parser-lexer-shared.h +++ b/src/wasm-ast-parser-lexer-shared.h @@ -69,7 +69,7 @@ typedef enum WasmFuncFieldType { WASM_FUNC_FIELD_TYPE_EXPRS, WASM_FUNC_FIELD_TYPE_PARAM_TYPES, WASM_FUNC_FIELD_TYPE_BOUND_PARAM, - WASM_FUNC_FIELD_TYPE_RESULT_TYPE, + WASM_FUNC_FIELD_TYPE_RESULT_TYPES, WASM_FUNC_FIELD_TYPE_LOCAL_TYPES, WASM_FUNC_FIELD_TYPE_BOUND_LOCAL, } WasmFuncFieldType; @@ -83,10 +83,9 @@ typedef struct WasmBoundType { typedef struct WasmFuncField { WasmFuncFieldType type; union { - WasmExpr* first_expr; - WasmTypeVector types; /* WASM_FUNC_FIELD_TYPE_{PARAM,LOCAL}_TYPES */ + WasmExpr* first_expr; /* WASM_FUNC_FIELD_TYPE_EXPRS */ + WasmTypeVector types; /* WASM_FUNC_FIELD_TYPE_*_TYPES */ WasmBoundType bound_type; /* WASM_FUNC_FIELD_TYPE_BOUND_{LOCAL, PARAM} */ - WasmType result_type; }; struct WasmFuncField* next; } WasmFuncField; diff --git a/src/wasm-ast-parser.y b/src/wasm-ast-parser.y index 46d6bd24..a97ae6ba 100644 --- a/src/wasm-ast-parser.y +++ b/src/wasm-ast-parser.y @@ -116,6 +116,8 @@ static WasmBool is_empty_signature(WasmFuncSignature* sig); static void append_implicit_func_declaration(WasmAllocator*, WasmLocation*, WasmModule*, WasmFuncDeclaration*); +static WasmType get_result_type_from_type_vector(WasmTypeVector* types); + typedef struct BinaryErrorCallbackData { WasmLocation* loc; WasmAstLexer* lexer; @@ -263,11 +265,14 @@ func_type : $$.result_type = WASM_TYPE_VOID; $$.param_types = $3; } - | LPAR PARAM value_type_list RPAR LPAR RESULT VALUE_TYPE RPAR { - $$.result_type = $7; + | LPAR PARAM value_type_list RPAR LPAR RESULT value_type_list RPAR { $$.param_types = $3; + $$.result_type = get_result_type_from_type_vector(&$7); + } + | LPAR RESULT value_type_list RPAR { + WASM_ZERO_MEMORY($$); + $$.result_type = get_result_type_from_type_vector(&$3); } - | LPAR RESULT VALUE_TYPE RPAR { WASM_ZERO_MEMORY($$); $$.result_type = $3; } ; @@ -748,10 +753,10 @@ const_expr : /* Functions */ func_fields : func_body - | LPAR RESULT VALUE_TYPE RPAR func_body { + | LPAR RESULT value_type_list RPAR func_body { $$ = new_func_field(parser->allocator); - $$->type = WASM_FUNC_FIELD_TYPE_RESULT_TYPE; - $$->result_type = $3; + $$->type = WASM_FUNC_FIELD_TYPE_RESULT_TYPES; + $$->types = $3; $$->next = $5; } | LPAR PARAM value_type_list RPAR func_fields { @@ -838,8 +843,9 @@ func_info : break; } - case WASM_FUNC_FIELD_TYPE_RESULT_TYPE: - $$->decl.sig.result_type = field->result_type; + case WASM_FUNC_FIELD_TYPE_RESULT_TYPES: + $$->decl.sig.result_type = + get_result_type_from_type_vector(&field->types); break; } @@ -1607,6 +1613,15 @@ static void append_implicit_func_declaration(WasmAllocator* allocator, decl->flags |= WASM_FUNC_DECLARATION_FLAG_SHARED_SIGNATURE; } +static WasmType get_result_type_from_type_vector(WasmTypeVector* types) { + /* TODO(binji): handle multiple result types more cleanly */ + switch (types->size) { + case 0: return WASM_TYPE_VOID; break; + case 1: return types->data[0]; break; + default: return WASM_TYPE_MULTIPLE; break; + } +} + WasmResult wasm_parse_ast(WasmAstLexer* lexer, struct WasmScript* out_script, WasmSourceErrorHandler* error_handler) { diff --git a/src/wasm-binary-reader-interpreter.c b/src/wasm-binary-reader-interpreter.c index 661caa58..ce0e27c0 100644 --- a/src/wasm-binary-reader-interpreter.c +++ b/src/wasm-binary-reader-interpreter.c @@ -276,13 +276,12 @@ static WasmResult emit_drop_keep(Context* ctx, uint32_t drop, uint8_t keep) { return WASM_OK; } -static WasmResult emit_return(Context* ctx, WasmType result_type) { +static WasmResult drop_exprs_for_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; } @@ -455,6 +454,7 @@ static WasmResult on_memory_limits(WasmBool has_max, memory->allocator = ctx->memory_allocator; memory->page_size = initial_pages; memory->byte_size = initial_pages * WASM_PAGE_SIZE; + memory->max_page_size = has_max ? max_pages : WASM_MAX_PAGES; memory->data = wasm_alloc_zero(ctx->memory_allocator, memory->byte_size, WASM_DEFAULT_ALIGN); return WASM_OK; @@ -677,32 +677,28 @@ static void pop_label(Context* ctx) { } } -static void push_expr(Context* ctx, WasmType type, WasmOpcode opcode) { - /* TODO: refactor to remove opcode param */ - if (type != WASM_TYPE_VOID) { - 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); - } -} - 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]; } +static WasmBool top_expr_is_any(Context* ctx) { + 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 WASM_TRUE; + } + return WASM_FALSE; +} + 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--; + if (type != WASM_TYPE_ANY) { + LOGF("%3" PRIzd ": pop %s\n", ctx->expr_stack.size, s_type_names[type]); + ctx->expr_stack.size--; + } return type; } @@ -712,10 +708,29 @@ static WasmType top_expr_if(Context* ctx, WasmBool cond) { return WASM_TYPE_VOID; } -static WasmResult check_end(Context* ctx, WasmType* top_type) { +static void push_expr(Context* ctx, WasmType type, WasmOpcode opcode) { + /* TODO: refactor to remove opcode param */ + if (type != WASM_TYPE_VOID) { + if (top_expr_is_any(ctx)) + 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); + } +} + +static WasmResult check_end(Context* ctx, + WasmType* top_type, + size_t stack_size_adjustment) { 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; + /* the stack_size_adjustment is typically 0; it is non-zero when checking the + * implicit function label. The function label stack size does not include + * the parameters, so it will appear as though there are too many values on + * the stack if the stack size is not adjusted. */ + size_t label_stack_size = label->expr_stack_size + stack_size_adjustment; + assert(ctx->expr_stack.size >= label_stack_size); + size_t stack_size = ctx->expr_stack.size - label_stack_size; if (stack_size == 0) { *top_type = WASM_TYPE_VOID; return WASM_OK; @@ -741,10 +756,14 @@ static WasmResult begin_function_body(uint32_t index, void* user_data) { ctx->current_func = func; ctx->depth_fixups.size = 0; - ctx->expr_stack.size = sig->param_types.size; + ctx->expr_stack.size = 0; ctx->label_stack.size = 0; ctx->depth = 0; + /* push implicit func label (equivalent to return) */ + push_label(ctx, LABEL_TYPE_FUNC, sig->result_type, WASM_INVALID_OFFSET, + WASM_INVALID_OFFSET); + /* fixup function references */ uint32_t i; Uint32Vector* fixups = &ctx->func_fixups.data[index]; @@ -753,25 +772,33 @@ static WasmResult begin_function_body(uint32_t index, void* user_data) { /* 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]); + WasmType type = sig->param_types.data[i]; + wasm_append_type_value(ctx->allocator, &func->param_and_local_types, &type); + wasm_append_type_value(ctx->allocator, &ctx->expr_stack, &type); } - /* push implicit func label (equivalent to return) */ - 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; + Label* label = top_label(ctx); + if (!label || label->label_type != LABEL_TYPE_FUNC) { + print_error(ctx, "unexpected function end"); + return WASM_ERROR; + } + WasmInterpreterFuncSignature* sig = get_func_signature(ctx, ctx->current_func); 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)); + CHECK_RESULT(check_end(ctx, &top_type, sig->param_types.size)); + unify_type(&label->type, top_type); + CHECK_RESULT( + check_type(ctx, sig->result_type, label->type, "implicit return")); + CHECK_RESULT(drop_exprs_for_return(ctx, sig->result_type)); + fixup_top_label(ctx, get_istream_offset(ctx)); + CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_RETURN)); pop_label(ctx); ctx->current_func = NULL; ctx->expr_stack.size = 0; @@ -815,7 +842,6 @@ static WasmResult on_local_decl(uint32_t decl_index, 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, opcode_name)); CHECK_RESULT(emit_opcode(ctx, opcode)); @@ -826,7 +852,6 @@ static WasmResult on_unary_expr(WasmOpcode opcode, void* user_data) { 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); CHECK_RESULT(check_type(ctx, s_opcode_type1[opcode], left, opcode_name)); @@ -838,7 +863,6 @@ static WasmResult on_binary_expr(WasmOpcode opcode, void* user_data) { static WasmResult on_block_expr(void* user_data) { Context* ctx = user_data; - 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; @@ -846,7 +870,6 @@ static WasmResult on_block_expr(void* user_data) { static WasmResult on_loop_expr(void* user_data) { Context* ctx = user_data; - 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; @@ -854,7 +877,6 @@ static WasmResult on_loop_expr(void* user_data) { 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")); CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_BR_UNLESS)); @@ -867,7 +889,6 @@ static WasmResult on_if_expr(void* user_data) { static WasmResult on_else_expr(void* user_data) { Context* ctx = user_data; - 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"); @@ -875,7 +896,7 @@ static WasmResult on_else_expr(void* user_data) { } WasmType top_type; - CHECK_RESULT(check_end(ctx, &top_type)); + CHECK_RESULT(check_end(ctx, &top_type, 0)); CHECK_RESULT( unify_and_check_type(ctx, &label->type, top_type, "if true branch")); @@ -892,7 +913,6 @@ static WasmResult on_else_expr(void* user_data) { static WasmResult on_end_expr(void* user_data) { Context* ctx = user_data; - 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"); @@ -903,9 +923,12 @@ static WasmResult on_end_expr(void* user_data) { 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])); + CHECK_RESULT(check_end(ctx, &top_type, 0)); + if (label->label_type != LABEL_TYPE_LOOP) { + CHECK_RESULT(unify_and_check_type(ctx, &label->type, top_type, + s_label_type_name[label->label_type])); + top_type = label->type; + } if (label->label_type == LABEL_TYPE_IF || label->label_type == LABEL_TYPE_ELSE) { @@ -916,13 +939,12 @@ static WasmResult on_end_expr(void* user_data) { fixup_top_label(ctx, get_istream_offset(ctx)); ctx->expr_stack.size = label->expr_stack_size; pop_label(ctx); - push_expr(ctx, label->type, WASM_OPCODE_END); + push_expr(ctx, top_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; - LOGF("%3" PRIzd ": br\n", ctx->expr_stack.size); WasmType value = top_expr_if(ctx, arity > 0); CHECK_DEPTH(ctx, depth); depth = translate_depth(ctx, depth); @@ -937,7 +959,6 @@ 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 = top_expr_if(ctx, arity > 0); CHECK_DEPTH(ctx, depth); @@ -953,8 +974,10 @@ static WasmResult on_br_if_expr(uint8_t arity, 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); + /* don't pop the top expr from the stack if it is ANY; we want that to + * propagate through */ + if (!top_expr_is_any(ctx)) + ctx->expr_stack.size -= arity; return WASM_OK; } @@ -964,7 +987,6 @@ 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 = top_expr_if(ctx, arity > 0); CHECK_RESULT(check_type(ctx, WASM_TYPE_I32, key, "br_table")); @@ -994,7 +1016,6 @@ 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); @@ -1013,7 +1034,6 @@ static WasmResult on_call_expr(uint32_t func_index, void* user_data) { 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); @@ -1033,7 +1053,6 @@ static WasmResult on_call_import_expr(uint32_t import_index, void* user_data) { 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")); @@ -1053,7 +1072,6 @@ static WasmResult on_call_indirect_expr(uint32_t sig_index, void* user_data) { 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; @@ -1061,7 +1079,6 @@ static WasmResult on_drop_expr(void* user_data) { 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); @@ -1070,7 +1087,6 @@ static WasmResult on_i32_const_expr(uint32_t value, void* user_data) { 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); @@ -1079,7 +1095,6 @@ static WasmResult on_i64_const_expr(uint64_t value, void* user_data) { 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); @@ -1088,7 +1103,6 @@ static WasmResult on_f32_const_expr(uint32_t value_bits, void* user_data) { 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); @@ -1097,7 +1111,6 @@ static WasmResult on_f64_const_expr(uint64_t value_bits, void* user_data) { 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)); @@ -1108,7 +1121,6 @@ static WasmResult on_get_global_expr(uint32_t global_index, void* user_data) { 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); @@ -1120,7 +1132,6 @@ static WasmResult on_set_global_expr(uint32_t global_index, void* user_data) { 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)); @@ -1131,7 +1142,6 @@ static WasmResult on_get_local_expr(uint32_t local_index, void* user_data) { 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); @@ -1143,10 +1153,9 @@ static WasmResult on_set_local_expr(uint32_t local_index, void* user_data) { 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); + WasmType value = top_expr(ctx); CHECK_RESULT(check_type(ctx, type, value, "tee_local")); CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_TEE_LOCAL)); CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index))); @@ -1155,7 +1164,6 @@ static WasmResult on_tee_local_expr(uint32_t local_index, void* user_data) { 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)); @@ -1168,7 +1176,6 @@ 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)); @@ -1182,7 +1189,6 @@ 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]; @@ -1196,7 +1202,6 @@ static WasmResult on_store_expr(WasmOpcode opcode, 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; @@ -1205,27 +1210,25 @@ static WasmResult on_current_memory_expr(void* user_data) { static WasmResult on_nop_expr(void* user_data) { Context* ctx = user_data; 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 = top_expr(ctx); CHECK_RESULT(check_type(ctx, sig->result_type, value, "return")); } - CHECK_RESULT(emit_return(ctx, sig->result_type)); + CHECK_RESULT(drop_exprs_for_return(ctx, sig->result_type)); + CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_RETURN)); 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); @@ -1240,7 +1243,6 @@ static WasmResult on_select_expr(void* user_data) { static WasmResult on_unreachable_expr(void* user_data) { Context* ctx = user_data; - LOGF("%3" PRIzd ": unreachable\n", ctx->expr_stack.size); CHECK_RESULT(emit_opcode(ctx, WASM_OPCODE_UNREACHABLE)); push_expr(ctx, WASM_TYPE_ANY, WASM_OPCODE_UNREACHABLE); return WASM_OK; diff --git a/src/wasm-common.h b/src/wasm-common.h index 5807834e..744c8f6e 100644 --- a/src/wasm-common.h +++ b/src/wasm-common.h @@ -132,6 +132,9 @@ enum { WASM_TYPE_F64, WASM_NUM_TYPES, WASM_TYPE____ = WASM_TYPE_VOID, /* convenient for the opcode table below */ + /* used when parsing multiple return types to signify an error */ + /* TODO(binji): remove and support properly */ + WASM_TYPE_MULTIPLE = WASM_NUM_TYPES, }; typedef unsigned char WasmType; diff --git a/src/wasm-interpreter.c b/src/wasm-interpreter.c index 393a37a8..f6eab79e 100644 --- a/src/wasm-interpreter.c +++ b/src/wasm-interpreter.c @@ -347,6 +347,12 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) #define CHECK_STACK() TRAP_IF(vs_top >= vs_end, VALUE_STACK_EXHAUSTED) +#define PUSH_NEG_1_AND_BREAK_IF(cond) \ + if (WASM_UNLIKELY(cond)) { \ + PUSH_I32(-1); \ + break; \ + } + #define PUSH(v) \ do { \ CHECK_STACK(); \ @@ -874,13 +880,14 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module, uint32_t old_byte_size = module->memory.byte_size; VALUE_TYPE_I32 grow_pages = POP_I32(); uint32_t new_page_size = old_page_size + grow_pages; - TRAP_IF((uint64_t)new_page_size * WASM_PAGE_SIZE > UINT32_MAX, - MEMORY_SIZE_OVERFLOW); + PUSH_NEG_1_AND_BREAK_IF(new_page_size > module->memory.max_page_size); + PUSH_NEG_1_AND_BREAK_IF((uint64_t)new_page_size * WASM_PAGE_SIZE > + UINT32_MAX); uint32_t new_byte_size = new_page_size * WASM_PAGE_SIZE; WasmAllocator* allocator = module->memory.allocator; void* new_data = wasm_realloc(allocator, module->memory.data, new_byte_size, WASM_DEFAULT_ALIGN); - TRAP_IF(new_data == NULL, OUT_OF_MEMORY); + PUSH_NEG_1_AND_BREAK_IF(new_data == NULL); memset((void*)((intptr_t)new_data + old_byte_size), 0, new_byte_size - old_byte_size); module->memory.data = new_data; @@ -1601,6 +1608,7 @@ void wasm_trace_pc(WasmInterpreterModule* module, break; case WASM_OPCODE_SET_LOCAL: + case WASM_OPCODE_TEE_LOCAL: wasm_writef(stream, "%s $%u, %u\n", s_opcode_name[opcode], read_u32_at(pc), TOP().i32); break; @@ -1931,6 +1939,7 @@ void wasm_disassemble_module(WasmInterpreterModule* module, break; case WASM_OPCODE_SET_LOCAL: + case WASM_OPCODE_TEE_LOCAL: wasm_writef(stream, "%s $%u, %%[-1]\n", s_opcode_name[opcode], read_u32(&pc)); break; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index b0b733d5..8fc5f5c4 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -44,10 +44,6 @@ struct WasmStream; V(TRAP_UNREACHABLE, "unreachable executed") \ /* call indirect signature doesn't match function table signature */ \ V(TRAP_INDIRECT_CALL_SIGNATURE_MISMATCH, "indirect call signature mismatch") \ - /* growing the memory would overflow the memory size type */ \ - V(TRAP_MEMORY_SIZE_OVERFLOW, "memory size overflow") \ - /* out of memory */ \ - V(TRAP_OUT_OF_MEMORY, "memory size exceeds implementation limit") \ /* ran out of call stack frames (probably infinite recursion) */ \ V(TRAP_CALL_STACK_EXHAUSTED, "call stack exhausted") \ /* ran out of value stack space */ \ @@ -95,6 +91,7 @@ typedef struct WasmInterpreterMemory { void* data; uint32_t page_size; uint32_t byte_size; + uint32_t max_page_size; } WasmInterpreterMemory; typedef struct WasmInterpreterFuncTableEntry { |