diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index af359f336c..822bfa785b 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -14,13 +14,6 @@ extern "C" { #endif -#if WASM_ENABLE_EXCE_HANDLING != 0 -#define _EXCEWARNING \ - LOG_WARNING /* for exception handling misbehavior logging */ -#define _EXCEVERBOSE \ - LOG_VERBOSE /* more excessive tracing of tagbrowsing and stack pointers */ -#endif - /** Value Type */ #define VALUE_TYPE_I32 0x7F #define VALUE_TYPE_I64 0X7E @@ -223,15 +216,18 @@ typedef struct WASMFunctionImport { #if WASM_ENABLE_TAGS != 0 typedef struct WASMTagImport { + char *module_name; + char *field_name; uint8 attribute; /* the type of the tag (numerical) */ uint32 type; /* the type of the catch function (numerical)*/ WASMType *tag_type; - uint32 tag_index_linked; + void *tag_ptr_linked; + #if WASM_ENABLE_MULTI_MODULE != 0 - /* imported function pointer after linked */ - /* TODO: remove if not needed */ + /* imported tag pointer after linked */ WASMModule *import_module; WASMTag *import_tag_linked; + uint32 import_tag_index_linked; #endif } WASMTagImport; #endif @@ -340,6 +336,7 @@ struct WASMFunction { struct WASMTag { uint8 attribute; /* the attribute property of the tag (expected to be 0) */ uint32 type; /* the type of the tag (expected valid inden in type table) */ + WASMType *tag_type; }; #endif @@ -505,7 +502,7 @@ struct WASMModule { WASMTable *tables; WASMMemory *memories; #if WASM_ENABLE_TAGS != 0 - WASMTag *tags; + WASMTag **tags; #endif WASMGlobal *globals; WASMExport *exports; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 02eb8cdc3c..897cbf4757 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1272,7 +1272,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* get tag type */ uint8 tag_type_index = - module->module->tags[exception_tag_index].type; + module->module->tags[exception_tag_index]->type; uint32 cell_num_to_copy = wasm_types[tag_type_index]->param_cell_num; @@ -1291,9 +1291,35 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { read_leb_int32(frame_ip, frame_ip_end, exception_tag_index); - /* landig pad for the rethrow ? */ + /* landing pad for the rethrow ? */ find_a_catch_handler: { + WASMType *tag_type = NULL; + uint32 cell_num_to_copy = 0; + if (IS_INVALID_TAGINDEX(exception_tag_index)) { + /* + * invalid exception index, + * generated if a submodule throws an exception + * that has not been imported here + * + * This should result in a branch to the CATCH_ALL block, + * if there is one + */ + tag_type = NULL; + cell_num_to_copy = 0; + } + else { + if (module->e->tags[exception_tag_index].is_import_tag) { + tag_type = module->e->tags[exception_tag_index] + .u.tag_import->tag_type; + } + else { + tag_type = module->e->tags[exception_tag_index] + .u.tag->tag_type; + } + cell_num_to_copy = tag_type->param_cell_num; + } + /* browse through frame stack */ uint32 relative_depth = 0; do { @@ -1309,7 +1335,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* * skip that blocks in search * BLOCK, IF and LOOP do not contain handlers and - * cannot catch exceptions blocks marked as CATCH or + * cannot catch exceptions. + * blocks marked as CATCH or * CATCH_ALL did already caugth an exception and can * only be a target for RETHROW, but cannot catch an * exception again @@ -1347,34 +1374,20 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, UNWIND_CSP(relative_depth, LABEL_TYPE_CATCH); - /* transfer exception values */ - uint8 tag_type_index = - module->module - ->tags[exception_tag_index] - .type; - uint32 cell_num_to_copy = - wasm_types[tag_type_index] - ->param_cell_num; /* push exception_tag_index and * exception values for rethrow */ PUSH_I32(exception_tag_index); - if (cell_num_to_copy > 0) { - word_copy( - frame_sp, - frame_sp_old - - cell_num_to_copy, - cell_num_to_copy); - } + word_copy(frame_sp, + frame_sp_old + - cell_num_to_copy, + cell_num_to_copy); frame_sp += cell_num_to_copy; /* push exception values for catch */ - if (cell_num_to_copy > 0) { - word_copy( - frame_sp, - frame_sp_old - - cell_num_to_copy, - cell_num_to_copy); - } + word_copy(frame_sp, + frame_sp_old + - cell_num_to_copy, + cell_num_to_copy); frame_sp += cell_num_to_copy; /* advance to handler */ @@ -1403,21 +1416,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* unwind to delegated frame */ frame_csp -= lookup_depth; - /* transfer exception values */ - uint8 tag_type_index = - module->module - ->tags[exception_tag_index] - .type; - uint32 cell_num_to_copy = - wasm_types[tag_type_index] - ->param_cell_num; /* push exception values for catch */ - if (cell_num_to_copy > 0) { - word_copy(frame_sp, - frame_sp_old - - cell_num_to_copy, - cell_num_to_copy); - } + word_copy(frame_sp, + frame_sp_old + - cell_num_to_copy, + cell_num_to_copy); frame_sp += cell_num_to_copy; /* tag_index is already stored in @@ -1439,25 +1442,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* push exception_tag_index and * exception values for rethrow */ PUSH_I32(exception_tag_index); - if (exception_tag_index - != (int32_t)0xFFFFFFFF) { - /* transfer exception values */ - uint8 tag_type_index = - module->module - ->tags[exception_tag_index] - .type; - uint32 cell_num_to_copy = - wasm_types[tag_type_index] - ->param_cell_num; - if (cell_num_to_copy > 0) { - word_copy( - frame_sp, - frame_sp_old - - cell_num_to_copy, - cell_num_to_copy); - } - frame_sp += cell_num_to_copy; - } + word_copy(frame_sp, + frame_sp_old + - cell_num_to_copy, + cell_num_to_copy); + frame_sp += cell_num_to_copy; /* catch_all has no exception values */ /* advance to handler */ @@ -1469,7 +1458,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, "unexpected handler type"); goto got_exception; } - handler_number++; } /* exception not catched in this frame */ @@ -1481,29 +1469,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 *frame_sp_old = frame_sp; UNWIND_CSP(relative_depth, LABEL_TYPE_FUNCTION); - if (exception_tag_index - >= (int32_t)module->module->tag_count) { - wasm_set_exception(module, "invalid tag index"); - goto got_exception; - } - - /* transfer exception values */ - uint8 tag_type_index = - module->module->tags[exception_tag_index].type; - uint32 cell_num_to_copy = - wasm_types[tag_type_index]->param_cell_num; /* push exception values for catch * The values are copied to the CALLER FRAME * (prev_frame->sp) same behvior ad WASM_OP_RETURN */ - if (cell_num_to_copy > 0) { - word_copy(prev_frame->sp, - frame_sp_old - cell_num_to_copy, - cell_num_to_copy); - } + word_copy(prev_frame->sp, + frame_sp_old - cell_num_to_copy, + cell_num_to_copy); prev_frame->sp += cell_num_to_copy; *((int32 *)(prev_frame->sp)) = exception_tag_index; - (int32 *)(prev_frame->sp++); + prev_frame->sp++; /* mark frame as raised exception */ wasm_set_exception(module, @@ -4314,37 +4289,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* fix framesp */ UPDATE_ALL_FROM_FRAME(); - uint32 import_exception = - 0xFFFFFFFF; /* initialize imported exception index to be - invalid */ + uint32 import_exception; + /* initialize imported exception index to be invalid */ + SET_INVALID_TAGINDEX(import_exception); + /* pull external exception */ uint32 ext_exception = POP_I32(); - WASMModule *im_mod = cur_func->u.func_import->import_module; - /* external function came back with an exception or trap */ /* lookup exception in import tags */ - uint32 import_tag_index; - for (import_tag_index = 0; - import_tag_index < module->module->import_tag_count; - import_tag_index++) { - WASMTagImport *im_tag = - &(module->module->import_tags[import_tag_index] - .u.tag); + WASMTagInstance *tag = module->e->tags; + for (uint32 t = 0; t < module->module->import_tag_count; + tag++, t++) { /* compare the module and the external index with the * imort tag data */ - if ((im_mod == im_tag->import_module) - && (ext_exception == im_tag->tag_index_linked)) { + if ((cur_func->u.func_import->import_module + == tag->u.tag_import->import_module) + && (ext_exception + == tag->u.tag_import + ->import_tag_index_linked)) { /* set the import_exception to the import tag */ - import_exception = import_tag_index; + import_exception = t; break; } } /* - * push the internal exception index to stack, - * or 0xffffffff in case, the external exception - * is not in the import list + * excange the thrown exception (index valid in submodule) + * with the imported exception index (valid in this module) + * if the module did not import the exception, + * that results in a "INVALID_TAGINDEX", that triggers + * an CATCH_ALL block, if there is one. */ PUSH_I32(import_exception); } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index bc2e4df1b8..10eb076ad1 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -697,7 +697,6 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name, WASMExport *export = loader_find_export((WASMModuleCommon *)module, module_name, field_name, export_kind, error_buf, error_buf_size); - ; return export; } #endif @@ -888,6 +887,58 @@ wasm_loader_resolve_global(const char *module_name, const char *global_name, return global; } +#if WASM_ENABLE_TAGS != 0 +static WASMTag * +wasm_loader_resolve_tag(const char *module_name, const char *tag_name, + const WASMType *expected_tag_type, + uint32 *linked_tag_index, char *error_buf, + uint32 error_buf_size) +{ + WASMModuleCommon *module_reg; + WASMTag *tag = NULL; + WASMExport *export = NULL; + WASMModule *module = NULL; + + module_reg = wasm_runtime_find_module_registered(module_name); + if (!module_reg || module_reg->module_type != Wasm_Module_Bytecode) { + LOG_DEBUG("can not find a module named %s for tag %s", module_name, + tag_name); + set_error_buf(error_buf, error_buf_size, "unknown import"); + return NULL; + } + + module = (WASMModule *)module_reg; + export = + wasm_loader_find_export(module, module_name, tag_name, EXPORT_KIND_TAG, + error_buf, error_buf_size); + if (!export) { + return NULL; + } + + /* resolve tag type and tag */ + if (export->index < module->import_tag_count) { + /* importing an imported tag from the submodule */ + tag = module->import_tags[export->index].u.tag.import_tag_linked; + } + else { + /* importing an section tag from the submodule */ + tag = module->tags[export->index - module->import_tag_count]; + } + + /* check function type */ + if (!wasm_type_equal(expected_tag_type, tag->tag_type)) { + LOG_DEBUG("%s.%s failed the type check", module_name, tag_name); + set_error_buf(error_buf, error_buf_size, "incompatible import type"); + return NULL; + } + + if (linked_tag_index != NULL) { + *linked_tag_index = export->index; + } + + return tag; +} +#endif #endif /* end of WASM_ENABLE_MULTI_MODULE */ static bool @@ -1227,86 +1278,76 @@ load_tag_import(const uint8 **p_buf, const uint8 *buf_end, WASMTagImport *tag, /* structure to fill */ char *error_buf, uint32 error_buf_size) { - WASMExport *export = 0; - WASMModule *sub_module = NULL; - uint32 i; - -#if WASM_ENABLE_MULTI_MODULE != 0 - if (!wasm_runtime_is_built_in_module(sub_module_name)) { - sub_module = load_depended_module(parent_module, sub_module_name, - error_buf, error_buf_size); - if (!sub_module) { - return false; - } - } -#endif - - WASMModuleCommon *module_reg = - wasm_runtime_find_module_registered(sub_module_name); - if (!module_reg) { - set_error_buf(error_buf, error_buf_size, - "load_tag_import: registered module not found"); - goto fail; - } - sub_module = (WASMModule *)module_reg; - - export = sub_module->exports; - for (i = 0; i < sub_module->export_count; i++, export ++) { - - if (export->kind == EXPORT_KIND_TAG - && strcmp(export->name, tag_name) == 0) { - WASMTag *imp_tag = (WASMTag *)&sub_module->tags[export->index]; - WASMType *imp_tag_type = - (WASMType *)sub_module->types[imp_tag->type]; - /* fill import tag*/ - tag->tag_index_linked = export->index; - tag->tag_type = (WASMType *)sub_module->types[imp_tag->type]; + /* attribute and type of the import statement */ + uint8 declare_tag_attribute; + uint32 declare_type_index; + const uint8 *p = *p_buf, *p_end = buf_end; #if WASM_ENABLE_MULTI_MODULE != 0 - tag->import_module = (WASMModule *)module_reg; - tag->import_tag_linked = &sub_module->tags[export->index]; + WASMModule *sub_module = NULL; #endif - } - } - - uint8 tag_attribute; - uint32 tag_type; - const uint8 *p = *p_buf, *p_end = buf_end; /* get the one byte attribute */ CHECK_BUF(p, p_end, 1); - tag_attribute = read_uint8(p); - if (tag_attribute != 0) { + declare_tag_attribute = read_uint8(p); + if (declare_tag_attribute != 0) { set_error_buf(error_buf, error_buf_size, "unknown tag attribute"); goto fail; } /* get type */ - read_leb_uint32(p, p_end, tag_type); + read_leb_uint32(p, p_end, declare_type_index); /* compare against module->types */ - if (tag_type >= parent_module->type_count) { + if (declare_type_index >= parent_module->type_count) { set_error_buf(error_buf, error_buf_size, "unknown tag type"); goto fail; } - /* check, that the type of the referred tag returns void */ - WASMType *func_type = (WASMType *)parent_module->types[tag_type]; - if (func_type->result_count != 0) { + WASMType *declare_tag_type = parent_module->types[declare_type_index]; + + /* check, that the type of the declared tag returns void */ + if (declare_tag_type->result_count != 0) { set_error_buf(error_buf, error_buf_size, "tag type signature does not return void"); goto fail; } +#if WASM_ENABLE_MULTI_MODULE != 0 + if (!wasm_runtime_is_built_in_module(sub_module_name)) { + sub_module = (WASMModule *)wasm_runtime_load_depended_module( + (WASMModuleCommon *)parent_module, sub_module_name, error_buf, + error_buf_size); + if (!sub_module) { + return false; + } + /* wasm_loader_resolve_tag checks, that the imported tag + * and the declared tag have the same type + */ + uint32 linked_tag_index = 0; + WASMTag *linked_tag = wasm_loader_resolve_tag( + sub_module_name, tag_name, declare_tag_type, + &linked_tag_index /* out */, error_buf, error_buf_size); + if (linked_tag) { + tag->import_module = sub_module; + tag->import_tag_linked = linked_tag; + tag->import_tag_index_linked = linked_tag_index; + } + } +#endif /* store to module tag declarations */ - tag->attribute = tag_attribute; - tag->type = tag_type; + tag->attribute = declare_tag_attribute; + tag->type = declare_type_index; + + tag->module_name = (char *)sub_module_name; + tag->field_name = (char *)tag_name; + tag->tag_type = declare_tag_type; *p_buf = p; (void)parent_module; LOG_VERBOSE("Load tag import success\n"); - return true; + return true; fail: return false; } @@ -2671,28 +2712,30 @@ load_tag_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_code, const uint8 *buf_code_end, WASMModule *module, char *error_buf, uint32 error_buf_size) { - LOG_VERBOSE("In %s\n", __FUNCTION__); + (void)buf_code; + (void)buf_code_end; + const uint8 *p = buf, *p_end = buf_end; size_t total_size = 0; /* number of tags defined in the section */ uint32 section_tag_count = 0; uint8 tag_attribute; uint32 tag_type; + WASMTag *tag = NULL; /* get tag count */ read_leb_uint32(p, p_end, section_tag_count); - module->tag_count = module->import_tag_count + section_tag_count; + module->tag_count = section_tag_count; if (section_tag_count) { - total_size = sizeof(WASMTag) * module->tag_count; + total_size = sizeof(WASMTag *) * module->tag_count; if (!(module->tags = loader_malloc(total_size, error_buf, error_buf_size))) { return false; } /* load each tag, imported tags precede the tags */ uint32 tag_index; - for (tag_index = module->import_tag_count; - tag_index < module->tag_count; tag_index++) { + for (tag_index = 0; tag_index < section_tag_count; tag_index++) { /* get the one byte attribute */ CHECK_BUF(p, p_end, 1); @@ -2716,9 +2759,15 @@ load_tag_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_code, goto fail; } + if (!(tag = module->tags[tag_index] = loader_malloc( + sizeof(WASMTag), error_buf, error_buf_size))) { + return false; + } + /* store to module tag declarations */ - module->tags[tag_index].attribute = tag_attribute; - module->tags[tag_index].type = tag_type; + tag->attribute = tag_attribute; + tag->type = tag_type; + tag->tag_type = func_type; } } @@ -4414,6 +4463,16 @@ wasm_loader_unload(WASMModule *module) if (module->memories) wasm_runtime_free(module->memories); +#if WASM_ENABLE_TAGS != 0 + if (module->tags) { + for (i = 0; i < module->tag_count; i++) { + if (module->tags[i]) + wasm_runtime_free(module->tags[i]); + } + wasm_runtime_free(module->tags); + } +#endif + if (module->globals) wasm_runtime_free(module->globals); @@ -7095,7 +7154,6 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, return true; } - /* Check stack cell num equals return cell num */ if (available_stack_cell != return_cell_num) { #if WASM_ENABLE_EXCE_HANDLING != 0 /* testspec: this error message format is expected by try_catch.wast */ @@ -7597,30 +7655,58 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, /* check validity of tag_index against module->tag_count */ /* check tag index is within the tag index space */ - if (tag_index >= module->tag_count) { - set_error_buf(error_buf, error_buf_size, - "unknown tag index"); + if (tag_index >= module->import_tag_count + module->tag_count) { + snprintf(error_buf, error_buf_size, "unknown tag %d", + tag_index); goto fail; } - /* the index of the type stored in the tag declaration */ - uint8 tag_type_index = module->tags[tag_index].type; - - /* check validity of tag_type_index */ - if (tag_type_index >= module->type_count) { - set_error_buf(error_buf, error_buf_size, - "unknown tag type index"); - goto fail; + /* the tag_type is stored in either the WASMTag (section tags) + * or WASMTagImport (import tag) */ + WASMType *tag_type = NULL; + if (tag_index < module->import_tag_count) { + tag_type = module->import_tags[tag_index].u.tag.tag_type; + } + else { + tag_type = + module->tags[tag_index - module->import_tag_count] + ->tag_type; } - /* check, that the type of the referred tag returns void */ - WASMType *func_type = (WASMType *)module->types[tag_type_index]; - if (func_type->result_count != 0) { + if (tag_type->result_count != 0) { set_error_buf(error_buf, error_buf_size, "tag type signature does not return void"); goto fail; } + int32 available_stack_cell = + (int32)(loader_ctx->stack_cell_num + - cur_block->stack_cell_num); + + /* Check stack values match return types by comparing tag param + * types with stack cells */ + uint8 *frame_ref = loader_ctx->frame_ref; + for (int tti = (int32)tag_type->param_count - 1; tti >= 0; + tti--) { + if (!check_stack_top_values(frame_ref, available_stack_cell, + tag_type->types[tti], error_buf, + error_buf_size)) { + snprintf(error_buf, error_buf_size, + "type mismatch: instruction requires [%s] but " + "stack has [%s]", + tag_type->param_count > 0 + ? type2str(tag_type->types[tti]) + : "", + available_stack_cell > 0 + ? type2str(*(loader_ctx->frame_ref - 1)) + : ""); + goto fail; + } + frame_ref -= wasm_value_type_cell_num(tag_type->types[tti]); + available_stack_cell -= + wasm_value_type_cell_num(tag_type->types[tti]); + } + /* throw is stack polymorphic */ (void)label_type; RESET_STACK(); @@ -7683,23 +7769,25 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, /* check validity of tag_index against module->tag_count */ /* check tag index is within the tag index space */ - if (tag_index >= module->tag_count) { + if (tag_index >= module->import_tag_count + module->tag_count) { + LOG_VERBOSE("In %s, unknown tag at WASM_OP_CATCH\n", + __FUNCTION__); set_error_buf(error_buf, error_buf_size, "unknown tag"); goto fail; } - /* the index of the type stored in the tag declaration */ - uint8 tag_type_index = module->tags[tag_index].type; - - /* check validity of tag_type_index */ - if (tag_type_index >= module->type_count) { - set_error_buf(error_buf, error_buf_size, - "unknown tag type index"); - goto fail; + /* the tag_type is stored in either the WASMTag (section tags) + * or WASMTagImport (import tag) */ + WASMType *func_type = NULL; + if (tag_index < module->import_tag_count) { + func_type = module->import_tags[tag_index].u.tag.tag_type; + } + else { + func_type = + module->tags[tag_index - module->import_tag_count] + ->tag_type; } - /* check, that the type of the referred tag returns void */ - WASMType *func_type = module->types[tag_type_index]; if (func_type->result_count != 0) { set_error_buf(error_buf, error_buf_size, "tag type signature does not return void"); @@ -7717,7 +7805,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, BlockType new_block_type; new_block_type.is_value_type = false; - new_block_type.u.type = module->types[tag_type_index]; + new_block_type.u.type = func_type; /* * replace frame_csp by LABEL_TYPE_CATCH diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 720a78f036..c2668b6cb0 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -738,6 +738,101 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, return functions; } +#if WASM_ENABLE_TAGS != 0 +/** + * Destroy tags instances. + */ +static void +tags_deinstantiate(WASMTagInstance *tags, void **import_tag_ptrs) +{ + if (tags) { + wasm_runtime_free(tags); + } + if (import_tag_ptrs) { + wasm_runtime_free(import_tag_ptrs); + } +} + +/** + * Instantiate tags in a module. + */ +static WASMTagInstance * +tags_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, + char *error_buf, uint32 error_buf_size) +{ + WASMImport *import; + uint32 i, tag_count = module->import_tag_count + module->tag_count; + uint64 total_size = sizeof(WASMTagInstance) * (uint64)tag_count; + WASMTagInstance *tags, *tag; + + if (!(tags = runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + total_size = sizeof(void *) * (uint64)module->import_tag_count; + if (total_size > 0 + && !(module_inst->e->import_tag_ptrs = + runtime_malloc(total_size, error_buf, error_buf_size))) { + wasm_runtime_free(tags); + return NULL; + } + + /* instantiate tags from import section */ + tag = tags; + import = module->import_tags; + for (i = 0; i < module->import_tag_count; i++, import++) { + tag->is_import_tag = true; + tag->u.tag_import = &import->u.tag; + tag->type = import->u.tag.type; + tag->attribute = import->u.tag.attribute; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (import->u.tag.import_module) { + if (!(tag->import_module_inst = get_sub_module_inst( + module_inst, import->u.tag.import_module))) { + set_error_buf(error_buf, error_buf_size, "unknown tag"); + goto fail; + } + + if (!(tag->import_tag_inst = + wasm_lookup_tag(tag->import_module_inst, + import->u.tag.field_name, NULL))) { + set_error_buf(error_buf, error_buf_size, "unknown tag"); + goto fail; + } + + /* Copy the imported tag to current instance */ + module_inst->e->import_tag_ptrs[i] = + tag->u.tag_import->import_tag_linked; + } +#endif + tag++; + } + + /* instantiate tags from tag section */ + for (i = 0; i < module->tag_count; i++) { + tag->is_import_tag = false; + tag->type = module->tags[i]->type; + tag->u.tag = module->tags[i]; + +#if WASM_ENABLE_FAST_INTERP != 0 + /* tag->const_cell_num = function->u.func->const_cell_num; */ +#endif + tag++; + } + bh_assert((uint32)(tag - tags) == tag_count); + + return tags; + +#if WASM_ENABLE_MULTI_MODULE != 0 +fail: + tags_deinstantiate(tags, module_inst->e->import_tag_ptrs); + /* clean up */ + module_inst->e->import_tag_ptrs = NULL; + return NULL; +#endif +} +#endif + /** * Destroy global instances. */ @@ -937,6 +1032,52 @@ export_functions_instantiate(const WASMModule *module, return export_funcs; } +#if WASM_ENABLE_TAGS != 0 +/** + * Destroy export function instances. + */ +static void +export_tags_deinstantiate(WASMExportTagInstance *tags) +{ + if (tags) + wasm_runtime_free(tags); +} + +/** + * Instantiate export functions in a module. + */ +static WASMExportTagInstance * +export_tags_instantiate(const WASMModule *module, + WASMModuleInstance *module_inst, + uint32 export_tag_count, char *error_buf, + uint32 error_buf_size) +{ + WASMExportTagInstance *export_tags, *export_tag; + WASMExport *export = module->exports; + uint32 i; + uint64 total_size = + sizeof(WASMExportTagInstance) * (uint64)export_tag_count; + + if (!(export_tag = export_tags = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + for (i = 0; i < module->export_count; i++, export ++) + if (export->kind == EXPORT_KIND_TAG) { + export_tag->name = export->name; + + bh_assert((uint32)(module_inst->export_tags)); + + export_tag->tag = &module_inst->e->tags[export->index]; + export_tag++; + } + + bh_assert((uint32)(export_tag - export_tags) == export_tag_count); + return export_tags; +} +#endif + #if WASM_ENABLE_MULTI_MODULE != 0 static void export_globals_deinstantiate(WASMExportGlobInstance *globals) @@ -1693,6 +1834,9 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, module_inst->table_count = module->import_table_count + module->table_count; module_inst->e->function_count = module->import_function_count + module->function_count; +#if WASM_ENABLE_TAGS != 0 + module_inst->e->tag_count = module->import_tag_count + module->tag_count; +#endif /* export */ module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC); @@ -1701,11 +1845,15 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, get_export_count(module, EXPORT_KIND_TABLE); module_inst->export_memory_count = get_export_count(module, EXPORT_KIND_MEMORY); +#if WASM_ENABLE_TAGS != 0 + module_inst->e->export_tag_count = + get_export_count(module, EXPORT_KIND_TAG); +#endif module_inst->export_global_count = get_export_count(module, EXPORT_KIND_GLOBAL); #endif - /* Instantiate memories/tables/functions */ + /* Instantiate memories/tables/functions/tags */ if ((module_inst->memory_count > 0 && !(module_inst->memories = memories_instantiate(module, module_inst, parent, heap_size, @@ -1721,6 +1869,15 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, && !(module_inst->export_functions = export_functions_instantiate( module, module_inst, module_inst->export_func_count, error_buf, error_buf_size))) +#if WASM_ENABLE_TAGS != 0 + || (module_inst->e->tag_count > 0 + && !(module_inst->e->tags = tags_instantiate( + module, module_inst, error_buf, error_buf_size))) + || (module_inst->e->export_tag_count > 0 + && !(module_inst->e->export_tags = export_tags_instantiate( + module, module_inst, module_inst->e->export_tag_count, + error_buf, error_buf_size))) +#endif #if WASM_ENABLE_MULTI_MODULE != 0 || (module_inst->export_global_count > 0 && !(module_inst->export_globals = export_globals_instantiate( @@ -1738,7 +1895,6 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, ) { goto fail; } - if (global_count > 0) { /* Initialize the global data */ global_data = module_inst->global_data; @@ -2161,8 +2317,16 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) tables_deinstantiate(module_inst); functions_deinstantiate(module_inst->e->functions, module_inst->e->function_count); +#if WASM_ENABLE_TAGS != 0 + tags_deinstantiate(module_inst->e->tags, module_inst->e->import_tag_ptrs); +#endif + globals_deinstantiate(module_inst->e->globals); export_functions_deinstantiate(module_inst->export_functions); +#if WASM_ENABLE_TAGS != 0 + export_tags_deinstantiate(module_inst->e->export_tags); +#endif + #if WASM_ENABLE_MULTI_MODULE != 0 export_globals_deinstantiate(module_inst->export_globals); #endif @@ -2236,6 +2400,21 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name) (void)module_inst->export_tables; return module_inst->tables[0]; } + +#if WASM_ENABLE_TAGS != 0 +WASMTagInstance * +wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name, + const char *signature) +{ + uint32 i; + for (i = 0; i < module_inst->e->export_tag_count; i++) + if (!strcmp(module_inst->e->export_tags[i].name, name)) + return module_inst->e->export_tags[i].tag; + (void)signature; + return NULL; +} +#endif + #endif #ifdef OS_ENABLE_HW_BOUND_CHECK diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 7d78df14f6..2f9ce6c606 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -27,6 +27,9 @@ typedef struct WASMFunctionInstance WASMFunctionInstance; typedef struct WASMMemoryInstance WASMMemoryInstance; typedef struct WASMTableInstance WASMTableInstance; typedef struct WASMGlobalInstance WASMGlobalInstance; +#if WASM_ENABLE_TAGS != 0 +typedef struct WASMTagInstance WASMTagInstance; +#endif /** * When LLVM JIT, WAMR compiler or AOT is enabled, we should ensure that @@ -183,6 +186,30 @@ struct WASMFunctionInstance { #endif }; +#if WASM_ENABLE_TAGS != 0 +struct WASMTagInstance { + bool is_import_tag; + /* tag attribute */ + uint8 attribute; + /* tag type index */ + uint32 type; + union { + WASMTagImport *tag_import; + WASMTag *tag; + } u; + +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModuleInstance *import_module_inst; + WASMTagInstance *import_tag_inst; +#endif +}; +#endif + +#if WASM_ENABLE_EXCE_HANDLING != 0 +#define INVALID_TAGINDEX ((uint32)0xFFFFFFFF) +#define SET_INVALID_TAGINDEX(tag) (tag = INVALID_TAGINDEX) +#define IS_INVALID_TAGINDEX(tag) ((tag & INVALID_TAGINDEX) == INVALID_TAGINDEX) +#endif typedef struct WASMExportFuncInstance { char *name; WASMFunctionInstance *function; @@ -203,6 +230,13 @@ typedef struct WASMExportMemInstance { WASMMemoryInstance *memory; } WASMExportMemInstance; +#if WASM_ENABLE_TAGS != 0 +typedef struct WASMExportTagInstance { + char *name; + WASMTagInstance *tag; +} WASMExportTagInstance; +#endif + /* wasm-c-api import function info */ typedef struct CApiFuncImport { /* host func pointer after linked */ @@ -249,6 +283,14 @@ typedef struct WASMModuleInstanceExtra { WASMTableInstance **table_insts_linked; #endif +#if WASM_ENABLE_TAGS != 0 + uint32 tag_count; + uint32 export_tag_count; + WASMTagInstance *tags; + WASMExportTagInstance *export_tags; + void **import_tag_ptrs; +#endif + #if WASM_ENABLE_MEMORY_PROFILING != 0 uint32 max_aux_stack_used; #endif @@ -440,6 +482,13 @@ wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); WASMTableInstance * wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name); + +#if WASM_ENABLE_TAGS != 0 +WASMTagInstance * +wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name, + const char *signature); +#endif + #endif bool diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 48d35acbfb..a8eb81b57f 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -50,6 +50,7 @@ def get_iwasm_cmd(platform: str) -> str: WAST2WASM_CMD = exe_file_path("./wabt/out/gcc/Release/wat2wasm") SPEC_INTERPRETER_CMD = "spec/interpreter/wasm" WAMRC_CMD = "../../../wamr-compiler/build/wamrc" +EXCE_HANDLING_DIR = "exception-handling/test/core" class TargetAction(argparse.Action): @@ -84,12 +85,6 @@ def ignore_the_case( eh_flag=False, qemu_flag=False, ): - # print(f"case_name {case_name}\n") - if eh_flag: - if case_name in [ "tag", "try_catch", "rethrow", "try_delegate" ]: - return False - else: - return True if case_name in ["comments", "inline-module", "names"]: return True @@ -138,10 +133,6 @@ def ignore_the_case( def preflight_check(aot_flag, eh_flag): - global SPEC_TEST_DIR - if eh_flag: - SPEC_TEST_DIR="exception-handling/test/core" - if not pathlib.Path(SPEC_TEST_DIR).resolve().exists(): print(f"Can not find {SPEC_TEST_DIR}") return False @@ -154,6 +145,10 @@ def preflight_check(aot_flag, eh_flag): print(f"Can not find {WAMRC_CMD}") return False + if eh_flag and not pathlib.Path(EXCE_HANDLING_DIR).resolve().exists(): + print(f"Can not find {EXCE_HANDLING_DIR}") + return False + return True @@ -297,10 +292,6 @@ def test_suite( log="", no_pty=False, ): - global SPEC_TEST_DIR - if eh_flag: - SPEC_TEST_DIR="exception-handling/test/core" - suite_path = pathlib.Path(SPEC_TEST_DIR).resolve() if not suite_path.exists(): print(f"can not find spec test cases at {suite_path}") @@ -315,6 +306,15 @@ def test_suite( gc_case_list = sorted(suite_path.glob("gc/*.wast")) case_list.extend(gc_case_list) + if eh_flag: + eh_path = pathlib.Path(EXCE_HANDLING_DIR).resolve() + if not eh_path.exists(): + print(f"can not find spec test cases at {eh_path}") + return False + eh_case_list = sorted(eh_path.glob("*.wast")) + eh_case_list_include = [test for test in eh_case_list if test.stem in ["throw", "tag", "try_catch", "rethrow", "try_delegate"]] + case_list.extend(eh_case_list_include) + # ignore based on command line options filtered_case_list = [] for case_path in case_list: diff --git a/tests/wamr-test-suites/spec-test-script/exception_handling.patch b/tests/wamr-test-suites/spec-test-script/exception_handling.patch new file mode 100644 index 0000000000..0c9e8d40f5 --- /dev/null +++ b/tests/wamr-test-suites/spec-test-script/exception_handling.patch @@ -0,0 +1,20 @@ +diff --git a/test/core/try_catch.wast b/test/core/try_catch.wast +index 2a0e9ff6..f243489d 100644 +--- a/test/core/try_catch.wast ++++ b/test/core/try_catch.wast +@@ -203,7 +203,6 @@ + + (assert_return (invoke "catch-param-i32" (i32.const 5)) (i32.const 5)) + +-(assert_return (invoke "catch-imported") (i32.const 2)) + + (assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0)) + (assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1)) +@@ -231,7 +230,6 @@ + ) + ) + +-(assert_return (invoke "imported-mismatch") (i32.const 3)) + + (assert_malformed + (module quote "(module (func (catch_all)))") diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 9c4b31b450..4e07072630 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -427,6 +427,26 @@ function spec_test() git apply ../../spec-test-script/thread_proposal_fix_atomic_case.patch fi + if [ ${ENABLE_EH} == 1 ]; then + echo "checkout exception-handling test cases" + popd + if [ ! -d "exception-handling" ];then + echo "exception-handling not exist, clone it from github" + git clone -b master --single-branch https://github.com/WebAssembly/exception-handling + fi + pushd exception-handling + + # restore and clean everything + git reset --hard 51c721661b671bb7dc4b3a3acb9e079b49778d36 + + if [[ ${ENABLE_MULTI_MODULE} == 0 ]]; then + git apply ../../spec-test-script/exception_handling.patch + fi + + popd + echo $(pwd) + fi + # update GC cases if [[ ${ENABLE_GC} == 1 ]]; then echo "checkout spec for GC proposal" @@ -465,6 +485,10 @@ function spec_test() fi fi + if [[ 1 == ${ENABLE_EH} ]]; then + ARGS_FOR_SPEC_TEST+="-e " + fi + # sgx only enable in interp mode and aot mode if [[ ${SGX_OPT} == "--sgx" ]];then if [[ $1 == 'classic-interp' || $1 == 'fast-interp' || $1 == 'aot' || $1 == 'fast-jit' ]]; then @@ -527,88 +551,6 @@ function spec_test() echo -e "\nFinish spec tests" | tee -a ${REPORT_DIR}/spec_test_report.txt } -function exception_test() -{ - echo "Now start exception tests" - touch ${REPORT_DIR}/exception_test_report.txt - - cd ${WORK_DIR} - if [ ! -d "exception-handling" ];then - echo "exception-handling not exist, clone it from github" - git clone -b master --single-branch https://github.com/WebAssembly/exception-handling - fi - - pushd exception-handling - - # restore and clean everything - git reset --hard HEAD - - popd - echo $(pwd) - - if [ ${WABT_BINARY_RELEASE} == "YES" ]; then - echo "download a binary release and install" - local WAT2WASM=${WORK_DIR}/wabt/out/gcc/Release/wat2wasm - if [ ! -f ${WAT2WASM} ]; then - case ${PLATFORM} in - linux) - WABT_PLATFORM=ubuntu - ;; - darwin) - WABT_PLATFORM=macos - ;; - *) - echo "wabt platform for ${PLATFORM} in unknown" - exit 1 - ;; - esac - if [ ! -f /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz ]; then - wget \ - https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ - -P /tmp - fi - - cd /tmp \ - && tar zxf wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ - && mkdir -p ${WORK_DIR}/wabt/out/gcc/Release/ \ - && install wabt-1.0.31/bin/wa* ${WORK_DIR}/wabt/out/gcc/Release/ \ - && cd - - fi - else - echo "download source code and compile and install" - if [ ! -d "wabt" ];then - echo "wabt not exist, clone it from github" - git clone --recursive https://github.com/WebAssembly/wabt - fi - echo "upate wabt" - cd wabt - git pull - git reset --hard origin/main - cd .. - make -C wabt gcc-release -j 4 - fi - - ln -sf ${WORK_DIR}/../spec-test-script/all.py . - ln -sf ${WORK_DIR}/../spec-test-script/runtest.py . - - local ARGS_FOR_SPEC_TEST="-e --no_clean_up " - - # set log directory - ARGS_FOR_SPEC_TEST+="--log ${REPORT_DIR}" - - cd ${WORK_DIR} - echo "python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/exception_test_report.txt" - python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/exception_test_report.txt - if [[ ${PIPESTATUS[0]} -ne 0 ]];then - echo -e "\nspec tests FAILED" | tee -a ${REPORT_DIR}/exception_test_report.txt - exit 1 - fi - cd - - - echo -e "\nFinish exception tests" | tee -a ${REPORT_DIR}/exception_test_report.txt -} - - function wasi_test() { echo "Now start wasi tests" @@ -916,7 +858,6 @@ function trigger() if [[ ${ENABLE_EH} == 1 ]]; then EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_EXCE_HANDLING=1" EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_TAIL_CALL=1" - EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MULTI_MODULE=1" fi echo "SANITIZER IS" $WAMR_BUILD_SANITIZER