mirror of
				https://github.com/bytecodealliance/wasm-micro-runtime.git
				synced 2025-10-31 13:17:31 +00:00 
			
		
		
		
	Implement Exception Handling for classic interpreter (#3096)
This PR adds the initial support for WASM exception handling: * Inside the classic interpreter only: * Initial handling of Tags * Initial handling of Exceptions based on W3C Exception Proposal * Import and Export of Exceptions and Tags * Add `cmake -DWAMR_BUILD_EXCE_HANDLING=1/0` option to enable/disable the feature, and by default it is disabled * Update the wamr-test-suites scripts to test the feature * Additional CI/CD changes to validate the exception spec proposal cases Refer to: https://github.com/bytecodealliance/wasm-micro-runtime/issues/1884587513f3c68bebfe9ad759bccdfed8Signed-off-by: Ricardo Aguilar <ricardoaguilar@siemens.com> Co-authored-by: Chris Woods <chris.woods@siemens.com> Co-authored-by: Rene Ermler <rene.ermler@siemens.com> Co-authored-by: Trenner Thomas <trenner.thomas@siemens.com>
This commit is contained in:
		
							parent
							
								
									7e65f9a244
								
							
						
					
					
						commit
						af318bac81
					
				|  | @ -335,6 +335,11 @@ 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) | ||||
|   add_definitions (-DWASM_ENABLE_TAGS=1) | ||||
|   message ("     Exception Handling enabled") | ||||
| endif () | ||||
| if (DEFINED WAMR_BH_VPRINTF) | ||||
|   add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF}) | ||||
| endif () | ||||
|  |  | |||
|  | @ -457,6 +457,14 @@ | |||
| #define WASM_ENABLE_REF_TYPES 0 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WASM_ENABLE_EXCE_HANDLING | ||||
| #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 | ||||
|  |  | |||
|  | @ -65,6 +65,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 +77,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]; | ||||
|  | @ -201,6 +218,24 @@ typedef struct WASMFunctionImport { | |||
|     bool call_conv_wasm_c_api; | ||||
| } 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; | ||||
|     void *tag_ptr_linked; | ||||
| 
 | ||||
| #if WASM_ENABLE_MULTI_MODULE != 0 | ||||
|     /* imported tag  pointer after linked */ | ||||
|     WASMModule *import_module; | ||||
|     WASMTag *import_tag_linked; | ||||
|     uint32 import_tag_index_linked; | ||||
| #endif | ||||
| } WASMTagImport; | ||||
| #endif | ||||
| 
 | ||||
| typedef struct WASMGlobalImport { | ||||
|     char *module_name; | ||||
|     char *field_name; | ||||
|  | @ -227,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; | ||||
|  | @ -265,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 */ | ||||
|  | @ -294,6 +336,14 @@ 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) */ | ||||
|     WASMType *tag_type; | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| struct WASMGlobal { | ||||
|     uint8 type; | ||||
|     bool is_mutable; | ||||
|  | @ -420,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; | ||||
|  | @ -433,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; | ||||
|  | @ -445,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; | ||||
|  | @ -628,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; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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;   \ | ||||
|  | @ -1188,6 +1209,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 | ||||
|  | @ -1230,6 +1254,379 @@ 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); | ||||
| 
 | ||||
|             /* 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 { | ||||
|                     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); | ||||
| 
 | ||||
|                                             /* push exception_tag_index and
 | ||||
|                                              * exception values for rethrow */ | ||||
|                                             PUSH_I32(exception_tag_index); | ||||
|                                             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
 | ||||
|                                              */ | ||||
|                                             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; | ||||
| 
 | ||||
|                                         /* push exception values for catch */ | ||||
|                                         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); | ||||
|                                         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); | ||||
|                             /* push exception values for catch
 | ||||
|                              * The values are copied to the CALLER FRAME | ||||
|                              * (prev_frame->sp) same behvior ad WASM_OP_RETURN | ||||
|                              */ | ||||
|                             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; | ||||
|                             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); | ||||
|  | @ -3814,10 +4211,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) | ||||
|  | @ -3834,6 +4227,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | |||
|         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) | ||||
|         HANDLE_OP(EXT_OP_TRY) | ||||
| #endif | ||||
| #if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SIMD != 0 | ||||
|         /* SIMD isn't supported by interpreter, but when JIT is
 | ||||
|            enabled, `iwasm --interp <wasm_file>` may be run to | ||||
|  | @ -3844,8 +4246,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) | ||||
|         /* Used by fast interpreter */ | ||||
|         HANDLE_OP(EXT_OP_SET_LOCAL_FAST_I64) | ||||
|  | @ -3896,6 +4296,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; | ||||
|                     /* initialize imported exception index to be invalid */ | ||||
|                     SET_INVALID_TAGINDEX(import_exception); | ||||
| 
 | ||||
