mirror of
				https://github.com/bytecodealliance/wasm-micro-runtime.git
				synced 2025-10-30 12:51:16 +00:00 
			
		
		
		
	Fix data/elem drop (#2747)
Currently, `data.drop` instruction is implemented by directly modifying the underlying module. It breaks use cases where you have multiple instances sharing a single loaded module. `elem.drop` has the same problem too. This PR fixes the issue by keeping track of which data/elem segments have been dropped by using bitmaps for each module instances separately, and add a sample to demonstrate the issue and make the CI run it. Also add a missing check of dropped elements to the fast-jit `table.init`. Fixes: https://github.com/bytecodealliance/wasm-micro-runtime/issues/2735 Fixes: https://github.com/bytecodealliance/wasm-micro-runtime/issues/2772
This commit is contained in:
		
							parent
							
								
									08c0ec74c4
								
							
						
					
					
						commit
						562a5dd1b6
					
				|  | @ -444,6 +444,12 @@ jobs: | ||||||
|           cmake --build . --config Release --parallel 4 |           cmake --build . --config Release --parallel 4 | ||||||
|           ./iwasm wasm-apps/no_pthread.wasm |           ./iwasm wasm-apps/no_pthread.wasm | ||||||
| 
 | 
 | ||||||
|  |       - name: Build Sample [shared-module] | ||||||
|  |         run: | | ||||||
|  |           cd samples/shared-module | ||||||
|  |           ./build.sh | ||||||
|  |           ./run.sh | ||||||
|  | 
 | ||||||
|   test: |   test: | ||||||
|     needs: |     needs: | ||||||
|       [ |       [ | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								.github/workflows/compilation_on_macos.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/compilation_on_macos.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -327,3 +327,9 @@ jobs: | ||||||
|           cmake .. |           cmake .. | ||||||
|           cmake --build . --config Release --parallel 4 |           cmake --build . --config Release --parallel 4 | ||||||
|           ./iwasm wasm-apps/no_pthread.wasm |           ./iwasm wasm-apps/no_pthread.wasm | ||||||
|  | 
 | ||||||
|  |       - name: Build Sample [shared-module] | ||||||
|  |         run: | | ||||||
|  |           cd samples/shared-module | ||||||
|  |           ./build.sh | ||||||
|  |           ./run.sh | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								.github/workflows/nightly_run.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/nightly_run.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -501,6 +501,12 @@ jobs: | ||||||
|           cmake .. |           cmake .. | ||||||
|           cmake --build . --config Release --parallel 4 |           cmake --build . --config Release --parallel 4 | ||||||
|           ./iwasm wasm-apps/no_pthread.wasm |           ./iwasm wasm-apps/no_pthread.wasm | ||||||
|  | 
 | ||||||
|  |       - name: Build Sample [shared-module] | ||||||
|  |         run: | | ||||||
|  |           cd samples/shared-module | ||||||
|  |           ./build.sh | ||||||
|  |           ./run.sh | ||||||
|   test: |   test: | ||||||
|     needs: |     needs: | ||||||
|       [ |       [ | ||||||
|  |  | ||||||
|  | @ -1095,7 +1095,6 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, | ||||||
| 
 | 
 | ||||||
|         data_list[i]->mode = mode; |         data_list[i]->mode = mode; | ||||||
|         data_list[i]->elem_type = elem_type; |         data_list[i]->elem_type = elem_type; | ||||||
|         data_list[i]->is_dropped = false; |  | ||||||
|         data_list[i]->table_index = table_index; |         data_list[i]->table_index = table_index; | ||||||
|         data_list[i]->offset.init_expr_type = (uint8)init_expr_type; |         data_list[i]->offset.init_expr_type = (uint8)init_expr_type; | ||||||
|         data_list[i]->offset.u.i64 = (int64)init_expr_value; |         data_list[i]->offset.u.i64 = (int64)init_expr_value; | ||||||
|  |  | ||||||
|  | @ -1098,6 +1098,9 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, | ||||||
|                 char *error_buf, uint32 error_buf_size) |                 char *error_buf, uint32 error_buf_size) | ||||||
| { | { | ||||||
|     AOTModuleInstance *module_inst; |     AOTModuleInstance *module_inst; | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     WASMModuleInstanceExtraCommon *common; | ||||||
|  | #endif | ||||||
|     const uint32 module_inst_struct_size = |     const uint32 module_inst_struct_size = | ||||||
|         offsetof(AOTModuleInstance, global_table_data.bytes); |         offsetof(AOTModuleInstance, global_table_data.bytes); | ||||||
|     const uint64 module_inst_mem_inst_size = |     const uint64 module_inst_mem_inst_size = | ||||||
|  | @ -1164,6 +1167,32 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     common = &((AOTModuleInstanceExtra *)module_inst->e)->common; | ||||||
|  | #endif | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 | ||||||
|  |     if (module->mem_init_data_count > 0) { | ||||||
|  |         common->data_dropped = bh_bitmap_new(0, module->mem_init_data_count); | ||||||
|  |         if (common->data_dropped == NULL) { | ||||||
|  |             LOG_DEBUG("failed to allocate bitmaps"); | ||||||
|  |             set_error_buf(error_buf, error_buf_size, | ||||||
|  |                           "failed to allocate bitmaps"); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | #if WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     if (module->table_init_data_count > 0) { | ||||||
|  |         common->elem_dropped = bh_bitmap_new(0, module->table_init_data_count); | ||||||
|  |         if (common->elem_dropped == NULL) { | ||||||
|  |             LOG_DEBUG("failed to allocate bitmaps"); | ||||||
|  |             set_error_buf(error_buf, error_buf_size, | ||||||
|  |                           "failed to allocate bitmaps"); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     /* Initialize global info */ |     /* Initialize global info */ | ||||||
|     p = (uint8 *)module_inst + module_inst_struct_size |     p = (uint8 *)module_inst + module_inst_struct_size | ||||||
|         + module_inst_mem_inst_size; |         + module_inst_mem_inst_size; | ||||||
|  | @ -1264,6 +1293,8 @@ fail: | ||||||
| void | void | ||||||
| aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) | aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) | ||||||
| { | { | ||||||
|  |     WASMModuleInstanceExtraCommon *common = | ||||||
|  |         &((AOTModuleInstanceExtra *)module_inst->e)->common; | ||||||
|     if (module_inst->exec_env_singleton) { |     if (module_inst->exec_env_singleton) { | ||||||
|         /* wasm_exec_env_destroy will call
 |         /* wasm_exec_env_destroy will call
 | ||||||
|            wasm_cluster_wait_for_all_except_self to wait for other |            wasm_cluster_wait_for_all_except_self to wait for other | ||||||
|  | @ -1306,7 +1337,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) | ||||||
|     if (module_inst->func_type_indexes) |     if (module_inst->func_type_indexes) | ||||||
|         wasm_runtime_free(module_inst->func_type_indexes); |         wasm_runtime_free(module_inst->func_type_indexes); | ||||||
| 
 | 
 | ||||||
|     if (((AOTModuleInstanceExtra *)module_inst->e)->common.c_api_func_imports) |     if (common->c_api_func_imports) | ||||||
|         wasm_runtime_free(((AOTModuleInstanceExtra *)module_inst->e) |         wasm_runtime_free(((AOTModuleInstanceExtra *)module_inst->e) | ||||||
|                               ->common.c_api_func_imports); |                               ->common.c_api_func_imports); | ||||||
| 
 | 
 | ||||||
|  | @ -1317,6 +1348,13 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) | ||||||
|         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst); |         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 | ||||||
|  |     bh_bitmap_delete(common->data_dropped); | ||||||
|  | #endif | ||||||
|  | #if WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     bh_bitmap_delete(common->elem_dropped); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     wasm_runtime_free(module_inst); |     wasm_runtime_free(module_inst); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -2302,13 +2340,21 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, | ||||||
| { | { | ||||||
|     AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); |     AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); | ||||||
|     AOTModule *aot_module; |     AOTModule *aot_module; | ||||||
|     uint8 *data = NULL; |     uint8 *data; | ||||||
|     uint8 *maddr; |     uint8 *maddr; | ||||||
|     uint64 seg_len = 0; |     uint64 seg_len; | ||||||
| 
 | 
 | ||||||
|     aot_module = (AOTModule *)module_inst->module; |     if (bh_bitmap_get_bit( | ||||||
|     seg_len = aot_module->mem_init_data_list[seg_index]->byte_count; |             ((AOTModuleInstanceExtra *)module_inst->e)->common.data_dropped, | ||||||
|     data = aot_module->mem_init_data_list[seg_index]->bytes; |             seg_index)) { | ||||||
|  |         seg_len = 0; | ||||||
|  |         data = NULL; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         aot_module = (AOTModule *)module_inst->module; | ||||||
|  |         seg_len = aot_module->mem_init_data_list[seg_index]->byte_count; | ||||||
|  |         data = aot_module->mem_init_data_list[seg_index]->bytes; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst, |     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst, | ||||||
|                                         dst, len)) |                                         dst, len)) | ||||||
|  | @ -2331,9 +2377,9 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, | ||||||
| bool | bool | ||||||
| aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index) | aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index) | ||||||
| { | { | ||||||
|     AOTModule *aot_module = (AOTModule *)module_inst->module; |     bh_bitmap_set_bit( | ||||||
| 
 |         ((AOTModuleInstanceExtra *)module_inst->e)->common.data_dropped, | ||||||
|     aot_module->mem_init_data_list[seg_index]->byte_count = 0; |         seg_index); | ||||||
|     /* Currently we can't free the dropped data segment
 |     /* Currently we can't free the dropped data segment
 | ||||||
|        as the mem_init_data_count is a continuous array */ |        as the mem_init_data_count is a continuous array */ | ||||||
|     return true; |     return true; | ||||||
|  | @ -2546,9 +2592,9 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, | ||||||
| void | void | ||||||
| aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx) | aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx) | ||||||
| { | { | ||||||
|     AOTModule *module = (AOTModule *)module_inst->module; |     bh_bitmap_set_bit( | ||||||
|     AOTTableInitData *tbl_seg = module->table_init_data_list[tbl_seg_idx]; |         ((AOTModuleInstanceExtra *)module_inst->e)->common.elem_dropped, | ||||||
|     tbl_seg->is_dropped = true; |         tbl_seg_idx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
|  | @ -2576,7 +2622,9 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx, | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (tbl_seg->is_dropped) { |     if (bh_bitmap_get_bit( | ||||||
|  |             ((AOTModuleInstanceExtra *)module_inst->e)->common.elem_dropped, | ||||||
|  |             tbl_seg_idx)) { | ||||||
|         aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); |         aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -129,7 +129,6 @@ aot_create_table_init_data_list(const WASMModule *module) | ||||||
|         data_list[i]->mode = module->table_segments[i].mode; |         data_list[i]->mode = module->table_segments[i].mode; | ||||||
|         data_list[i]->elem_type = module->table_segments[i].elem_type; |         data_list[i]->elem_type = module->table_segments[i].elem_type; | ||||||
|         /* runtime control it */ |         /* runtime control it */ | ||||||
|         data_list[i]->is_dropped = false; |  | ||||||
|         data_list[i]->table_index = module->table_segments[i].table_index; |         data_list[i]->table_index = module->table_segments[i].table_index; | ||||||
|         bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr), |         bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr), | ||||||
|                     &module->table_segments[i].base_offset, |                     &module->table_segments[i].base_offset, | ||||||
|  |  | ||||||
|  | @ -143,7 +143,6 @@ typedef struct AOTTableInitData { | ||||||
|     uint32 mode; |     uint32 mode; | ||||||
|     /* funcref or externref, elemkind will be considered as funcref */ |     /* funcref or externref, elemkind will be considered as funcref */ | ||||||
|     uint32 elem_type; |     uint32 elem_type; | ||||||
|     bool is_dropped; |  | ||||||
|     /* optional, only for active */ |     /* optional, only for active */ | ||||||
|     uint32 table_index; |     uint32 table_index; | ||||||
|     /* Start address of init data */ |     /* Start address of init data */ | ||||||
|  |  | ||||||
|  | @ -269,7 +269,7 @@ static uint32 | ||||||
| get_table_init_data_size(AOTTableInitData *table_init_data) | get_table_init_data_size(AOTTableInitData *table_init_data) | ||||||
| { | { | ||||||
|     /*
 |     /*
 | ||||||
|      * mode (4 bytes), elem_type (4 bytes), do not need is_dropped field |      * mode (4 bytes), elem_type (4 bytes) | ||||||
|      * |      * | ||||||
|      * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 |      * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 | ||||||
|      * bytes) |      * bytes) | ||||||
|  |  | ||||||
|  | @ -650,6 +650,7 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx, | ||||||
|     WASMDataSeg *data_segment; |     WASMDataSeg *data_segment; | ||||||
|     uint32 mem_size; |     uint32 mem_size; | ||||||
|     uint8 *mem_addr, *data_addr; |     uint8 *mem_addr, *data_addr; | ||||||
|  |     uint32 seg_len; | ||||||
| 
 | 
 | ||||||
|     /* if d + n > the length of mem.data */ |     /* if d + n > the length of mem.data */ | ||||||
|     mem_inst = inst->memories[mem_idx]; |     mem_inst = inst->memories[mem_idx]; | ||||||
|  | @ -659,13 +660,19 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx, | ||||||
| 
 | 
 | ||||||
|     /* if s + n > the length of data.data */ |     /* if s + n > the length of data.data */ | ||||||
|     bh_assert(seg_idx < inst->module->data_seg_count); |     bh_assert(seg_idx < inst->module->data_seg_count); | ||||||
|     data_segment = inst->module->data_segments[seg_idx]; |     if (bh_bitmap_get_bit(inst->e->common.data_dropped, seg_idx)) { | ||||||
|     if (data_segment->data_length < data_offset |         seg_len = 0; | ||||||
|         || data_segment->data_length - data_offset < len) |         data_addr = NULL; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         data_segment = inst->module->data_segments[seg_idx]; | ||||||
|  |         seg_len = data_segment->data_length; | ||||||
|  |         data_addr = data_segment->data + data_offset; | ||||||
|  |     } | ||||||
|  |     if (seg_len < data_offset || seg_len - data_offset < len) | ||||||
|         goto out_of_bounds; |         goto out_of_bounds; | ||||||
| 
 | 
 | ||||||
|     mem_addr = mem_inst->memory_data + mem_offset; |     mem_addr = mem_inst->memory_data + mem_offset; | ||||||
|     data_addr = data_segment->data + data_offset; |  | ||||||
|     bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len); |     bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len); | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
|  | @ -706,21 +713,22 @@ fail: | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  | wasm_data_drop(WASMModuleInstance *inst, uint32 seg_idx) | ||||||
|  | { | ||||||
|  |     bh_bitmap_set_bit(inst->e->common.data_dropped, seg_idx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool | bool | ||||||
| jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx) | jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx) | ||||||
| { | { | ||||||
|     JitReg module = get_module_reg(cc->jit_frame); |     JitReg args[2] = { 0 }; | ||||||
|     JitReg data_segments = jit_cc_new_reg_ptr(cc); |  | ||||||
|     JitReg data_segment = jit_cc_new_reg_ptr(cc); |  | ||||||
| 
 | 
 | ||||||
|     GEN_INSN(LDPTR, data_segments, module, |     args[0] = get_module_inst_reg(cc->jit_frame); | ||||||
|              NEW_CONST(I32, offsetof(WASMModule, data_segments))); |     args[1] = NEW_CONST(I32, seg_idx); | ||||||
|     GEN_INSN(LDPTR, data_segment, data_segments, |  | ||||||
|              NEW_CONST(I32, seg_idx * sizeof(WASMDataSeg *))); |  | ||||||
|     GEN_INSN(STI32, NEW_CONST(I32, 0), data_segment, |  | ||||||
|              NEW_CONST(I32, offsetof(WASMDataSeg, data_length))); |  | ||||||
| 
 | 
 | ||||||
|     return true; |     return jit_emit_callnative(cc, wasm_data_drop, 0, args, | ||||||
|  |                                sizeof(args) / sizeof(args[0])); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
|  |  | ||||||
|  | @ -10,21 +10,22 @@ | ||||||
| #include "../jit_frontend.h" | #include "../jit_frontend.h" | ||||||
| 
 | 
 | ||||||
| #if WASM_ENABLE_REF_TYPES != 0 | #if WASM_ENABLE_REF_TYPES != 0 | ||||||
|  | static void | ||||||
|  | wasm_elem_drop(WASMModuleInstance *inst, uint32 tbl_seg_idx) | ||||||
|  | { | ||||||
|  |     bh_bitmap_set_bit(inst->e->common.elem_dropped, tbl_seg_idx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool | bool | ||||||
| jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx) | jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx) | ||||||
| { | { | ||||||
|     JitReg module, tbl_segs; |     JitReg args[2] = { 0 }; | ||||||
| 
 | 
 | ||||||
|     module = get_module_reg(cc->jit_frame); |     args[0] = get_module_inst_reg(cc->jit_frame); | ||||||
|  |     args[1] = NEW_CONST(I32, tbl_seg_idx); | ||||||
| 
 | 
 | ||||||
|     tbl_segs = jit_cc_new_reg_ptr(cc); |     return jit_emit_callnative(cc, wasm_elem_drop, 0, args, | ||||||
|     GEN_INSN(LDPTR, tbl_segs, module, |                                sizeof(args) / sizeof(args[0])); | ||||||
|              NEW_CONST(I32, offsetof(WASMModule, table_segments))); |  | ||||||
| 
 |  | ||||||
|     GEN_INSN(STI32, NEW_CONST(I32, true), tbl_segs, |  | ||||||
|              NEW_CONST(I32, tbl_seg_idx * sizeof(WASMTableSeg) |  | ||||||
|                                 + offsetof(WASMTableSeg, is_dropped))); |  | ||||||
|     return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool | bool | ||||||
|  | @ -105,6 +106,12 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx, | ||||||
|     if (offset_len_out_of_bounds(dst_offset, len, tbl_sz)) |     if (offset_len_out_of_bounds(dst_offset, len, tbl_sz)) | ||||||
|         goto out_of_bounds; |         goto out_of_bounds; | ||||||
| 
 | 
 | ||||||
|  |     if (!len) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     if (bh_bitmap_get_bit(inst->e->common.elem_dropped, elem_idx)) | ||||||
|  |         goto out_of_bounds; | ||||||
|  | 
 | ||||||
|     bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems) |     bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems) | ||||||
|                     + dst_offset * sizeof(uint32), |                     + dst_offset * sizeof(uint32), | ||||||
|                 (uint32)((tbl_sz - dst_offset) * sizeof(uint32)), |                 (uint32)((tbl_sz - dst_offset) * sizeof(uint32)), | ||||||
|  |  | ||||||
|  | @ -311,7 +311,6 @@ typedef struct WASMTableSeg { | ||||||
|     uint32 mode; |     uint32 mode; | ||||||
|     /* funcref or externref, elemkind will be considered as funcref */ |     /* funcref or externref, elemkind will be considered as funcref */ | ||||||
|     uint32 elem_type; |     uint32 elem_type; | ||||||
|     bool is_dropped; |  | ||||||
|     /* optional, only for active */ |     /* optional, only for active */ | ||||||
|     uint32 table_index; |     uint32 table_index; | ||||||
|     InitializerExpression base_offset; |     InitializerExpression base_offset; | ||||||
|  |  | ||||||
|  | @ -3160,9 +3160,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                         maddr = memory->memory_data + (uint32)addr; |                         maddr = memory->memory_data + (uint32)addr; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|                         seg_len = (uint64)module->module->data_segments[segment] |                         if (bh_bitmap_get_bit(module->e->common.data_dropped, | ||||||
|                                       ->data_length; |                                               segment)) { | ||||||
|                         data = module->module->data_segments[segment]->data; |                             seg_len = 0; | ||||||
|  |                             data = NULL; | ||||||
|  |                         } | ||||||
|  |                         else { | ||||||
|  |                             seg_len = | ||||||
|  |                                 (uint64)module->module->data_segments[segment] | ||||||
|  |                                     ->data_length; | ||||||
|  |                             data = module->module->data_segments[segment]->data; | ||||||
|  |                         } | ||||||
|                         if (offset + bytes > seg_len) |                         if (offset + bytes > seg_len) | ||||||
|                             goto out_of_bounds; |                             goto out_of_bounds; | ||||||
| 
 | 
 | ||||||
|  | @ -3175,7 +3183,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                         uint32 segment; |                         uint32 segment; | ||||||
| 
 | 
 | ||||||
|                         read_leb_uint32(frame_ip, frame_ip_end, segment); |                         read_leb_uint32(frame_ip, frame_ip_end, segment); | ||||||
|                         module->module->data_segments[segment]->data_length = 0; |                         bh_bitmap_set_bit(module->e->common.data_dropped, | ||||||
|  |                                           segment); | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     case WASM_OP_MEMORY_COPY: |                     case WASM_OP_MEMORY_COPY: | ||||||
|  | @ -3270,8 +3279,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                             break; |                             break; | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (module->module->table_segments[elem_idx] |                         if (bh_bitmap_get_bit(module->e->common.elem_dropped, | ||||||
|                                 .is_dropped) { |                                               elem_idx)) { | ||||||
|                             wasm_set_exception(module, |                             wasm_set_exception(module, | ||||||
|                                                "out of bounds table access"); |                                                "out of bounds table access"); | ||||||
|                             goto got_exception; |                             goto got_exception; | ||||||
|  | @ -3303,8 +3312,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                         read_leb_uint32(frame_ip, frame_ip_end, elem_idx); |                         read_leb_uint32(frame_ip, frame_ip_end, elem_idx); | ||||||
|                         bh_assert(elem_idx < module->module->table_seg_count); |                         bh_assert(elem_idx < module->module->table_seg_count); | ||||||
| 
 | 
 | ||||||
|                         module->module->table_segments[elem_idx].is_dropped = |                         bh_bitmap_set_bit(module->e->common.elem_dropped, | ||||||
|                             true; |                                           elem_idx); | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     case WASM_OP_TABLE_COPY: |                     case WASM_OP_TABLE_COPY: | ||||||
|  |  | ||||||
|  | @ -3005,10 +3005,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                             goto out_of_bounds; |                             goto out_of_bounds; | ||||||
|                         maddr = memory->memory_data + (uint32)addr; |                         maddr = memory->memory_data + (uint32)addr; | ||||||
| #endif | #endif | ||||||
|  |                         if (bh_bitmap_get_bit(module->e->common.data_dropped, | ||||||
|  |                                               segment)) { | ||||||
|  |                             seg_len = 0; | ||||||
|  |                             data = NULL; | ||||||
|  |                         } | ||||||
|  |                         else { | ||||||
| 
 | 
 | ||||||
|                         seg_len = (uint64)module->module->data_segments[segment] |                             seg_len = | ||||||
|                                       ->data_length; |                                 (uint64)module->module->data_segments[segment] | ||||||
|                         data = module->module->data_segments[segment]->data; |                                     ->data_length; | ||||||
|  |                             data = module->module->data_segments[segment]->data; | ||||||
|  |                         } | ||||||
|                         if (offset + bytes > seg_len) |                         if (offset + bytes > seg_len) | ||||||
|                             goto out_of_bounds; |                             goto out_of_bounds; | ||||||
| 
 | 
 | ||||||
|  | @ -3021,8 +3029,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                         uint32 segment; |                         uint32 segment; | ||||||
| 
 | 
 | ||||||
|                         segment = read_uint32(frame_ip); |                         segment = read_uint32(frame_ip); | ||||||
| 
 |                         bh_bitmap_set_bit(module->e->common.data_dropped, | ||||||
|                         module->module->data_segments[segment]->data_length = 0; |                                           segment); | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     case WASM_OP_MEMORY_COPY: |                     case WASM_OP_MEMORY_COPY: | ||||||
|  | @ -3114,8 +3122,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                             break; |                             break; | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (module->module->table_segments[elem_idx] |                         if (bh_bitmap_get_bit(module->e->common.elem_dropped, | ||||||
|                                 .is_dropped) { |                                               elem_idx)) { | ||||||
|                             wasm_set_exception(module, |                             wasm_set_exception(module, | ||||||
|                                                "out of bounds table access"); |                                                "out of bounds table access"); | ||||||
|                             goto got_exception; |                             goto got_exception; | ||||||
|  | @ -3144,9 +3152,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, | ||||||
|                     { |                     { | ||||||
|                         uint32 elem_idx = read_uint32(frame_ip); |                         uint32 elem_idx = read_uint32(frame_ip); | ||||||
|                         bh_assert(elem_idx < module->module->table_seg_count); |                         bh_assert(elem_idx < module->module->table_seg_count); | ||||||
| 
 |                         bh_bitmap_set_bit(module->e->common.elem_dropped, | ||||||
|                         module->module->table_segments[elem_idx].is_dropped = |                                           elem_idx); | ||||||
|                             true; |  | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     case WASM_OP_TABLE_COPY: |                     case WASM_OP_TABLE_COPY: | ||||||
|  |  | ||||||
|  | @ -1666,6 +1666,31 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 | ||||||
|  |     if (module->data_seg_count > 0) { | ||||||
|  |         module_inst->e->common.data_dropped = | ||||||
|  |             bh_bitmap_new(0, module->data_seg_count); | ||||||
|  |         if (module_inst->e->common.data_dropped == NULL) { | ||||||
|  |             LOG_DEBUG("failed to allocate bitmaps"); | ||||||
|  |             set_error_buf(error_buf, error_buf_size, | ||||||
|  |                           "failed to allocate bitmaps"); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | #if WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     if (module->table_seg_count > 0) { | ||||||
|  |         module_inst->e->common.elem_dropped = | ||||||
|  |             bh_bitmap_new(0, module->table_seg_count); | ||||||
|  |         if (module_inst->e->common.elem_dropped == NULL) { | ||||||
|  |             LOG_DEBUG("failed to allocate bitmaps"); | ||||||
|  |             set_error_buf(error_buf, error_buf_size, | ||||||
|  |                           "failed to allocate bitmaps"); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #if WASM_ENABLE_DUMP_CALL_STACK != 0 | #if WASM_ENABLE_DUMP_CALL_STACK != 0 | ||||||
|     if (!(module_inst->frames = runtime_malloc((uint64)sizeof(Vector), |     if (!(module_inst->frames = runtime_malloc((uint64)sizeof(Vector), | ||||||
|                                                error_buf, error_buf_size))) { |                                                error_buf, error_buf_size))) { | ||||||
|  | @ -2189,6 +2214,13 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) | ||||||
|         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst); |         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 | ||||||
|  |     bh_bitmap_delete(module_inst->e->common.data_dropped); | ||||||
|  | #endif | ||||||
|  | #if WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     bh_bitmap_delete(module_inst->e->common.elem_dropped); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     wasm_runtime_free(module_inst); |     wasm_runtime_free(module_inst); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -3148,16 +3180,23 @@ llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index, | ||||||
| { | { | ||||||
|     WASMMemoryInstance *memory_inst; |     WASMMemoryInstance *memory_inst; | ||||||
|     WASMModule *module; |     WASMModule *module; | ||||||
|     uint8 *data = NULL; |     uint8 *data; | ||||||
|     uint8 *maddr; |     uint8 *maddr; | ||||||
|     uint64 seg_len = 0; |     uint64 seg_len; | ||||||
| 
 | 
 | ||||||
|     bh_assert(module_inst->module_type == Wasm_Module_Bytecode); |     bh_assert(module_inst->module_type == Wasm_Module_Bytecode); | ||||||
| 
 | 
 | ||||||
|     memory_inst = wasm_get_default_memory(module_inst); |     memory_inst = wasm_get_default_memory(module_inst); | ||||||
|     module = module_inst->module; | 
 | ||||||
|     seg_len = module->data_segments[seg_index]->data_length; |     if (bh_bitmap_get_bit(module_inst->e->common.data_dropped, seg_index)) { | ||||||
|     data = module->data_segments[seg_index]->data; |         seg_len = 0; | ||||||
|  |         data = NULL; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         module = module_inst->module; | ||||||
|  |         seg_len = module->data_segments[seg_index]->data_length; | ||||||
|  |         data = module->data_segments[seg_index]->data; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst, |     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst, | ||||||
|                                         dst, len)) |                                         dst, len)) | ||||||
|  | @ -3182,7 +3221,7 @@ llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index) | ||||||
| { | { | ||||||
|     bh_assert(module_inst->module_type == Wasm_Module_Bytecode); |     bh_assert(module_inst->module_type == Wasm_Module_Bytecode); | ||||||
| 
 | 
 | ||||||
|     module_inst->module->data_segments[seg_index]->data_length = 0; |     bh_bitmap_set_bit(module_inst->e->common.data_dropped, seg_index); | ||||||
|     /* Currently we can't free the dropped data segment
 |     /* Currently we can't free the dropped data segment
 | ||||||
|        as they are stored in wasm bytecode */ |        as they are stored in wasm bytecode */ | ||||||
|     return true; |     return true; | ||||||
|  | @ -3193,12 +3232,8 @@ llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index) | ||||||
| void | void | ||||||
| llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx) | llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx) | ||||||
| { | { | ||||||
|     WASMTableSeg *tbl_segs; |  | ||||||
| 
 |  | ||||||
|     bh_assert(module_inst->module_type == Wasm_Module_Bytecode); |     bh_assert(module_inst->module_type == Wasm_Module_Bytecode); | ||||||
| 
 |     bh_bitmap_set_bit(module_inst->e->common.elem_dropped, tbl_seg_idx); | ||||||
|     tbl_segs = module_inst->module->table_segments; |  | ||||||
|     tbl_segs[tbl_seg_idx].is_dropped = true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
|  | @ -3227,7 +3262,7 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx, | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (tbl_seg->is_dropped) { |     if (bh_bitmap_get_bit(module_inst->e->common.elem_dropped, tbl_seg_idx)) { | ||||||
|         jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); |         jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "wasm.h" | #include "wasm.h" | ||||||
| #include "bh_atomic.h" | #include "bh_atomic.h" | ||||||
|  | #include "bh_bitmap.h" | ||||||
| #include "bh_hashmap.h" | #include "bh_hashmap.h" | ||||||
| #include "../common/wasm_runtime_common.h" | #include "../common/wasm_runtime_common.h" | ||||||
| #include "../common/wasm_exec_env.h" | #include "../common/wasm_exec_env.h" | ||||||
|  | @ -223,6 +224,12 @@ typedef struct WASMModuleInstanceExtraCommon { | ||||||
|     /* Disable bounds checks or not */ |     /* Disable bounds checks or not */ | ||||||
|     bool disable_bounds_checks; |     bool disable_bounds_checks; | ||||||
| #endif | #endif | ||||||
|  | #if WASM_ENABLE_BULK_MEMORY != 0 | ||||||
|  |     bh_bitmap *data_dropped; | ||||||
|  | #endif | ||||||
|  | #if WASM_ENABLE_REF_TYPES != 0 | ||||||
|  |     bh_bitmap *elem_dropped; | ||||||
|  | #endif | ||||||
| } WASMModuleInstanceExtraCommon; | } WASMModuleInstanceExtraCommon; | ||||||
| 
 | 
 | ||||||
| /* Extra info of WASM module instance for interpreter/jit mode */ | /* Extra info of WASM module instance for interpreter/jit mode */ | ||||||
|  |  | ||||||
							
								
								
									
										27
									
								
								core/shared/utils/bh_bitmap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								core/shared/utils/bh_bitmap.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2021 Intel Corporation.  All rights reserved. | ||||||
|  |  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "bh_bitmap.h" | ||||||
|  | 
 | ||||||
|  | bh_bitmap * | ||||||
|  | bh_bitmap_new(uintptr_t begin_index, unsigned bitnum) | ||||||
|  | { | ||||||
|  |     bh_bitmap *bitmap; | ||||||
|  |     uint32 bitmap_size = (bitnum + 7) / 8; | ||||||
|  |     uint32 total_size = offsetof(bh_bitmap, map) + bitmap_size; | ||||||
|  | 
 | ||||||
|  |     if (bitnum > UINT32_MAX - 7 || total_size < offsetof(bh_bitmap, map) | ||||||
|  |         || (total_size - offsetof(bh_bitmap, map)) != bitmap_size) { | ||||||
|  |         return NULL; /* integer overflow */ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if ((bitmap = BH_MALLOC(total_size)) != NULL) { | ||||||
|  |         memset(bitmap, 0, total_size); | ||||||
|  |         bitmap->begin_index = begin_index; | ||||||
|  |         bitmap->end_index = begin_index + bitnum; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return bitmap; | ||||||
|  | } | ||||||
							
								
								
									
										114
									
								
								core/shared/utils/bh_bitmap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								core/shared/utils/bh_bitmap.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,114 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2021 Intel Corporation.  All rights reserved. | ||||||
|  |  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef _BH_BITMAP_H | ||||||
|  | #define _BH_BITMAP_H | ||||||
|  | 
 | ||||||
|  | #include "bh_platform.h" | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * A simple fixed size bitmap. | ||||||
|  |  */ | ||||||
|  | typedef struct bh_bitmap { | ||||||
|  |     /* The first valid bit index.  */ | ||||||
|  |     uintptr_t begin_index; | ||||||
|  | 
 | ||||||
|  |     /* The last valid bit index plus one.  */ | ||||||
|  |     uintptr_t end_index; | ||||||
|  | 
 | ||||||
|  |     /* The bitmap.  */ | ||||||
|  |     uint8 map[1]; | ||||||
|  | } bh_bitmap; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Create a new bitmap. | ||||||
|  |  * | ||||||
|  |  * @param begin_index the first valid bit index | ||||||
|  |  * @param bitnum maximal bit number of the bitmap. | ||||||
|  |  * | ||||||
|  |  * @return the new bitmap if succeeds, NULL otherwise. | ||||||
|  |  */ | ||||||
|  | bh_bitmap * | ||||||
|  | bh_bitmap_new(uintptr_t begin_index, unsigned bitnum); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Delete a bitmap. | ||||||
|  |  * | ||||||
|  |  * @param bitmap the bitmap to be deleted | ||||||
|  |  */ | ||||||
|  | static inline void | ||||||
|  | bh_bitmap_delete(bh_bitmap *bitmap) | ||||||
|  | { | ||||||
|  |     if (bitmap != NULL) | ||||||
|  |         BH_FREE(bitmap); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Check whether the given index is in the range of the bitmap. | ||||||
|  |  * | ||||||
|  |  * @param bitmap the bitmap | ||||||
|  |  * @param n the bit index | ||||||
|  |  * | ||||||
|  |  * @return true if the index is in range, false otherwise | ||||||
|  |  */ | ||||||
|  | static inline bool | ||||||
|  | bh_bitmap_is_in_range(bh_bitmap *bitmap, unsigned n) | ||||||
|  | { | ||||||
|  |     return n >= bitmap->begin_index && n < bitmap->end_index; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Get a bit in the bitmap | ||||||
|  |  * | ||||||
|  |  * @param bitmap the bitmap | ||||||
|  |  * @param n the n-th bit to be get | ||||||
|  |  * | ||||||
|  |  * @return value of the bit | ||||||
|  |  */ | ||||||
|  | static inline int | ||||||
|  | bh_bitmap_get_bit(bh_bitmap *bitmap, unsigned n) | ||||||
|  | { | ||||||
|  |     unsigned idx = n - bitmap->begin_index; | ||||||
|  |     bh_assert(n >= bitmap->begin_index && n < bitmap->end_index); | ||||||
|  |     return (bitmap->map[idx / 8] >> (idx % 8)) & 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Set a bit in the bitmap. | ||||||
|  |  * | ||||||
|  |  * @param bitmap the bitmap | ||||||
|  |  * @param n the n-th bit to be set | ||||||
|  |  */ | ||||||
|  | static inline void | ||||||
|  | bh_bitmap_set_bit(bh_bitmap *bitmap, unsigned n) | ||||||
|  | { | ||||||
|  |     unsigned idx = n - bitmap->begin_index; | ||||||
|  |     bh_assert(n >= bitmap->begin_index && n < bitmap->end_index); | ||||||
|  |     bitmap->map[idx / 8] |= 1 << (idx % 8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Clear a bit in the bitmap. | ||||||
|  |  * | ||||||
|  |  * @param bitmap the bitmap | ||||||
|  |  * @param n the n-th bit to be cleared | ||||||
|  |  */ | ||||||
|  | static inline void | ||||||
|  | bh_bitmap_clear_bit(bh_bitmap *bitmap, unsigned n) | ||||||
|  | { | ||||||
|  |     unsigned idx = n - bitmap->begin_index; | ||||||
|  |     bh_assert(n >= bitmap->begin_index && n < bitmap->end_index); | ||||||
|  |     bitmap->map[idx / 8] &= ~(1 << (idx % 8)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -98,6 +98,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \ | ||||||
|                    ${SHARED_ROOT}/mem-alloc/ems/ems_alloc.c \
 |                    ${SHARED_ROOT}/mem-alloc/ems/ems_alloc.c \
 | ||||||
|                    ${SHARED_ROOT}/mem-alloc/ems/ems_hmu.c \
 |                    ${SHARED_ROOT}/mem-alloc/ems/ems_hmu.c \
 | ||||||
|                    ${SHARED_ROOT}/utils/bh_assert.c \
 |                    ${SHARED_ROOT}/utils/bh_assert.c \
 | ||||||
|  |                    ${SHARED_ROOT}/utils/bh_bitmap.c \
 | ||||||
|                    ${SHARED_ROOT}/utils/bh_common.c \
 |                    ${SHARED_ROOT}/utils/bh_common.c \
 | ||||||
|                    ${SHARED_ROOT}/utils/bh_hashmap.c \
 |                    ${SHARED_ROOT}/utils/bh_hashmap.c \
 | ||||||
|                    ${SHARED_ROOT}/utils/bh_list.c \
 |                    ${SHARED_ROOT}/utils/bh_list.c \
 | ||||||
|  |  | ||||||
|  | @ -371,6 +371,7 @@ CSRCS += nuttx_platform.c \ | ||||||
|          ems_alloc.c \
 |          ems_alloc.c \
 | ||||||
|          ems_hmu.c \
 |          ems_hmu.c \
 | ||||||
|          bh_assert.c \
 |          bh_assert.c \
 | ||||||
|  |          bh_bitmap.c \
 | ||||||
|          bh_common.c \
 |          bh_common.c \
 | ||||||
|          bh_hashmap.c \
 |          bh_hashmap.c \
 | ||||||
|          bh_list.c \
 |          bh_list.c \
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								samples/shared-module/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/shared-module/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | /out/ | ||||||
							
								
								
									
										95
									
								
								samples/shared-module/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								samples/shared-module/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | ||||||
|  | # Copyright (C) 2019 Intel Corporation.  All rights reserved. | ||||||
|  | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  | 
 | ||||||
|  | cmake_minimum_required (VERSION 3.14) | ||||||
|  | 
 | ||||||
|  | include(CheckPIESupported) | ||||||
|  | 
 | ||||||
|  | project (shared-module) | ||||||
|  | 
 | ||||||
|  | set (CMAKE_CXX_STANDARD 17) | ||||||
|  | 
 | ||||||
|  | ################  runtime settings  ################ | ||||||
|  | string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) | ||||||
|  | if (APPLE) | ||||||
|  |   add_definitions(-DBH_PLATFORM_DARWIN) | ||||||
|  | endif () | ||||||
|  | 
 | ||||||
|  | # Reset default linker flags | ||||||
|  | set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||||||
|  | set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") | ||||||
|  | 
 | ||||||
|  | # WAMR features switch | ||||||
|  | 
 | ||||||
|  | # Set WAMR_BUILD_TARGET, currently values supported: | ||||||
|  | # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", | ||||||
|  | # "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" | ||||||
|  | if (NOT DEFINED WAMR_BUILD_TARGET) | ||||||
|  |   if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") | ||||||
|  |     set (WAMR_BUILD_TARGET "AARCH64") | ||||||
|  |   elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") | ||||||
|  |     set (WAMR_BUILD_TARGET "RISCV64") | ||||||
|  |   elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) | ||||||
|  |     # Build as X86_64 by default in 64-bit platform | ||||||
|  |     set (WAMR_BUILD_TARGET "X86_64") | ||||||
|  |   elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) | ||||||
|  |     # Build as X86_32 by default in 32-bit platform | ||||||
|  |     set (WAMR_BUILD_TARGET "X86_32") | ||||||
|  |   else () | ||||||
|  |     message(SEND_ERROR "Unsupported build target platform!") | ||||||
|  |   endif () | ||||||
|  | endif () | ||||||
|  | 
 | ||||||
|  | if (NOT CMAKE_BUILD_TYPE) | ||||||
|  |   set (CMAKE_BUILD_TYPE Debug) | ||||||
|  | endif () | ||||||
|  | 
 | ||||||
|  | set (WAMR_BUILD_INTERP 1) | ||||||
|  | set (WAMR_BUILD_AOT 1) | ||||||
|  | set (WAMR_BUILD_JIT 0) | ||||||
|  | 
 | ||||||
|  | # fast interpreter | ||||||
|  | # set (WAMR_BUILD_FAST_INTERP 1) | ||||||
|  | 
 | ||||||
|  | # fast-jit | ||||||
|  | # set (WAMR_BUILD_FAST_JIT 1) | ||||||
|  | 
 | ||||||
|  | # llvm jit | ||||||
|  | # set (WAMR_BUILD_JIT 1) | ||||||
|  | # set (LLVM_DIR /usr/local/opt/llvm@14/lib/cmake/llvm) | ||||||
|  | 
 | ||||||
|  | set (WAMR_BUILD_REF_TYPES 1) | ||||||
|  | 
 | ||||||
|  | if (NOT MSVC) | ||||||
|  |   # linker flags | ||||||
|  |   if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) | ||||||
|  |     set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") | ||||||
|  |   endif () | ||||||
|  |   set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") | ||||||
|  |   if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") | ||||||
|  |     if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) | ||||||
|  |       set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") | ||||||
|  |     endif () | ||||||
|  |   endif () | ||||||
|  | endif () | ||||||
|  | 
 | ||||||
|  | # build out vmlib | ||||||
|  | set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) | ||||||
|  | include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) | ||||||
|  | 
 | ||||||
|  | add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) | ||||||
|  | 
 | ||||||
|  | ################  application related  ################ | ||||||
|  | include_directories(${CMAKE_CURRENT_LIST_DIR}/src) | ||||||
|  | include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) | ||||||
|  | 
 | ||||||
|  | add_executable (shared-module src/main.c ${UNCOMMON_SHARED_SOURCE}) | ||||||
|  | 
 | ||||||
|  | check_pie_supported() | ||||||
|  | set_target_properties (shared-module PROPERTIES POSITION_INDEPENDENT_CODE ON) | ||||||
|  | 
 | ||||||
|  | if (APPLE) | ||||||
|  |   target_link_libraries (shared-module vmlib -lm -ldl -lpthread ${LLVM_AVAILABLE_LIBS}) | ||||||
|  | else () | ||||||
|  |   target_link_libraries (shared-module vmlib -lm -ldl -lpthread -lrt ${LLVM_AVAILABLE_LIBS}) | ||||||
|  | endif () | ||||||
							
								
								
									
										5
									
								
								samples/shared-module/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								samples/shared-module/README.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | The "shared-module" sample project | ||||||
|  | ================================== | ||||||
|  | 
 | ||||||
|  | This sample demonstrates a bug described in: | ||||||
|  | https://github.com/bytecodealliance/wasm-micro-runtime/issues/2735. | ||||||
							
								
								
									
										63
									
								
								samples/shared-module/build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										63
									
								
								samples/shared-module/build.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | # | ||||||
|  | # Copyright (C) 2019 Intel Corporation.  All rights reserved. | ||||||
|  | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | CURR_DIR=$PWD | ||||||
|  | WAMR_DIR=${PWD}/../.. | ||||||
|  | OUT_DIR=${PWD}/out | ||||||
|  | 
 | ||||||
|  | WASM_APPS=${PWD}/wasm-apps | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | rm -rf ${OUT_DIR} | ||||||
|  | mkdir ${OUT_DIR} | ||||||
|  | mkdir ${OUT_DIR}/wasm-apps | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | echo "##################### build shared-module project" | ||||||
|  | cd ${CURR_DIR} | ||||||
|  | mkdir -p cmake_build | ||||||
|  | cd cmake_build | ||||||
|  | cmake .. | ||||||
|  | make -j ${nproc} | ||||||
|  | if [ $? != 0 ];then | ||||||
|  |     echo "BUILD_FAIL shared-module exit as $?\n" | ||||||
|  |     exit 2 | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | cp -a shared-module ${OUT_DIR} | ||||||
|  | 
 | ||||||
|  | printf "\n" | ||||||
|  | 
 | ||||||
|  | echo "##################### build wasm apps" | ||||||
|  | 
 | ||||||
|  | cd ${WASM_APPS} | ||||||
|  | 
 | ||||||
|  | for i in `ls *.wat` | ||||||
|  | do | ||||||
|  | APP_SRC="$i" | ||||||
|  | OUT_FILE=${i%.*}.wasm | ||||||
|  | 
 | ||||||
|  | # Note: the CI installs wabt in /opt/wabt | ||||||
|  | if type wat2wasm; then | ||||||
|  |     WAT2WASM=${WAT2WASM:-wat2wasm} | ||||||
|  | elif [ -x /opt/wabt/bin/wat2wasm ]; then | ||||||
|  |     WAT2WASM=${WAT2WASM:-/opt/wabt/bin/wat2wasm} | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | ${WAT2WASM} -o ${OUT_DIR}/wasm-apps/${OUT_FILE} ${APP_SRC} | ||||||
|  | 
 | ||||||
|  | # aot | ||||||
|  | # wamrc -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE} | ||||||
|  | # mv ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE} | ||||||
|  | 
 | ||||||
|  | if [ -f ${OUT_DIR}/wasm-apps/${OUT_FILE} ]; then | ||||||
|  |         echo "build ${OUT_FILE} success" | ||||||
|  | else | ||||||
|  |         echo "build ${OUT_FILE} fail" | ||||||
|  | fi | ||||||
|  | done | ||||||
|  | echo "##################### build wasm apps done" | ||||||
							
								
								
									
										3
									
								
								samples/shared-module/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								samples/shared-module/run.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | out/shared-module -f out/wasm-apps/testapp.wasm | ||||||
							
								
								
									
										206
									
								
								samples/shared-module/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								samples/shared-module/src/main.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,206 @@ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2019 Intel Corporation.  All rights reserved. | ||||||
|  |  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "wasm_export.h" | ||||||
|  | #include "bh_read_file.h" | ||||||
|  | #include "bh_getopt.h" | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | print_usage(void) | ||||||
|  | { | ||||||
|  |     fprintf(stdout, "Options:\r\n"); | ||||||
|  |     fprintf(stdout, "  -f [path of wasm file] \n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | main(int argc, char *argv_main[]) | ||||||
|  | { | ||||||
|  |     int exit_code = 1; | ||||||
|  |     static char global_heap_buf[512 * 1024]; | ||||||
|  |     char *buffer; | ||||||
|  |     char error_buf[128]; | ||||||
|  |     int opt; | ||||||
|  |     char *wasm_path = NULL; | ||||||
|  | 
 | ||||||
|  |     const unsigned int N = 4; | ||||||
|  |     wasm_module_t module = NULL; | ||||||
|  |     wasm_module_inst_t module_inst[N]; | ||||||
|  |     wasm_exec_env_t exec_env[N]; | ||||||
|  |     const char *name_test_data_drop = "test_data_drop"; | ||||||
|  |     const char *name_test_elem_drop = "test_elem_drop"; | ||||||
|  |     wasm_function_inst_t func_test_data_drop[N]; | ||||||
|  |     wasm_function_inst_t func_test_elem_drop[N]; | ||||||
|  |     unsigned int i; | ||||||
|  |     unsigned int iter; | ||||||
|  |     uint32 buf_size, stack_size = 8092, heap_size = 8092; | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < N; i++) { | ||||||
|  |         module_inst[i] = NULL; | ||||||
|  |         exec_env[i] = NULL; | ||||||
|  |         func_test_data_drop[i] = NULL; | ||||||
|  |         func_test_elem_drop[i] = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     RuntimeInitArgs init_args; | ||||||
|  |     memset(&init_args, 0, sizeof(RuntimeInitArgs)); | ||||||
|  | 
 | ||||||
|  |     while ((opt = getopt(argc, argv_main, "hf:")) != -1) { | ||||||
|  |         switch (opt) { | ||||||
|  |             case 'f': | ||||||
|  |                 wasm_path = optarg; | ||||||
|  |                 break; | ||||||
|  |             case 'h': | ||||||
|  |                 print_usage(); | ||||||
|  |                 return 0; | ||||||
|  |             case '?': | ||||||
|  |                 print_usage(); | ||||||
|  |                 return 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (optind == 1) { | ||||||
|  |         print_usage(); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     memset(&init_args, 0, sizeof(init_args)); | ||||||
|  |     init_args.mem_alloc_type = Alloc_With_Pool; | ||||||
|  |     init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; | ||||||
|  |     init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); | ||||||
|  | 
 | ||||||
|  |     if (!wasm_runtime_full_init(&init_args)) { | ||||||
|  |         printf("Init runtime environment failed.\n"); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     buffer = bh_read_file_to_buffer(wasm_path, &buf_size); | ||||||
|  | 
 | ||||||
|  |     if (!buffer) { | ||||||
|  |         printf("Open wasm app file [%s] failed.\n", wasm_path); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     module = wasm_runtime_load((uint8 *)buffer, buf_size, error_buf, | ||||||
|  |                                sizeof(error_buf)); | ||||||
|  |     if (!module) { | ||||||
|  |         printf("Load wasm module failed. error: %s\n", error_buf); | ||||||
|  |         goto fail; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (i = 0; i < N; i++) { | ||||||
|  |         module_inst[i] = wasm_runtime_instantiate(module, stack_size, heap_size, | ||||||
|  |                                                   error_buf, sizeof(error_buf)); | ||||||
|  | 
 | ||||||
|  |         if (!module_inst[i]) { | ||||||
|  |             printf("Instantiate wasm module failed. error: %s\n", error_buf); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         exec_env[i] = wasm_runtime_create_exec_env(module_inst[i], stack_size); | ||||||
|  |         if (!exec_env[i]) { | ||||||
|  |             printf("Create wasm execution environment failed.\n"); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         func_test_data_drop[i] = wasm_runtime_lookup_function( | ||||||
|  |             module_inst[i], name_test_data_drop, NULL); | ||||||
|  |         if (!func_test_data_drop[i]) { | ||||||
|  |             printf("The wasm function %s is not found.\n", name_test_data_drop); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         func_test_elem_drop[i] = wasm_runtime_lookup_function( | ||||||
|  |             module_inst[i], name_test_elem_drop, NULL); | ||||||
|  |         if (!func_test_elem_drop[i]) { | ||||||
|  |             printf("The wasm function %s is not found.\n", name_test_elem_drop); | ||||||
|  |             goto fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (iter = 0; iter < 2; iter++) { | ||||||
|  |         /*
 | ||||||
|  |          * as we drop data/table in the first iteration, | ||||||
|  |          * the later iterations should trap. | ||||||
|  |          */ | ||||||
|  |         const bool should_trap = iter > 0; | ||||||
|  | 
 | ||||||
|  |         for (i = 0; i < N; i++) { | ||||||
|  |             uint32_t argv[1] = {}; | ||||||
|  |             if (wasm_runtime_call_wasm(exec_env[i], func_test_data_drop[i], 0, | ||||||
|  |                                        argv)) { | ||||||
|  |                 uint32_t result = argv[0]; | ||||||
|  |                 printf( | ||||||
|  |                     "Native finished calling wasm function: %s, return: %x\n", | ||||||
|  |                     name_test_data_drop, result); | ||||||
|  |                 if (result != 0x64636261) { /* "abcd" */ | ||||||
|  |                     printf("unexpected return value\n"); | ||||||
|  |                     goto fail; | ||||||
|  |                 } | ||||||
|  |                 if (should_trap) { | ||||||
|  |                     printf("a trap is expected\n"); | ||||||
|  |                     goto fail; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else if (should_trap) { | ||||||
|  |                 printf("call wasm function %s failed as expected. error: %s\n", | ||||||
|  |                        name_test_data_drop, | ||||||
|  |                        wasm_runtime_get_exception(module_inst[i])); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 printf("call wasm function %s failed. error: %s\n", | ||||||
|  |                        name_test_data_drop, | ||||||
|  |                        wasm_runtime_get_exception(module_inst[i])); | ||||||
|  |                 goto fail; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (i = 0; i < N; i++) { | ||||||
|  |             wasm_runtime_clear_exception(module_inst[i]); | ||||||
|  | 
 | ||||||
|  |             uint32_t argv[1] = {}; | ||||||
|  |             if (wasm_runtime_call_wasm(exec_env[i], func_test_elem_drop[i], 0, | ||||||
|  |                                        argv)) { | ||||||
|  |                 uint32_t result = argv[0]; | ||||||
|  |                 printf( | ||||||
|  |                     "Native finished calling wasm function: %s, return: %x\n", | ||||||
|  |                     name_test_elem_drop, result); | ||||||
|  |                 if (result != 0) { | ||||||
|  |                     printf("unexpected return value\n"); | ||||||
|  |                     goto fail; | ||||||
|  |                 } | ||||||
|  |                 if (should_trap) { | ||||||
|  |                     printf("a trap is expected\n"); | ||||||
|  |                     goto fail; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else if (should_trap) { | ||||||
|  |                 printf("call wasm function %s failed as expected. error: %s\n", | ||||||
|  |                        name_test_elem_drop, | ||||||
|  |                        wasm_runtime_get_exception(module_inst[i])); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 printf("call wasm function %s failed. error: %s\n", | ||||||
|  |                        name_test_elem_drop, | ||||||
|  |                        wasm_runtime_get_exception(module_inst[i])); | ||||||
|  |                 goto fail; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     exit_code = 0; | ||||||
|  | fail: | ||||||
|  |     for (i = 0; i < N; i++) { | ||||||
|  |         if (exec_env[i]) | ||||||
|  |             wasm_runtime_destroy_exec_env(exec_env[i]); | ||||||
|  |         if (module_inst[i]) | ||||||
|  |             wasm_runtime_deinstantiate(module_inst[i]); | ||||||
|  |     } | ||||||
|  |     if (module) | ||||||
|  |         wasm_runtime_unload(module); | ||||||
|  |     if (buffer) | ||||||
|  |         BH_FREE(buffer); | ||||||
|  |     wasm_runtime_destroy(); | ||||||
|  |     return exit_code; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								samples/shared-module/wasm-apps/testapp.wat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								samples/shared-module/wasm-apps/testapp.wat
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | ;; Copyright (C) 2023 Midokura Japan KK.  All rights reserved. | ||||||
|  | ;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
|  | 
 | ||||||
|  | (module | ||||||
|  |   (func (export "test_data_drop") (result i32) | ||||||
|  |     (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 4)) | ||||||
|  |     data.drop 0 | ||||||
|  |     (i32.load (i32.const 0)) | ||||||
|  |   ) | ||||||
|  |   (func (export "test_elem_drop") (result i32) | ||||||
|  |     (table.init 0 (i32.const 0) (i32.const 0) (i32.const 4)) | ||||||
|  |     elem.drop 0 | ||||||
|  |     i32.const 3 | ||||||
|  |     table.get 0 | ||||||
|  |     ref.is_null | ||||||
|  |   ) | ||||||
|  |   (func $f) | ||||||
|  |   (memory 1 1) | ||||||
|  |   (table 4 4 funcref) | ||||||
|  |   (data "abcd") | ||||||
|  |   (elem func $f $f $f $f) | ||||||
|  | ) | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 YAMAMOTO Takashi
						YAMAMOTO Takashi