From 587513f3c60f1707681af606a578a8c9f2dfb586 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 3 Jan 2023 20:01:05 +0800 Subject: [PATCH 1/3] Add place holders for exception handling opcodes (#1852) Define exception handling opcodes and add empty handlers for the opcodes. --- build-scripts/config_common.cmake | 4 +++ core/config.h | 4 +++ core/iwasm/interpreter/wasm_interp_classic.c | 28 +++++++++++++++----- core/iwasm/interpreter/wasm_interp_fast.c | 28 +++++++++++++++----- core/iwasm/interpreter/wasm_loader.c | 24 +++++++++++++++++ core/iwasm/interpreter/wasm_mini_loader.c | 23 ++++++++++++++++ core/iwasm/interpreter/wasm_opcode.h | 26 +++++++++--------- 7 files changed, 113 insertions(+), 24 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 53b0207fbf..ad074e64b4 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -285,6 +285,10 @@ if (WAMR_BUILD_REF_TYPES EQUAL 1) else () message (" Reference types disabled") endif () +if (WAMR_BUILD_EXCE_HANDLING EQUAL 1) + add_definitions (-DWASM_ENABLE_EXCE_HANDLING=1) + message (" Exception Handling enabled") +endif () if (DEFINED WAMR_BH_VPRINTF) add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF}) endif () diff --git a/core/config.h b/core/config.h index 5d6438384e..a7e0ba0a9d 100644 --- a/core/config.h +++ b/core/config.h @@ -422,6 +422,10 @@ #define WASM_ENABLE_REF_TYPES 0 #endif +#ifndef WASM_ENABLE_EXCE_HANDLING +#define WASM_ENABLE_EXCE_HANDLING 0 +#endif + #ifndef WASM_ENABLE_SGX_IPFS #define WASM_ENABLE_SGX_IPFS 0 #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index fa542b14e0..63edbbf517 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1503,6 +1503,20 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto call_func_from_interp; } +#if WASM_ENABLE_EXCE_HANDLING != 0 + HANDLE_OP(WASM_OP_TRY) + HANDLE_OP(WASM_OP_CATCH) + HANDLE_OP(WASM_OP_THROW) + HANDLE_OP(WASM_OP_RETHROW) + HANDLE_OP(WASM_OP_DELEGATE) + HANDLE_OP(WASM_OP_CATCH_ALL) + { + /* TODO */ + wasm_set_exception(module, "unsupported opcode"); + goto got_exception; + } +#endif + /* parametric instructions */ HANDLE_OP(WASM_OP_DROP) { @@ -3747,10 +3761,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif #if WASM_ENABLE_LABELS_AS_VALUES != 0 - HANDLE_OP(WASM_OP_UNUSED_0x06) - HANDLE_OP(WASM_OP_UNUSED_0x07) - HANDLE_OP(WASM_OP_UNUSED_0x08) - HANDLE_OP(WASM_OP_UNUSED_0x09) HANDLE_OP(WASM_OP_UNUSED_0x0a) #if WASM_ENABLE_TAIL_CALL == 0 HANDLE_OP(WASM_OP_RETURN_CALL) @@ -3766,13 +3776,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_REF_NULL) HANDLE_OP(WASM_OP_REF_IS_NULL) HANDLE_OP(WASM_OP_REF_FUNC) +#endif +#if WASM_ENABLE_EXCE_HANDLING == 0 + HANDLE_OP(WASM_OP_TRY) + HANDLE_OP(WASM_OP_CATCH) + HANDLE_OP(WASM_OP_THROW) + HANDLE_OP(WASM_OP_RETHROW) + HANDLE_OP(WASM_OP_DELEGATE) + HANDLE_OP(WASM_OP_CATCH_ALL) #endif HANDLE_OP(WASM_OP_UNUSED_0x14) HANDLE_OP(WASM_OP_UNUSED_0x15) HANDLE_OP(WASM_OP_UNUSED_0x16) HANDLE_OP(WASM_OP_UNUSED_0x17) - HANDLE_OP(WASM_OP_UNUSED_0x18) - HANDLE_OP(WASM_OP_UNUSED_0x19) HANDLE_OP(WASM_OP_UNUSED_0x27) /* Used by fast interpreter */ HANDLE_OP(EXT_OP_SET_LOCAL_FAST_I64) diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 3109b0c824..eecf27992a 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1395,6 +1395,20 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto call_func_from_interp; } +#if WASM_ENABLE_EXCE_HANDLING != 0 + HANDLE_OP(WASM_OP_TRY) + HANDLE_OP(WASM_OP_CATCH) + HANDLE_OP(WASM_OP_THROW) + HANDLE_OP(WASM_OP_RETHROW) + HANDLE_OP(WASM_OP_DELEGATE) + HANDLE_OP(WASM_OP_CATCH_ALL) + { + /* TODO */ + wasm_set_exception(module, "unsupported opcode"); + goto got_exception; + } +#endif + /* parametric instructions */ HANDLE_OP(WASM_OP_SELECT) { @@ -3601,10 +3615,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif #if WASM_ENABLE_LABELS_AS_VALUES != 0 - HANDLE_OP(WASM_OP_UNUSED_0x06) - HANDLE_OP(WASM_OP_UNUSED_0x07) - HANDLE_OP(WASM_OP_UNUSED_0x08) - HANDLE_OP(WASM_OP_UNUSED_0x09) HANDLE_OP(WASM_OP_UNUSED_0x0a) #if WASM_ENABLE_TAIL_CALL == 0 HANDLE_OP(WASM_OP_RETURN_CALL) @@ -3619,6 +3629,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_REF_NULL) HANDLE_OP(WASM_OP_REF_IS_NULL) HANDLE_OP(WASM_OP_REF_FUNC) +#endif +#if WASM_ENABLE_EXCE_HANDLING == 0 + HANDLE_OP(WASM_OP_TRY) + HANDLE_OP(WASM_OP_CATCH) + HANDLE_OP(WASM_OP_THROW) + HANDLE_OP(WASM_OP_RETHROW) + HANDLE_OP(WASM_OP_DELEGATE) + HANDLE_OP(WASM_OP_CATCH_ALL) #endif /* SELECT_T is converted to SELECT or SELECT_64 */ HANDLE_OP(WASM_OP_SELECT_T) @@ -3626,8 +3644,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_UNUSED_0x15) HANDLE_OP(WASM_OP_UNUSED_0x16) HANDLE_OP(WASM_OP_UNUSED_0x17) - HANDLE_OP(WASM_OP_UNUSED_0x18) - HANDLE_OP(WASM_OP_UNUSED_0x19) HANDLE_OP(WASM_OP_UNUSED_0x27) /* optimized op code */ HANDLE_OP(WASM_OP_F32_STORE) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ef7df8e000..414393beb4 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -4553,6 +4553,17 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, u8 = read_uint8(p); /* 0x00 */ break; +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_TRY: + case WASM_OP_CATCH: + case WASM_OP_THROW: + case WASM_OP_RETHROW: + case WASM_OP_DELEGATE: + case WASM_OP_CATCH_ALL: + /* TODO */ + return false; +#endif + case WASM_OP_DROP: case WASM_OP_SELECT: case WASM_OP_DROP_64: @@ -7828,6 +7839,19 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, break; } +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_TRY: + case WASM_OP_CATCH: + case WASM_OP_THROW: + case WASM_OP_RETHROW: + case WASM_OP_DELEGATE: + case WASM_OP_CATCH_ALL: + /* TODO */ + set_error_buf_v(error_buf, error_buf_size, "%s %02x", + "unsupported opcode", opcode); + goto fail; +#endif + case WASM_OP_DROP: { BranchBlock *cur_block = loader_ctx->frame_csp - 1; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index cebd47eea2..e46283abbe 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -3232,6 +3232,17 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, u8 = read_uint8(p); /* 0x00 */ break; +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_TRY: + case WASM_OP_CATCH: + case WASM_OP_THROW: + case WASM_OP_RETHROW: + case WASM_OP_DELEGATE: + case WASM_OP_CATCH_ALL: + /* TODO */ + return false; +#endif + case WASM_OP_DROP: case WASM_OP_SELECT: case WASM_OP_DROP_64: @@ -6073,6 +6084,18 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, break; } +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_TRY: + case WASM_OP_CATCH: + case WASM_OP_THROW: + case WASM_OP_RETHROW: + case WASM_OP_DELEGATE: + case WASM_OP_CATCH_ALL: + /* TODO */ + set_error_buf(error_buf, error_buf_size, "unsupported opcode"); + goto fail; +#endif + case WASM_OP_DROP: { BranchBlock *cur_block = loader_ctx->frame_csp - 1; diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index cd7478a6b9..067deed826 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -21,10 +21,11 @@ typedef enum WASMOpcode { WASM_OP_IF = 0x04, /* if */ WASM_OP_ELSE = 0x05, /* else */ - WASM_OP_UNUSED_0x06 = 0x06, - WASM_OP_UNUSED_0x07 = 0x07, - WASM_OP_UNUSED_0x08 = 0x08, - WASM_OP_UNUSED_0x09 = 0x09, + WASM_OP_TRY = 0x06, /* try */ + WASM_OP_CATCH = 0x07, /* catch */ + WASM_OP_THROW = 0x08, /* throw */ + WASM_OP_RETHROW = 0x09, /* rethrow */ + WASM_OP_UNUSED_0x0a = 0x0a, WASM_OP_END = 0x0b, /* end */ @@ -41,8 +42,9 @@ typedef enum WASMOpcode { WASM_OP_UNUSED_0x15 = 0x15, WASM_OP_UNUSED_0x16 = 0x16, WASM_OP_UNUSED_0x17 = 0x17, - WASM_OP_UNUSED_0x18 = 0x18, - WASM_OP_UNUSED_0x19 = 0x19, + + WASM_OP_DELEGATE = 0x18, /* delegate */ + WASM_OP_CATCH_ALL = 0x19, /* catch_all */ /* parametric instructions */ WASM_OP_DROP = 0x1a, /* drop */ @@ -694,10 +696,10 @@ typedef enum WASMAtomicEXTOpcode { HANDLE_OPCODE(WASM_OP_LOOP), /* 0x03 */ \ HANDLE_OPCODE(WASM_OP_IF), /* 0x04 */ \ HANDLE_OPCODE(WASM_OP_ELSE), /* 0x05 */ \ - HANDLE_OPCODE(WASM_OP_UNUSED_0x06), /* 0x06 */ \ - HANDLE_OPCODE(WASM_OP_UNUSED_0x07), /* 0x07 */ \ - HANDLE_OPCODE(WASM_OP_UNUSED_0x08), /* 0x08 */ \ - HANDLE_OPCODE(WASM_OP_UNUSED_0x09), /* 0x09 */ \ + HANDLE_OPCODE(WASM_OP_TRY), /* 0x06 */ \ + HANDLE_OPCODE(WASM_OP_CATCH), /* 0x07 */ \ + HANDLE_OPCODE(WASM_OP_THROW), /* 0x08 */ \ + HANDLE_OPCODE(WASM_OP_RETHROW), /* 0x09 */ \ HANDLE_OPCODE(WASM_OP_UNUSED_0x0a), /* 0x0a */ \ HANDLE_OPCODE(WASM_OP_END), /* 0x0b */ \ HANDLE_OPCODE(WASM_OP_BR), /* 0x0c */ \ @@ -712,8 +714,8 @@ typedef enum WASMAtomicEXTOpcode { HANDLE_OPCODE(WASM_OP_UNUSED_0x15), /* 0x15 */ \ HANDLE_OPCODE(WASM_OP_UNUSED_0x16), /* 0x16 */ \ HANDLE_OPCODE(WASM_OP_UNUSED_0x17), /* 0x17 */ \ - HANDLE_OPCODE(WASM_OP_UNUSED_0x18), /* 0x18 */ \ - HANDLE_OPCODE(WASM_OP_UNUSED_0x19), /* 0x19 */ \ + HANDLE_OPCODE(WASM_OP_DELEGATE), /* 0x18 */ \ + HANDLE_OPCODE(WASM_OP_CATCH_ALL), /* 0x19 */ \ HANDLE_OPCODE(WASM_OP_DROP), /* 0x1a */ \ HANDLE_OPCODE(WASM_OP_SELECT), /* 0x1b */ \ HANDLE_OPCODE(WASM_OP_SELECT_T), /* 0x1c */ \ From 8bebfe9ad75695a2390d2db6ccbef8ba5350da34 Mon Sep 17 00:00:00 2001 From: Chris Woods <6069113+woodsmc@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:46:45 -0500 Subject: [PATCH 2/3] Add initial support for WASM exceptions (#2382) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds the initial support for WASM exceptions, it is an initial contribution, as part 1 of 2 contributions. Refer to: https://github.com/bytecodealliance/wasm-micro-runtime/pull/2382 ### Included in this contribution * Inside the classic interpreter only: * Initial handling of Tags * Initial handling of Exceptions based on W3C Exception Proposal * Add `cmake -DWAMR_BUILD_EXCE_HANDLING=1/0` option to enable/disable   the feature, and update the wamr-test-suites scripts to test the feature. ### To be included in Part 2 * Inside the classic interpreter only: * Bug fixes and naming convention improvements * Additional CI /CD changes to validate ENABLE_EXCE_HANDLING switch builds OK on all platforms * Import and Export of Exceptions and Tags Signed-off-by: Chris Woods Co-authored-by: Ricardo Aguilar Co-authored-by: Rene Ermler  --- build-scripts/config_common.cmake | 1 + core/config.h | 4 + core/iwasm/interpreter/wasm.h | 70 +++ core/iwasm/interpreter/wasm_interp.h | 8 + core/iwasm/interpreter/wasm_interp_classic.c | 533 +++++++++++++++++- core/iwasm/interpreter/wasm_interp_fast.c | 4 +- core/iwasm/interpreter/wasm_loader.c | 527 ++++++++++++++++- core/iwasm/interpreter/wasm_opcode.h | 19 +- product-mini/platforms/nuttx/wamr.mk | 8 + .../wamr-test-suites/spec-test-script/all.py | 40 +- .../spec-test-script/runtest.py | 50 ++ tests/wamr-test-suites/test_wamr.sh | 96 +++- 12 files changed, 1303 insertions(+), 57 deletions(-) diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index eaedcc671d..2e94c9afa7 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -319,6 +319,7 @@ else () endif () if (WAMR_BUILD_EXCE_HANDLING EQUAL 1) add_definitions (-DWASM_ENABLE_EXCE_HANDLING=1) + add_definitions (-DWASM_ENABLE_TAGS=1) message (" Exception Handling enabled") endif () if (DEFINED WAMR_BH_VPRINTF) diff --git a/core/config.h b/core/config.h index 120149b9b7..c63de091f9 100644 --- a/core/config.h +++ b/core/config.h @@ -445,6 +445,10 @@ #define WASM_ENABLE_EXCE_HANDLING 0 #endif +#ifndef WASM_ENABLE_TAGS +#define WASM_ENABLE_TAGS 0 +#endif + #ifndef WASM_ENABLE_SGX_IPFS #define WASM_ENABLE_SGX_IPFS 0 #endif diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index c7d9f1de9b..9b2dd10828 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -14,6 +14,13 @@ 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 @@ -65,6 +72,9 @@ extern "C" { #if WASM_ENABLE_BULK_MEMORY != 0 #define SECTION_TYPE_DATACOUNT 12 #endif +#if WASM_ENABLE_TAGS != 0 +#define SECTION_TYPE_TAG 13 +#endif #define SUB_SECTION_TYPE_MODULE 0 #define SUB_SECTION_TYPE_FUNC 1 @@ -74,20 +84,34 @@ extern "C" { #define IMPORT_KIND_TABLE 1 #define IMPORT_KIND_MEMORY 2 #define IMPORT_KIND_GLOBAL 3 +#if WASM_ENABLE_TAGS != 0 +#define IMPORT_KIND_TAG 4 +#endif #define EXPORT_KIND_FUNC 0 #define EXPORT_KIND_TABLE 1 #define EXPORT_KIND_MEMORY 2 #define EXPORT_KIND_GLOBAL 3 +#if WASM_ENABLE_TAGS != 0 +#define EXPORT_KIND_TAG 4 +#endif #define LABEL_TYPE_BLOCK 0 #define LABEL_TYPE_LOOP 1 #define LABEL_TYPE_IF 2 #define LABEL_TYPE_FUNCTION 3 +#if WASM_ENABLE_EXCE_HANDLING != 0 +#define LABEL_TYPE_TRY 4 +#define LABEL_TYPE_CATCH 5 +#define LABEL_TYPE_CATCH_ALL 6 +#endif typedef struct WASMModule WASMModule; typedef struct WASMFunction WASMFunction; typedef struct WASMGlobal WASMGlobal; +#if WASM_ENABLE_TAGS != 0 +typedef struct WASMTag WASMTag; +#endif typedef union V128 { int8 i8x16[16]; @@ -197,6 +221,21 @@ typedef struct WASMFunctionImport { bool call_conv_wasm_c_api; } WASMFunctionImport; +#if WASM_ENABLE_TAGS != 0 +typedef struct WASMTagImport { + uint8 attribute; /* the type of the tag (numerical) */ + uint32 type; /* the type of the catch function (numerical)*/ + WASMType *tag_type; + uint32 tag_index_linked; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* imported function pointer after linked */ + /* TODO: remove if not needed */ + WASMModule *import_module; + WASMTag *import_tag_linked; +#endif +} WASMTagImport; +#endif + typedef struct WASMGlobalImport { char *module_name; char *field_name; @@ -223,6 +262,9 @@ typedef struct WASMImport { WASMFunctionImport function; WASMTableImport table; WASMMemoryImport memory; +#if WASM_ENABLE_TAGS != 0 + WASMTagImport tag; +#endif WASMGlobalImport global; struct { char *module_name; @@ -261,6 +303,10 @@ struct WASMFunction { uint32 const_cell_num; #endif +#if WASM_ENABLE_EXCE_HANDLING != 0 + uint32 exception_handler_count; +#endif + #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ || WASM_ENABLE_WAMR_COMPILER != 0 /* Whether function has opcode memory.grow */ @@ -290,6 +336,13 @@ struct WASMFunction { #endif }; +#if WASM_ENABLE_TAGS != 0 +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) */ +}; +#endif + struct WASMGlobal { uint8 type; bool is_mutable; @@ -417,6 +470,9 @@ struct WASMModule { uint32 function_count; uint32 table_count; uint32 memory_count; +#if WASM_ENABLE_TAGS != 0 + uint32 tag_count; +#endif uint32 global_count; uint32 export_count; uint32 table_seg_count; @@ -430,11 +486,17 @@ struct WASMModule { uint32 import_function_count; uint32 import_table_count; uint32 import_memory_count; +#if WASM_ENABLE_TAGS != 0 + uint32 import_tag_count; +#endif uint32 import_global_count; WASMImport *import_functions; WASMImport *import_tables; WASMImport *import_memories; +#if WASM_ENABLE_TAGS != 0 + WASMImport *import_tags; +#endif WASMImport *import_globals; WASMType **types; @@ -442,6 +504,9 @@ struct WASMModule { WASMFunction **functions; WASMTable *tables; WASMMemory *memories; +#if WASM_ENABLE_TAGS != 0 + WASMTag *tags; +#endif WASMGlobal *globals; WASMExport *exports; WASMTableSeg *table_segments; @@ -625,6 +690,11 @@ typedef struct WASMBranchBlock { uint8 *target_addr; uint32 *frame_sp; uint32 cell_num; +#if WASM_ENABLE_EXCE_HANDLING != 0 + /* in exception handling, label_type needs to be stored to lookup exception + * handlers */ + uint8 label_type; +#endif } WASMBranchBlock; /** diff --git a/core/iwasm/interpreter/wasm_interp.h b/core/iwasm/interpreter/wasm_interp.h index d3692ff21b..2b5a51ea8e 100644 --- a/core/iwasm/interpreter/wasm_interp.h +++ b/core/iwasm/interpreter/wasm_interp.h @@ -34,6 +34,14 @@ typedef struct WASMInterpFrame { uint64 time_started; #endif +#if WASM_ENABLE_EXCE_HANDLING != 0 + /* set to true if the callee returns an exception rather than + * result values on the stack + */ + bool exception_raised; + uint32 tag_index; +#endif + #if WASM_ENABLE_FAST_INTERP != 0 /* Return offset of the first return value of current frame, the callee will put return values here continuously */ diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 286ccf585e..87fa7477cb 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -338,10 +338,19 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) frame_sp += 2; \ } while (0) +/* in exception handling, label_type needs to be stored to lookup exception + * handlers */ + +#if WASM_ENABLE_EXCE_HANDLING != 0 +#define SET_LABEL_TYPE(_label_type) frame_csp->label_type = _label_type +#else +#define SET_LABEL_TYPE(_label_type) (void)0 +#endif + #define PUSH_CSP(_label_type, param_cell_num, cell_num, _target_addr) \ do { \ bh_assert(frame_csp < frame->csp_boundary); \ - /* frame_csp->label_type = _label_type; */ \ + SET_LABEL_TYPE(_label_type); \ frame_csp->cell_num = cell_num; \ frame_csp->begin_addr = frame_ip; \ frame_csp->target_addr = _target_addr; \ @@ -392,6 +401,18 @@ read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) frame_sp -= n; \ } while (0) +#if WASM_ENABLE_EXCE_HANDLING != 0 +/* unwind the CSP to a given label and optionally modify the labeltype */ +#define UNWIND_CSP(N, T) \ + do { \ + /* unwind to function frame */ \ + frame_csp -= N; \ + /* drop handlers and values pushd in try block */ \ + frame_sp = (frame_csp - 1)->frame_sp; \ + (frame_csp - 1)->label_type = T ? T : (frame_csp - 1)->label_type; \ + } while (0) +#endif + #define SYNC_ALL_TO_FRAME() \ do { \ frame->sp = frame_sp; \ @@ -1184,6 +1205,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; uint32 cache_index, type_index, param_cell_num, cell_num; +#if WASM_ENABLE_EXCE_HANDLING != 0 + int32_t exception_tag_index; +#endif uint8 value_type; #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 @@ -1226,6 +1250,404 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_NOP) { HANDLE_OP_END(); } +#if WASM_ENABLE_EXCE_HANDLING != 0 + + HANDLE_OP(WASM_OP_RETHROW) + { + int32_t relative_depth; + read_leb_int32(frame_ip, frame_ip_end, relative_depth); + + /* No frame found with exception handler; validation should + * catch it */ + bh_assert(frame_csp >= frame->csp_bottom + relative_depth); + + /* go up the frame stack */ + WASMBranchBlock *tgtframe = (frame_csp - 1) - relative_depth; + + bh_assert(tgtframe->label_type == LABEL_TYPE_CATCH + || tgtframe->label_type == LABEL_TYPE_CATCH_ALL); + + /* tgtframe points to the frame containing a thrown + * exception */ + + uint32 *tgtframe_sp = tgtframe->frame_sp; + + /* frame sp of tgtframe points to catched exception */ + exception_tag_index = *((uint32 *)tgtframe_sp); + tgtframe_sp++; + + /* get tag type */ + uint8 tag_type_index = + module->module->tags[exception_tag_index].type; + uint32 cell_num_to_copy = + wasm_types[tag_type_index]->param_cell_num; + + /* move exception parameters (if there are any) onto top + * of stack */ + if (cell_num_to_copy > 0) { + word_copy(frame_sp, tgtframe_sp - cell_num_to_copy, + cell_num_to_copy); + } + + frame_sp += cell_num_to_copy; + goto find_a_catch_handler; + } + + HANDLE_OP(WASM_OP_THROW) + { + read_leb_int32(frame_ip, frame_ip_end, exception_tag_index); + + /* landig pad for the rethrow ? */ + find_a_catch_handler: + { + /* browse through frame stack */ + uint32 relative_depth = 0; + do { + POP_CSP_CHECK_OVERFLOW(relative_depth - 1); + WASMBranchBlock *tgtframe = frame_csp - relative_depth - 1; + + switch (tgtframe->label_type) { + case LABEL_TYPE_BLOCK: + case LABEL_TYPE_IF: + case LABEL_TYPE_LOOP: + case LABEL_TYPE_CATCH: + case LABEL_TYPE_CATCH_ALL: + /* + * skip that blocks in search + * BLOCK, IF and LOOP do not contain handlers and + * 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 + */ + break; + case LABEL_TYPE_TRY: + { + uint32 handler_number = 0; + uint8 **handlers = (uint8 **)tgtframe->frame_sp; + uint8 *handler = NULL; + while ((handler = handlers[handler_number]) != 0) { + uint8 handler_opcode = *handler; + uint8 *target_addr = + handler + + 1; /* first instruction or leb-immediate + behind the handler opcode */ + switch (handler_opcode) { + case WASM_OP_CATCH: + { + int32 lookup_index = 0; + /* read the tag_index and advance + * target_addr to the first instruction + * in the block */ + read_leb_int32(target_addr, 0, + lookup_index); + + if (exception_tag_index + == lookup_index) { + /* set ip */ + frame_ip = target_addr; + /* save frame_sp (points to + * exception values) */ + uint32 *frame_sp_old = frame_sp; + + 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); + } + 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); + } + frame_sp += cell_num_to_copy; + + /* advance to handler */ + HANDLE_OP_END(); + } + break; + } + case WASM_OP_DELEGATE: + { + int32 lookup_depth = 0; + /* read the depth */ + read_leb_int32(target_addr, 0, + lookup_depth); + + /* save frame_sp (points to exception + * values) */ + uint32 *frame_sp_old = frame_sp; + + UNWIND_CSP(relative_depth, + LABEL_TYPE_CATCH); + + /* leave the block (the delegate is + * technically not inside the frame) */ + frame_csp--; + + /* 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); + } + frame_sp += cell_num_to_copy; + + /* tag_index is already stored in + * exception_tag_index */ + goto find_a_catch_handler; + } + case WASM_OP_CATCH_ALL: + { + /* no immediate */ + /* save frame_sp (points to exception + * values) */ + uint32 *frame_sp_old = frame_sp; + /* set ip */ + frame_ip = target_addr; + + UNWIND_CSP(relative_depth, + LABEL_TYPE_CATCH_ALL); + + /* 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; + } + /* catch_all has no exception values */ + + /* advance to handler */ + HANDLE_OP_END(); + } + default: + wasm_set_exception( + module, "WASM_OP_THROW found " + "unexpected handler type"); + goto got_exception; + } + + handler_number++; + } + /* exception not catched in this frame */ + break; + } + case LABEL_TYPE_FUNCTION: + { + /* save frame_sp (points to exception values) */ + 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); + } + prev_frame->sp += cell_num_to_copy; + *((int32 *)(prev_frame->sp)) = exception_tag_index; + (int32 *)(prev_frame->sp++); + + /* mark frame as raised exception */ + wasm_set_exception(module, + "uncaught wasm exception"); + + /* end of function, treat as WASM_OP_RETURN */ + goto return_func; + } + default: + wasm_set_exception( + module, + "unexpected or invalid label in THROW or " + "RETHROW when searching a catch handler"); + goto got_exception; + } + + relative_depth++; + + } while (1); + } + + /* something went wrong. normally, we should always find the + * func label. if not, stop the interpreter */ + wasm_set_exception( + module, "WASM_OP_THROW hit the bottom of the frame stack"); + goto got_exception; + } + + HANDLE_OP(EXT_OP_TRY) + { + /* read the blocktype */ + read_leb_uint32(frame_ip, frame_ip_end, type_index); + param_cell_num = wasm_types[type_index]->param_cell_num; + cell_num = wasm_types[type_index]->ret_cell_num; + goto handle_op_try; + } + + HANDLE_OP(WASM_OP_TRY) + { + value_type = *frame_ip++; + param_cell_num = 0; + cell_num = wasm_value_type_cell_num(value_type); + + handle_op_try: + + cache_index = ((uintptr_t)frame_ip) + & (uintptr_t)(BLOCK_ADDR_CACHE_SIZE - 1); + cache_items = exec_env->block_addr_cache[cache_index]; + if (cache_items[0].start_addr == frame_ip) { + cache_items[0].start_addr = 0; + } + if (cache_items[1].start_addr == frame_ip) { + cache_items[1].start_addr = 0; + } + + /* start at the first opcode following the try and its blocktype + */ + uint8 *lookup_cursor = frame_ip; + uint8 handler_opcode = WASM_OP_UNREACHABLE; + + /* target_addr filled in when END or DELEGATE is found */ + PUSH_CSP(LABEL_TYPE_TRY, param_cell_num, cell_num, 0); + + /* reset to begin of block */ + lookup_cursor = frame_ip; + do { + /* lookup the next CATCH, CATCH_ALL or END for this TRY */ + if (!wasm_loader_find_block_addr( + exec_env, (BlockAddr *)exec_env->block_addr_cache, + lookup_cursor, (uint8 *)-1, LABEL_TYPE_TRY, + &else_addr, &end_addr)) { + /* something went wrong */ + wasm_set_exception(module, "find block address failed"); + goto got_exception; + } + + /* place cursor for continuation past opcode */ + lookup_cursor = end_addr + 1; + + /* end_addr points to CATCH, CATCH_ALL, DELEGATE or END */ + handler_opcode = *end_addr; + switch (handler_opcode) { + case WASM_OP_CATCH: + skip_leb(lookup_cursor); /* skip tag_index */ + PUSH_I64(end_addr); + break; + case WASM_OP_CATCH_ALL: + PUSH_I64(end_addr); + break; + case WASM_OP_DELEGATE: + skip_leb(lookup_cursor); /* skip depth */ + PUSH_I64(end_addr); + /* patch target_addr */ + (frame_csp - 1)->target_addr = lookup_cursor; + break; + case WASM_OP_END: + PUSH_I64(0); + /* patch target_addr */ + (frame_csp - 1)->target_addr = end_addr; + break; + default: + /* something went wrong */ + wasm_set_exception(module, + "find block address returned an " + "unexpected opcode"); + goto got_exception; + } + /* ... search until the returned address is the END of the + * TRY block */ + } while (handler_opcode != WASM_OP_END + && handler_opcode != WASM_OP_DELEGATE); + /* handler setup on stack complete */ + + HANDLE_OP_END(); + } + HANDLE_OP(WASM_OP_CATCH) + { + /* skip the tag_index */ + skip_leb(frame_ip); + /* leave the frame */ + POP_CSP_N(0); + HANDLE_OP_END(); + } + HANDLE_OP(WASM_OP_CATCH_ALL) + { + /* leave the frame */ + POP_CSP_N(0); + HANDLE_OP_END(); + } + HANDLE_OP(WASM_OP_DELEGATE) + { + /* skip the delegate depth */ + skip_leb(frame_ip); + /* leave the frame like WASM_OP_END */ + POP_CSP(); + HANDLE_OP_END(); + } +#endif HANDLE_OP(EXT_OP_BLOCK) { read_leb_uint32(frame_ip, frame_ip_end, type_index); @@ -1544,20 +1966,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto call_func_from_interp; } -#if WASM_ENABLE_EXCE_HANDLING != 0 - HANDLE_OP(WASM_OP_TRY) - HANDLE_OP(WASM_OP_CATCH) - HANDLE_OP(WASM_OP_THROW) - HANDLE_OP(WASM_OP_RETHROW) - HANDLE_OP(WASM_OP_DELEGATE) - HANDLE_OP(WASM_OP_CATCH_ALL) - { - /* TODO */ - wasm_set_exception(module, "unsupported opcode"); - goto got_exception; - } -#endif - /* parametric instructions */ HANDLE_OP(WASM_OP_DROP) { @@ -3845,6 +4253,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_RETHROW) HANDLE_OP(WASM_OP_DELEGATE) HANDLE_OP(WASM_OP_CATCH_ALL) + HANDLE_OP(EXT_OP_TRY) #endif HANDLE_OP(WASM_OP_UNUSED_0x14) HANDLE_OP(WASM_OP_UNUSED_0x15) @@ -3900,6 +4309,50 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (cur_func->import_func_inst) { wasm_interp_call_func_import(module, exec_env, cur_func, prev_frame); +#if WASM_ENABLE_EXCE_HANDLING != 0 + char uncaught_exception[128] = { 0 }; + bool has_exception = + wasm_copy_exception(module, uncaught_exception); + if (has_exception + && strstr(uncaught_exception, "uncaught wasm exception")) { + /* fix framesp */ + UPDATE_ALL_FROM_FRAME(); + + uint32 import_exception = + 0xFFFFFFFF; /* initialize imported exception index to be + invalid */ + /* 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); + + /* 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)) { + /* set the import_exception to the import tag */ + import_exception = import_tag_index; + break; + } + } + /* + * push the internal exception index to stack, + * or 0xffffffff in case, the external exception + * is not in the import list + */ + PUSH_I32(import_exception); + } +#endif } else #endif @@ -3920,19 +4373,57 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (memory) linear_mem_size = memory->memory_data_size; #endif - if (wasm_copy_exception(module, NULL)) + if (wasm_copy_exception(module, NULL)) { +#if WASM_ENABLE_EXCE_HANDLING != 0 + /* the caller raised an exception */ + char uncaught_exception[128] = { 0 }; + bool has_exception = + wasm_copy_exception(module, uncaught_exception); + + /* libc_builtin signaled a "exception thrown by stdc++" trap */ + if (has_exception + && strstr(uncaught_exception, + "exception thrown by stdc++")) { + wasm_set_exception(module, NULL); + + /* setup internal c++ rethrow */ + exception_tag_index = 0; + goto find_a_catch_handler; + } + + /* when throw hits the end of a function it signalles with a + * "uncaught wasm exception" trap */ + if (has_exception + && strstr(uncaught_exception, "uncaught wasm exception")) { + wasm_set_exception(module, NULL); + exception_tag_index = POP_I32(); + + /* rethrow the exception into that frame */ + goto find_a_catch_handler; + } +#endif goto got_exception; + } } else { WASMFunction *cur_wasm_func = cur_func->u.func; WASMType *func_type; +#if WASM_ENABLE_EXCE_HANDLING != 0 + /* account for exception handlers */ + /* bundle them here */ + uint32 eh_size = + cur_wasm_func->exception_handler_count * sizeof(uint8 *); + cur_wasm_func->max_stack_cell_num += eh_size; +#endif + func_type = cur_wasm_func->func_type; all_cell_num = cur_func->param_cell_num + cur_func->local_cell_num + cur_wasm_func->max_stack_cell_num + cur_wasm_func->max_block_num * (uint32)sizeof(WASMBranchBlock) / 4; + /* param_cell_num, local_cell_num, max_stack_cell_num and max_block_num are all no larger than UINT16_MAX (checked in loader), all_cell_num must be smaller than 1MB */ @@ -3981,11 +4472,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, FREE_FRAME(exec_env, frame); wasm_exec_env_set_cur_frame(exec_env, prev_frame); - if (!prev_frame->ip) + if (!prev_frame->ip) { /* Called from native. */ return; + } RECOVER_CONTEXT(prev_frame); +#if WASM_ENABLE_EXCE_HANDLING != 0 + if (wasm_get_exception(module)) { + wasm_set_exception(module, NULL); + exception_tag_index = POP_I32(); + goto find_a_catch_handler; + } +#endif HANDLE_OP_END(); } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index b98e2cd4ca..e3374271d2 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1425,8 +1425,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_RETHROW) HANDLE_OP(WASM_OP_DELEGATE) HANDLE_OP(WASM_OP_CATCH_ALL) + HANDLE_OP(EXT_OP_TRY) { - /* TODO */ wasm_set_exception(module, "unsupported opcode"); goto got_exception; } @@ -3684,12 +3684,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_REF_FUNC) #endif #if WASM_ENABLE_EXCE_HANDLING == 0 + /* if exception handling is disabled, these opcodes issue a trap */ HANDLE_OP(WASM_OP_TRY) HANDLE_OP(WASM_OP_CATCH) HANDLE_OP(WASM_OP_THROW) HANDLE_OP(WASM_OP_RETHROW) HANDLE_OP(WASM_OP_DELEGATE) HANDLE_OP(WASM_OP_CATCH_ALL) + HANDLE_OP(EXT_OP_TRY) #endif /* SELECT_T is converted to SELECT or SELECT_64 */ HANDLE_OP(WASM_OP_SELECT_T) diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index c74e87bf2c..61ccf8e28b 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1386,6 +1386,99 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, return false; } +#if WASM_ENABLE_TAGS != 0 +static bool +load_tag_import(const uint8 **p_buf, const uint8 *buf_end, + const WASMModule *parent_module, /* this module ! */ + const char *sub_module_name, const char *tag_name, + WASMTagImport *tag, /* structure to fill */ + char *error_buf, uint32 error_buf_size) +{ + WASMExport *export = 0; + WASMModule *sub_module = NULL; + +#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; + uint32 i; + + 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]; +#if WASM_ENABLE_MULTI_MODULE != 0 + tag->import_module = (WASMModule *)module_reg; + tag->import_tag_linked = &sub_module->tags[export->index]; +#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) { + set_error_buf(error_buf, error_buf_size, "unknown tag attribute"); + goto fail; + } + + /* get type */ + read_leb_uint32(p, p_end, tag_type); + /* compare against module->types */ + if (tag_type >= 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) { + set_error_buf(error_buf, error_buf_size, + "tag type signature does not return void"); + + goto fail; + } + + /* store to module tag declarations */ + tag->attribute = tag_attribute; + tag->type = tag_type; + + *p_buf = p; + (void)parent_module; + + LOG_VERBOSE("Load tag import success\n"); + return true; + +fail: + return false; +} +#endif + static bool load_global_import(const uint8 **p_buf, const uint8 *buf_end, const WASMModule *parent_module, char *sub_module_name, @@ -1598,6 +1691,9 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, WASMImport *import; WASMImport *import_functions = NULL, *import_tables = NULL; WASMImport *import_memories = NULL, *import_globals = NULL; +#if WASM_ENABLE_TAGS != 0 + WASMImport *import_tags = NULL; +#endif char *sub_module_name, *field_name; uint8 u8, kind; @@ -1626,7 +1722,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p += name_len; CHECK_BUF(p, p_end, 1); - /* 0x00/0x01/0x02/0x03 */ + /* 0x00/0x01/0x02/0x03/0x04 */ kind = read_uint8(p); switch (kind) { @@ -1667,6 +1763,16 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } break; +#if WASM_ENABLE_TAGS != 0 + case IMPORT_KIND_TAG: /* import tags */ + /* it only counts the number of tags to import */ + module->import_tag_count++; + CHECK_BUF(p, p_end, 1); + u8 = read_uint8(p); + read_leb_uint32(p, p_end, type_index); + break; +#endif + case IMPORT_KIND_GLOBAL: /* import global */ CHECK_BUF(p, p_end, 2); p += 2; @@ -1689,10 +1795,23 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, import_memories = module->import_memories = module->imports + module->import_function_count + module->import_table_count; + +#if WASM_ENABLE_TAGS != 0 + if (module->import_tag_count) + import_tags = module->import_tags = + module->imports + module->import_function_count + + module->import_table_count + module->import_memory_count; + if (module->import_global_count) + import_globals = module->import_globals = + module->imports + module->import_function_count + + module->import_table_count + module->import_memory_count + + module->import_tag_count; +#else if (module->import_global_count) import_globals = module->import_globals = module->imports + module->import_function_count + module->import_table_count + module->import_memory_count; +#endif p = p_old; @@ -1719,7 +1838,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, p += name_len; CHECK_BUF(p, p_end, 1); - /* 0x00/0x01/0x02/0x03 */ + /* 0x00/0x01/0x02/0x03/0x4 */ kind = read_uint8(p); switch (kind) { @@ -1755,6 +1874,18 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } break; +#if WASM_ENABLE_TAGS != 0 + case IMPORT_KIND_TAG: + bh_assert(import_tags); + import = import_tags++; + if (!load_tag_import(&p, p_end, module, sub_module_name, + field_name, &import->u.tag, error_buf, + error_buf_size)) { + return false; + } + break; +#endif + case IMPORT_KIND_GLOBAL: /* import global */ bh_assert(import_globals); import = import_globals++; @@ -2266,6 +2397,16 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } break; +#if WASM_ENABLE_TAGS != 0 + /* export tag */ + case EXPORT_KIND_TAG: + if (index >= module->tag_count + module->import_tag_count) { + set_error_buf(error_buf, error_buf_size, "unknown tag"); + return false; + } + break; +#endif + /* global index */ case EXPORT_KIND_GLOBAL: if (index @@ -2275,6 +2416,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return false; } break; + default: set_error_buf(error_buf, error_buf_size, "invalid export kind"); @@ -2681,6 +2823,75 @@ load_datacount_section(const uint8 *buf, const uint8 *buf_end, } #endif +#if WASM_ENABLE_TAGS != 0 +static bool +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__); + 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; + + /* get tag count */ + read_leb_uint32(p, p_end, section_tag_count); + module->tag_count = module->import_tag_count + section_tag_count; + + if (section_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++) { + + /* get the one byte attribute */ + CHECK_BUF(p, p_end, 1); + tag_attribute = read_uint8(p); + + /* get type */ + read_leb_uint32(p, p_end, tag_type); + /* compare against module->types */ + if (tag_type >= module->type_count) { + set_error_buf(error_buf, error_buf_size, "unknown type"); + return false; + } + + /* get return type (must be 0) */ + /* check, that the type of the referred tag returns void */ + WASMType *func_type = (WASMType *)module->types[tag_type]; + if (func_type->result_count != 0) { + set_error_buf(error_buf, error_buf_size, + "non-empty tag result type"); + + goto fail; + } + + /* store to module tag declarations */ + module->tags[tag_index].attribute = tag_attribute; + module->tags[tag_index].type = tag_type; + } + } + + if (p != p_end) { + set_error_buf(error_buf, error_buf_size, "section size mismatch"); + return false; + } + + LOG_VERBOSE("Load tag section success.\n"); + return true; +fail: + return false; +} +#endif + static bool load_code_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_func, const uint8 *buf_func_end, WASMModule *module, @@ -3471,6 +3682,14 @@ load_from_sections(WASMModule *module, WASMSection *sections, error_buf_size)) return false; break; +#if WASM_ENABLE_TAGS != 0 + case SECTION_TYPE_TAG: + /* load tag declaration section */ + if (!load_tag_section(buf, buf_end, buf_code, buf_code_end, + module, error_buf, error_buf_size)) + return false; + break; +#endif case SECTION_TYPE_GLOBAL: if (!load_global_section(buf, buf_end, module, error_buf, error_buf_size)) @@ -3940,6 +4159,9 @@ static uint8 section_ids[] = { SECTION_TYPE_FUNC, SECTION_TYPE_TABLE, SECTION_TYPE_MEMORY, +#if WASM_ENABLE_TAGS != 0 + SECTION_TYPE_TAG, +#endif SECTION_TYPE_GLOBAL, SECTION_TYPE_EXPORT, SECTION_TYPE_START, @@ -4490,6 +4712,64 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_NOP: break; +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_TRY: + u8 = read_uint8(p); + if (block_nested_depth + < sizeof(block_stack) / sizeof(BlockAddr)) { + block_stack[block_nested_depth].start_addr = p; + block_stack[block_nested_depth].else_addr = NULL; + } + block_nested_depth++; + break; + case EXT_OP_TRY: + skip_leb_uint32(p, p_end); + if (block_nested_depth + < sizeof(block_stack) / sizeof(BlockAddr)) { + block_stack[block_nested_depth].start_addr = p; + block_stack[block_nested_depth].else_addr = NULL; + } + block_nested_depth++; + break; + case WASM_OP_CATCH: + if (block_nested_depth == 1) { + *p_end_addr = (uint8 *)(p - 1); + /* stop search and return the address of the catch block */ + return true; + } + break; + case WASM_OP_CATCH_ALL: + if (block_nested_depth == 1) { + *p_end_addr = (uint8 *)(p - 1); + /* stop search and return the address of the catch_all block + */ + return true; + } + break; + case WASM_OP_THROW: + /* skip tag_index */ + skip_leb(p); + break; + case WASM_OP_RETHROW: + /* skip depth */ + skip_leb(p); + break; + case WASM_OP_DELEGATE: + if (block_nested_depth == 1) { + *p_end_addr = (uint8 *)(p - 1); + return true; + } + else { + /* the DELEGATE opcode ends the tryblock, */ + block_nested_depth--; + if (block_nested_depth + < sizeof(block_stack) / sizeof(BlockAddr)) + block_stack[block_nested_depth].end_addr = + (uint8 *)(p - 1); + } + break; +#endif + case WASM_OP_BLOCK: case WASM_OP_LOOP: case WASM_OP_IF: @@ -4612,17 +4892,6 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, u8 = read_uint8(p); /* 0x00 */ break; -#if WASM_ENABLE_EXCE_HANDLING != 0 - case WASM_OP_TRY: - case WASM_OP_CATCH: - case WASM_OP_THROW: - case WASM_OP_RETHROW: - case WASM_OP_DELEGATE: - case WASM_OP_CATCH_ALL: - /* TODO */ - return false; -#endif - case WASM_OP_DROP: case WASM_OP_SELECT: case WASM_OP_DROP_64: @@ -5369,6 +5638,10 @@ wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size) goto fail; loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8; +#if WASM_ENABLE_EXCE_HANDLING != 0 + func->exception_handler_count = 0; +#endif + #if WASM_ENABLE_FAST_INTERP != 0 loader_ctx->frame_offset_size = sizeof(int16) * 32; if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset = @@ -6982,9 +7255,25 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block, /* 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 */ + snprintf( + error_buf, error_buf_size, "type mismatch: %s requires [%s]%s[%s]", + block->label_type == LABEL_TYPE_TRY + || (block->label_type == LABEL_TYPE_CATCH + && return_cell_num > 0) + ? "instruction" + : "block", + return_cell_num > 0 ? type2str(return_types[0]) : "", + " but stack has ", + available_stack_cell > 0 ? type2str(*(loader_ctx->frame_ref - 1)) + : ""); + goto fail; +#else set_error_buf(error_buf, error_buf_size, "type mismatch: stack size does not match block type"); goto fail; +#endif } /* Check stack values match return types */ @@ -7298,6 +7587,24 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, goto handle_op_block_and_loop; case WASM_OP_BLOCK: case WASM_OP_LOOP: +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_TRY: + if (opcode == WASM_OP_TRY) { + /* + * keep track of exception handlers to account for + * memory allocation + */ + func->exception_handler_count++; + + /* + * try is a block + * do nothing special, but execution continues to + * to handle_op_block_and_loop, + * and that be pushes the csp + */ + } + +#endif #if WASM_ENABLE_FAST_INTERP != 0 PRESERVE_LOCAL_FOR_BLOCK(); #endif @@ -7349,7 +7656,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_TYPE( wasm_type->types[wasm_type->param_count - i - 1]); } - PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK), block_type, p); @@ -7363,6 +7669,11 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (opcode == WASM_OP_BLOCK) { skip_label(); } +#if WASM_ENABLE_EXCE_HANDLING != 0 + else if (opcode == WASM_OP_TRY) { + skip_label(); + } +#endif else if (opcode == WASM_OP_LOOP) { skip_label(); if (BLOCK_HAS_PARAM(block_type)) { @@ -7430,7 +7741,182 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, #endif break; } +#if WASM_ENABLE_EXCE_HANDLING != 0 + case WASM_OP_THROW: + { + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + + uint8 label_type = cur_block->label_type; + uint32 tag_index = 0; + read_leb_int32(p, p_end, tag_index); + + /* 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"); + 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; + } + + /* 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) { + set_error_buf(error_buf, error_buf_size, + "tag type signature does not return void"); + goto fail; + } + + /* throw is stack polymorphic */ + (void)label_type; + RESET_STACK(); + + break; + } + case WASM_OP_RETHROW: + { + /* must be done before checking branch block */ + SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); + + /* check the target catching block: LABEL_TYPE_CATCH */ + if (!(frame_csp_tmp = check_branch_block( + loader_ctx, &p, p_end, error_buf, error_buf_size))) + goto fail; + + if (frame_csp_tmp->label_type != LABEL_TYPE_CATCH + && frame_csp_tmp->label_type != LABEL_TYPE_CATCH_ALL) { + /* trap according to spectest (rethrow.wast) */ + set_error_buf(error_buf, error_buf_size, + "invalid rethrow label"); + goto fail; + } + + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + uint8 label_type = cur_block->label_type; + (void)label_type; + /* rethrow is stack polymorphic */ + RESET_STACK(); + break; + } + case WASM_OP_DELEGATE: + { + /* check target block is valid */ + if (!(frame_csp_tmp = check_branch_block( + loader_ctx, &p, p_end, error_buf, error_buf_size))) + goto fail; + + /* valid types */ + if (LABEL_TYPE_TRY != frame_csp_tmp->label_type) { + snprintf(error_buf, error_buf_size, "unknown label"); + goto fail; + } + + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + uint8 label_type = cur_block->label_type; + + (void)label_type; + /* DELEGATE ends the block */ + POP_CSP(); + break; + } + case WASM_OP_CATCH: + { + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + + uint8 label_type = cur_block->label_type; + uint32 tag_index = 0; + read_leb_int32(p, p_end, tag_index); + + /* 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"); + 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; + } + + /* 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"); + goto fail; + } + + /* check validity of current label (expect LABEL_TYPE_TRY or + * LABEL_TYPE_CATCH) */ + if ((LABEL_TYPE_CATCH != label_type) + && (LABEL_TYPE_TRY != label_type)) { + set_error_buf(error_buf, error_buf_size, + "Unexpected block sequence encountered."); + goto fail; + } + + BlockType new_block_type; + new_block_type.is_value_type = false; + new_block_type.u.type = module->types[tag_type_index]; + + /* + * replace frame_csp by LABEL_TYPE_CATCH + */ + cur_block->label_type = LABEL_TYPE_CATCH; + + /* RESET_STACK removes the values pushed in TRY or pervious + * CATCH Blocks */ + RESET_STACK(); + + /* push types on the stack according to catched type */ + if (BLOCK_HAS_PARAM(new_block_type)) { + for (i = 0; i < new_block_type.u.type->param_count; i++) + PUSH_TYPE(new_block_type.u.type->types[i]); + } + break; + } + case WASM_OP_CATCH_ALL: + { + BranchBlock *cur_block = loader_ctx->frame_csp - 1; + + /* expecting a TRY or CATCH, anything else will be considered an + * error */ + if ((LABEL_TYPE_CATCH != cur_block->label_type) + && (LABEL_TYPE_TRY != cur_block->label_type)) { + set_error_buf(error_buf, error_buf_size, + "Unexpected block sequence encountered."); + goto fail; + } + + /* no immediates */ + /* replace frame_csp by LABEL_TYPE_CATCH_ALL */ + cur_block->label_type = LABEL_TYPE_CATCH_ALL; + + /* RESET_STACK removes the values pushed in TRY or pervious + * CATCH Blocks */ + RESET_STACK(); + + /* catch_all has no tagtype and therefore no parameters */ + break; + } +#endif case WASM_OP_ELSE: { BlockType block_type = (loader_ctx->frame_csp - 1)->block_type; @@ -7898,19 +8384,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, break; } -#if WASM_ENABLE_EXCE_HANDLING != 0 - case WASM_OP_TRY: - case WASM_OP_CATCH: - case WASM_OP_THROW: - case WASM_OP_RETHROW: - case WASM_OP_DELEGATE: - case WASM_OP_CATCH_ALL: - /* TODO */ - set_error_buf_v(error_buf, error_buf_size, "%s %02x", - "unsupported opcode", opcode); - goto fail; -#endif - case WASM_OP_DROP: { BranchBlock *cur_block = loader_ctx->frame_csp - 1; diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 287a570c7f..808677c7a7 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -20,12 +20,10 @@ typedef enum WASMOpcode { WASM_OP_LOOP = 0x03, /* loop */ WASM_OP_IF = 0x04, /* if */ WASM_OP_ELSE = 0x05, /* else */ - - WASM_OP_TRY = 0x06, /* try */ - WASM_OP_CATCH = 0x07, /* catch */ - WASM_OP_THROW = 0x08, /* throw */ - WASM_OP_RETHROW = 0x09, /* rethrow */ - + WASM_OP_TRY = 0x06, /* try */ + WASM_OP_CATCH = 0x07, /* catch* */ + WASM_OP_THROW = 0x08, /* throw of a try catch */ + WASM_OP_RETHROW = 0x09, /* rethrow of a try catch */ WASM_OP_UNUSED_0x0a = 0x0a, WASM_OP_END = 0x0b, /* end */ @@ -43,8 +41,8 @@ typedef enum WASMOpcode { WASM_OP_UNUSED_0x16 = 0x16, WASM_OP_UNUSED_0x17 = 0x17, - WASM_OP_DELEGATE = 0x18, /* delegate */ - WASM_OP_CATCH_ALL = 0x19, /* catch_all */ + WASM_OP_DELEGATE = 0x18, /* delegate block of the try catch*/ + WASM_OP_CATCH_ALL = 0x19, /* a catch_all handler in a try block */ /* parametric instructions */ WASM_OP_DROP = 0x1a, /* drop */ @@ -270,8 +268,10 @@ typedef enum WASMOpcode { EXT_OP_IF = 0xd5, /* if with blocktype */ EXT_OP_BR_TABLE_CACHE = 0xd6, /* br_table from cache */ + EXT_OP_TRY = 0xd7, /* try block with blocktype */ + #if WASM_ENABLE_DEBUG_INTERP != 0 - DEBUG_OP_BREAK = 0xd7, /* debug break point */ + DEBUG_OP_BREAK = 0xd8, /* debug break point */ #endif /* Post-MVP extend op prefix */ @@ -907,6 +907,7 @@ typedef enum WASMAtomicEXTOpcode { HANDLE_OPCODE(EXT_OP_LOOP), /* 0xd4 */ \ HANDLE_OPCODE(EXT_OP_IF), /* 0xd5 */ \ HANDLE_OPCODE(EXT_OP_BR_TABLE_CACHE), /* 0xd6 */ \ + HANDLE_OPCODE(EXT_OP_TRY), /* 0xd7 */ \ SET_GOTO_TABLE_ELEM(WASM_OP_MISC_PREFIX), /* 0xfc */ \ SET_GOTO_TABLE_ELEM(WASM_OP_ATOMIC_PREFIX), /* 0xfe */ \ DEF_DEBUG_BREAK_HANDLE() \ diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 04a6db91fd..d46a17fae7 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -338,6 +338,14 @@ else CFLAGS += -DWASM_ENABLE_REF_TYPES=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_ENABLE_EXCE_HANDLING),y) +CFLAGS += -DWASM_ENABLE_EXCE_HANDLING=1 +CFLAGS += -DWASM_ENABLE_TAGS=1 +else +CFLAGS += -DWASM_ENABLE_EXCE_HANDLING=0 +CFLAGS += -DWASM_ENABLE_TAGS=0 +endif + CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 44b0a14bdc..7892f77b6f 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -68,7 +68,15 @@ def ignore_the_case( gc_flag=False, xip_flag=False, qemu_flag=False, + eh_flag=False, ): + # print(f"case_name {case_name}\n") + if eh_flag and case_name in [ "tag", "try_catch", "rethrow", "try_delegate" ]: + return False + else: + return True + + if case_name in ["comments", "inline-module", "names"]: return True @@ -115,7 +123,11 @@ def ignore_the_case( return False -def preflight_check(aot_flag): +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 @@ -140,6 +152,7 @@ def test_case( multi_thread_flag=False, simd_flag=False, xip_flag=False, + eh_flag=False, clean_up_flag=True, verbose_flag=True, gc_flag=False, @@ -147,6 +160,7 @@ def test_case( qemu_firmware="", log="", ): + CMD = ["python3", "runtest.py"] CMD.append("--wast2wasm") CMD.append(WAST2WASM_CMD if not gc_flag else SPEC_INTERPRETER_CMD) @@ -181,6 +195,9 @@ def test_case( if xip_flag: CMD.append("--xip") + if eh_flag: + CMD.append("--eh") + if qemu_flag: CMD.append("--qemu") CMD.append("--qemu-firmware") @@ -253,6 +270,7 @@ def test_suite( multi_thread_flag=False, simd_flag=False, xip_flag=False, + eh_flag=False, clean_up_flag=True, verbose_flag=True, gc_flag=False, @@ -261,6 +279,10 @@ def test_suite( qemu_firmware="", log="", ): + 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}") @@ -290,6 +312,7 @@ def test_suite( gc_flag, xip_flag, qemu_flag, + eh_flag, ): filtered_case_list.append(case_path) print(f"---> {len(case_list)} --filter--> {len(filtered_case_list)}") @@ -315,6 +338,7 @@ def test_suite( multi_thread_flag, simd_flag, xip_flag, + eh_flag, clean_up_flag, verbose_flag, gc_flag, @@ -352,6 +376,7 @@ def test_suite( multi_thread_flag, simd_flag, xip_flag, + eh_flag, clean_up_flag, verbose_flag, gc_flag, @@ -411,6 +436,14 @@ def main(): dest="xip_flag", help="Running with the XIP feature", ) + # added to support WASM_ENABLE_EXCE_HANDLING + parser.add_argument( + "-e", + action="store_true", + default=False, + dest="eh_flag", + help="Running with the exception-handling feature", + ) parser.add_argument( "-t", action="store_true", @@ -483,7 +516,8 @@ def main(): options = parser.parse_args() print(options) - if not preflight_check(options.aot_flag): + + if not preflight_check(options.aot_flag, options.eh_flag): return False if not options.cases: @@ -502,6 +536,7 @@ def main(): options.multi_thread_flag, options.simd_flag, options.xip_flag, + options.eh_flag, options.clean_up_flag, options.verbose_flag, options.gc_flag, @@ -526,6 +561,7 @@ def main(): options.multi_thread_flag, options.simd_flag, options.xip_flag, + options.eh_flag, options.clean_up_flag, options.verbose_flag, options.gc_flag, diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index a1e505bd04..c2c599b028 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -224,6 +224,9 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result): parser.add_argument('--xip', default=False, action='store_true', help="Enable XIP") +parser.add_argument('--eh', default=False, action='store_true', + help="Enable Exception Handling") + parser.add_argument('--multi-module', default=False, action='store_true', help="Enable Multi-thread") @@ -692,6 +695,13 @@ def test_assert(r, opts, mode, cmd, expected): if o.find(e) >= 0 or e.find(o) >= 0: return True + # wasm-exception thrown out of function call, not a trap + if mode=='wasmexception': + o = re.sub('^Exception: ', '', out) + e = re.sub('^Exception: ', '', expected) + if o.find(e) >= 0 or e.find(o) >= 0: + return True + ## 0x9:i32,-0x1:i32 -> ['0x9:i32', '-0x1:i32'] expected_list = re.split(',', expected) out_list = re.split(',', out) @@ -917,6 +927,42 @@ def test_assert_exhaustion(r,opts,form): expected = "Exception: %s\n" % m.group(3) test_assert(r, opts, "exhaustion", "%s %s" % (func, " ".join(args)), expected) + +# added to support WASM_ENABLE_EXCE_HANDLING +def test_assert_wasmexception(r,opts,form): + # params + + # ^ + # \(assert_exception\s+ + # \(invoke\s+"([^"]+)"\s+ + # (\(.*\))\s* + # () + # \)\s* + # \)\s* + # $ + m = re.search('^\(assert_exception\s+\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*\)\s*$', form) + if not m: + # no params + + # ^ + # \(assert_exception\s+ + # \(invoke\s+"([^"]+)"\s* + # () + # \)\s* + # \)\s* + # $ + m = re.search('^\(assert_exception\s+\(invoke\s+"([^"]+)"\s*()\)\s*\)\s*$', form) + if not m: + raise Exception("unparsed assert_exception: '%s'" % form) + func = m.group(1) # function name + if m.group(2) == '': # arguments + args = [] + else: + args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m.group(2)[1:-1])] + + expected = "Exception: uncaught wasm exception\n" + test_assert(r, opts, "wasmexception", "%s %s" % (func, " ".join(args)), expected) + def do_invoke(r, opts, form): # params m = re.search('^\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*$', form) @@ -954,6 +1000,8 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): # default arguments if opts.gc: cmd = [opts.wast2wasm, "-u", "-d", wast_tempfile, "-o", wasm_tempfile] + elif opts.eh: + cmd = [opts.wast2wasm, "--enable-thread", "--no-check", "--enable-exceptions", "--enable-tail-call", wast_tempfile, "-o", wasm_tempfile ] else: cmd = [opts.wast2wasm, "--enable-thread", "--no-check", wast_tempfile, "-o", wasm_tempfile ] @@ -1168,6 +1216,8 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r) elif re.match("^\(assert_exhaustion\\b.*", form): test_assert_exhaustion(r, opts, form) + elif re.match("^\(assert_exception\\b.*", form): + test_assert_wasmexception(r, opts, form) elif re.match("^\(assert_unlinkable\\b.*", form): test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r, False) elif re.match("^\(assert_malformed\\b.*", form): diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 11650651c3..1154e5868f 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -22,6 +22,8 @@ function help() echo "-S enable SIMD feature" echo "-G enable GC feature" echo "-X enable XIP feature" + # added to support WASM_ENABLE_EXCE_HANDLING + echo "-e enable exception handling" echo "-x test SGX" echo "-w enable WASI threads" echo "-b use the wabt binary release package instead of compiling from the source code" @@ -46,6 +48,7 @@ COLLECT_CODE_COVERAGE=0 ENABLE_SIMD=0 ENABLE_GC=0 ENABLE_XIP=0 +ENABLE_EH=0 ENABLE_DEBUG_VERSION=0 ENABLE_GC_HEAP_VERIFY=0 #unit test case arrary @@ -58,7 +61,7 @@ QEMU_FIRMWARE="" # prod/testsuite-all branch WASI_TESTSUITE_COMMIT="cf64229727f71043d5849e73934e249e12cb9e06" -while getopts ":s:cabgvt:m:MCpSXxwPGQF:" opt +while getopts ":s:cabgvt:m:MCpSXexwPGQF:" opt do OPT_PARSED="TRUE" case $opt in @@ -133,6 +136,10 @@ do echo "enable XIP feature" ENABLE_XIP=1 ;; + e) + echo "enable exception handling feature" + ENABLE_EH=1 + ;; x) echo "test SGX" SGX_OPT="--sgx" @@ -487,6 +494,88 @@ 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" @@ -755,6 +844,11 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_WASI_THREADS=1" fi + 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 if [[ "$WAMR_BUILD_SANITIZER" == "ubsan" ]]; then From 59bccdfed82178c39ea4e14295ceb24289b3b857 Mon Sep 17 00:00:00 2001 From: Ricardo Aguilar <139989759+raguilar755@users.noreply.github.com> Date: Mon, 20 Nov 2023 23:27:43 -0700 Subject: [PATCH 3/3] PR2 Exception Handling Support (#2785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR continues the work from #2382 and updates the exception handling support: * Inside the classic interpreter only:   * Bug fixes and naming convention improvements   * Import and Export of Exceptions and Tags   * Remove the dependency on multi-module   * Additional CI /CD changes to validate ENABLE_EXCE_HANDLING switch builds      OK on all platforms Refer to https://github.com/bytecodealliance/wasm-micro-runtime/issues/1884. Signed-off-by: Ricardo Aguilar Co-authored-by: Chris Woods Co-authored-by: Rene Ermler Co-authored-by: Trenner Thomas --- core/iwasm/interpreter/wasm.h | 19 +- core/iwasm/interpreter/wasm_interp_classic.c | 163 +++++------ core/iwasm/interpreter/wasm_loader.c | 262 ++++++++++++------ core/iwasm/interpreter/wasm_runtime.c | 183 +++++++++++- core/iwasm/interpreter/wasm_runtime.h | 49 ++++ .../wamr-test-suites/spec-test-script/all.py | 28 +- .../spec-test-script/exception_handling.patch | 20 ++ tests/wamr-test-suites/test_wamr.sh | 107 ++----- 8 files changed, 540 insertions(+), 291 deletions(-) create mode 100644 tests/wamr-test-suites/spec-test-script/exception_handling.patch 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