|                     /* pull external exception */ | ||||
|                     uint32 ext_exception = POP_I32(); | ||||
| 
 | ||||
|                     /* external function came back with an exception or trap */ | ||||
|                     /* lookup exception in import tags */ | ||||
|                     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 ((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 = t; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     /*
 | ||||
|                      * 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); | ||||
|                 } | ||||
| #endif | ||||
|             } | ||||
|             else | ||||
| #endif | ||||
|  | @ -3916,19 +4360,57 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | |||
|             if (memory) | ||||
|                 linear_mem_size = get_linear_mem_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 */ | ||||
|  | @ -3977,11 +4459,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(); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1437,6 +1437,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) | ||||
|             HANDLE_OP(EXT_OP_TRY) | ||||
|             { | ||||
|                 wasm_set_exception(module, "unsupported opcode"); | ||||
|                 goto got_exception; | ||||
|             } | ||||
| #endif | ||||
| 
 | ||||
|             /* parametric instructions */ | ||||
|             HANDLE_OP(WASM_OP_SELECT) | ||||
|             { | ||||
|  | @ -3670,10 +3684,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) | ||||
|  | @ -3688,6 +3698,16 @@ 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 | ||||
|         /* 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) | ||||
|  | @ -3695,8 +3715,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) | ||||
|  |  | |||
|  | @ -707,7 +707,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 | ||||
|  | @ -898,6 +897,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 | ||||
|  | @ -1237,6 +1288,89 @@ fail: | |||
|     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) | ||||
| { | ||||
|     /* 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 | ||||
|     WASMModule *sub_module = NULL; | ||||
| #endif | ||||
| 
 | ||||
|     /* get the one byte attribute */ | ||||
|     CHECK_BUF(p, p_end, 1); | ||||
|     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, declare_type_index); | ||||
|     /* compare against module->types */ | ||||
|     if (declare_type_index >= parent_module->type_count) { | ||||
|         set_error_buf(error_buf, error_buf_size, "unknown tag type"); | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     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 = 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; | ||||
| 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, | ||||
|  | @ -1458,6 +1592,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; | ||||
| 
 | ||||
|  | @ -1486,7 +1623,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) { | ||||
|  | @ -1527,6 +1664,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; | ||||
|  | @ -1549,10 +1696,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; | ||||
| 
 | ||||
|  | @ -1579,7 +1739,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) { | ||||
|  | @ -1615,6 +1775,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++; | ||||
|  | @ -2126,6 +2298,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 | ||||
|  | @ -2135,6 +2317,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"); | ||||
|  | @ -2541,6 +2724,83 @@ fail: | |||
| } | ||||
| #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) | ||||
| { | ||||
|     (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 = 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 = 0; tag_index < section_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; | ||||
|             } | ||||
| 
 | ||||
|             if (!(tag = module->tags[tag_index] = loader_malloc( | ||||
|                       sizeof(WASMTag), error_buf, error_buf_size))) { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             /* store to module tag declarations */ | ||||
|             tag->attribute = tag_attribute; | ||||
|             tag->type = tag_type; | ||||
|             tag->tag_type = func_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, | ||||
|  | @ -3336,6 +3596,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)) | ||||
|  | @ -3805,6 +4073,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, | ||||
|  | @ -4210,6 +4481,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); | ||||
| 
 | ||||
|  | @ -4350,6 +4631,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: | ||||
|  | @ -5221,6 +5560,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 = | ||||
|  | @ -6832,11 +7175,26 @@ 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 */ | ||||
|         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 */ | ||||
|  | @ -7185,6 +7543,24 @@ re_scan: | |||
|             } | ||||
|             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 | ||||
|  | @ -7258,7 +7634,6 @@ re_scan: | |||
|                             wasm_type->types[wasm_type->param_count - i - 1]); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK), | ||||
|                          block_type, p); | ||||
| 
 | ||||
|  | @ -7291,6 +7666,11 @@ re_scan: | |||
|                             loader_ctx->p_code_compiled; | ||||
|                     } | ||||
|                 } | ||||
| #if WASM_ENABLE_EXCE_HANDLING != 0 | ||||
|                 else if (opcode == WASM_OP_TRY) { | ||||
|                     skip_label(); | ||||
|                 } | ||||
| #endif | ||||
|                 else if (opcode == WASM_OP_IF) { | ||||
|                     BranchBlock *block = loader_ctx->frame_csp - 1; | ||||
|                     /* If block has parameters, we should make sure they are in
 | ||||
|  | @ -7351,7 +7731,212 @@ re_scan: | |||
| #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->import_tag_count + module->tag_count) { | ||||
|                     snprintf(error_buf, error_buf_size, "unknown tag %d", | ||||
|                              tag_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; | ||||
|                 } | ||||
| 
 | ||||
|                 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(); | ||||
| 
 | ||||
|                 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->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 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; | ||||
|                 } | ||||
| 
 | ||||
|                 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 = func_type; | ||||
| 
 | ||||
|                 /*
 | ||||
|                  * 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: | ||||
|             { | ||||
|                 BranchBlock *block = NULL; | ||||
|  |  | |||
|  | @ -3259,6 +3259,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: | ||||
|  | @ -6173,6 +6184,18 @@ re_scan: | |||
|                 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; | ||||
|  |  | |||
|  | @ -20,11 +20,10 @@ typedef enum WASMOpcode { | |||
|     WASM_OP_LOOP = 0x03,        /* loop */ | ||||
|     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 of a try catch */ | ||||
|     WASM_OP_RETHROW = 0x09,     /* rethrow of a try catch */ | ||||
|     WASM_OP_UNUSED_0x0a = 0x0a, | ||||
| 
 | ||||
|     WASM_OP_END = 0x0b,                  /* end */ | ||||
|  | @ -41,8 +40,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 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 */ | ||||
|  | @ -268,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 */ | ||||
|  | @ -703,10 +705,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 */ \ | ||||
|  | @ -721,8 +723,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 */ \ | ||||
|  | @ -912,6 +914,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_SIMD_PREFIX_ELEM()            /* 0xfd */ \ | ||||
|         SET_GOTO_TABLE_ELEM(WASM_OP_ATOMIC_PREFIX),  /* 0xfe */ \ | ||||
|  |  | |||
|  | @ -732,6 +732,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. | ||||
|  */ | ||||
|  | @ -931,6 +1026,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) | ||||
|  | @ -1720,6 +1861,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); | ||||
|  | @ -1728,11 +1872,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, | ||||
|  | @ -1748,6 +1896,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( | ||||
|  | @ -1765,7 +1922,6 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, | |||
|     ) { | ||||
|         goto fail; | ||||
|     } | ||||
| 
 | ||||
|     if (global_count > 0) { | ||||
|         /* Initialize the global data */ | ||||
|         global_data = module_inst->global_data; | ||||
|  | @ -2188,8 +2344,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 | ||||
|  | @ -2270,6 +2434,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 | ||||
|  |  | |||
|  | @ -28,6 +28,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 | ||||
|  | @ -191,6 +194,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; | ||||
|  | @ -211,6 +238,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 */ | ||||
|  | @ -263,6 +297,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 | ||||
|  | @ -461,6 +503,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 | ||||
|  |  | |||
|  | @ -359,6 +359,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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -47,6 +47,7 @@ IWASM_CMD = get_iwasm_cmd(PLATFORM_NAME) | |||
| IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm" | ||||
| IWASM_QEMU_CMD = "iwasm" | ||||
| SPEC_TEST_DIR = "spec/test/core" | ||||
| EXCE_HANDLING_DIR = "exception-handling/test/core" | ||||
| WAST2WASM_CMD = exe_file_path("./wabt/out/gcc/Release/wat2wasm") | ||||
| SPEC_INTERPRETER_CMD = "spec/interpreter/wasm" | ||||
| WAMRC_CMD = "../../../wamr-compiler/build/wamrc" | ||||
|  | @ -78,8 +79,10 @@ def ignore_the_case( | |||
|     simd_flag=False, | ||||
|     gc_flag=False, | ||||
|     xip_flag=False, | ||||
|     eh_flag=False, | ||||
|     qemu_flag=False, | ||||
| ): | ||||
| 
 | ||||
|     if case_name in ["comments", "inline-module", "names"]: | ||||
|         return True | ||||
| 
 | ||||
|  | @ -126,7 +129,7 @@ def ignore_the_case( | |||
|     return False | ||||
| 
 | ||||
| 
 | ||||
| def preflight_check(aot_flag): | ||||
| def preflight_check(aot_flag, eh_flag): | ||||
|     if not pathlib.Path(SPEC_TEST_DIR).resolve().exists(): | ||||
|         print(f"Can not find {SPEC_TEST_DIR}") | ||||
|         return False | ||||
|  | @ -139,6 +142,10 @@ def preflight_check(aot_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 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -151,6 +158,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, | ||||
|  | @ -195,6 +203,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") | ||||
|  | @ -268,6 +279,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, | ||||
|  | @ -291,6 +303,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: | ||||
|  | @ -305,6 +326,7 @@ def test_suite( | |||
|             simd_flag, | ||||
|             gc_flag, | ||||
|             xip_flag, | ||||
|             eh_flag, | ||||
|             qemu_flag, | ||||
|         ): | ||||
|             filtered_case_list.append(case_path) | ||||
|  | @ -331,6 +353,7 @@ def test_suite( | |||
|                         multi_thread_flag, | ||||
|                         simd_flag, | ||||
|                         xip_flag, | ||||
|                         eh_flag, | ||||
|                         clean_up_flag, | ||||
|                         verbose_flag, | ||||
|                         gc_flag, | ||||
|  | @ -369,6 +392,7 @@ def test_suite( | |||
|                     multi_thread_flag, | ||||
|                     simd_flag, | ||||
|                     xip_flag, | ||||
|                     eh_flag, | ||||
|                     clean_up_flag, | ||||
|                     verbose_flag, | ||||
|                     gc_flag, | ||||
|  | @ -428,6 +452,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", | ||||
|  | @ -508,7 +540,7 @@ def main(): | |||
|     if options.target == "x86_32": | ||||
|         options.target = "i386" | ||||
| 
 | ||||
|     if not preflight_check(options.aot_flag): | ||||
|     if not preflight_check(options.aot_flag, options.eh_flag): | ||||
|         return False | ||||
| 
 | ||||
|     if not options.cases: | ||||
|  | @ -527,6 +559,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, | ||||
|  | @ -552,6 +585,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, | ||||
|  |  | |||
|  | @ -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)))") | ||||
|  | @ -301,6 +301,9 @@ parser.add_argument('--simd', default=False, action='store_true', | |||
| 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") | ||||
| 
 | ||||
|  | @ -762,6 +765,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) | ||||
|  | @ -987,6 +997,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) | ||||
|  | @ -1025,6 +1071,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 ] | ||||
|  | @ -1236,6 +1284,8 @@ if __name__ == "__main__": | |||
|                 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): | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ function help() | |||
|     echo "-S enable SIMD feature" | ||||
|     echo "-G enable GC feature" | ||||
|     echo "-X enable XIP feature" | ||||
|     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" | ||||
|  | @ -50,6 +51,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 | ||||
|  | @ -70,7 +72,7 @@ WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2" | |||
| TARGET_LIST=("AARCH64" "AARCH64_VFP" "ARMV7" "ARMV7_VFP" "THUMBV7" "THUMBV7_VFP" \ | ||||
|              "RISCV32" "RISCV32_ILP32F" "RISCV32_ILP32D" "RISCV64" "RISCV64_LP64F" "RISCV64_LP64D") | ||||
| 
 | ||||
| while getopts ":s:cabgvt:m:MCpSXxwPGQF:j:T:" opt | ||||
| while getopts ":s:cabgvt:m:MCpSXexwPGQF:j:T:" opt | ||||
| do | ||||
|     OPT_PARSED="TRUE" | ||||
|     case $opt in | ||||
|  | @ -145,6 +147,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" | ||||
|  | @ -425,6 +431,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" | ||||
|  | @ -463,6 +489,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 | ||||
|  | @ -827,6 +857,10 @@ 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" | ||||
|     fi | ||||
|     echo "SANITIZER IS" $WAMR_BUILD_SANITIZER | ||||
| 
 | ||||
|     if [[ "$WAMR_BUILD_SANITIZER" == "ubsan" ]]; then | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Wenyong Huang
						Wenyong Huang