diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 27592fde6d..6be445944f 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -585,6 +585,7 @@ jobs: cmake .. cmake --build . --config Debug --parallel 4 ./shared_heap_test + ./shared_heap_test --aot test: needs: diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index f92bba62f5..5b1edac85b 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.github/workflows/compilation_on_macos.yml @@ -394,3 +394,4 @@ jobs: cmake .. cmake --build . --config Debug --parallel 4 ./shared_heap_test + ./shared_heap_test --aot diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index 832c34d701..5149c830fa 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -600,6 +600,7 @@ jobs: cmake .. cmake --build . --config Debug --parallel 4 ./shared_heap_test + ./shared_heap_test --aot test: needs: diff --git a/core/config.h b/core/config.h index c49b63ca2d..6bab4da908 100644 --- a/core/config.h +++ b/core/config.h @@ -396,7 +396,9 @@ #define APP_HEAP_SIZE_DEFAULT (8 * 1024) #endif #define APP_HEAP_SIZE_MIN (256) -#define APP_HEAP_SIZE_MAX (512 * 1024 * 1024) +/* The ems memory allocator supports maximal heap size 1GB, + see ems_gc_internal.h */ +#define APP_HEAP_SIZE_MAX (1024 * 1024 * 1024) /* Default min/max gc heap size of each app */ #ifndef GC_HEAP_SIZE_DEFAULT diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 63a3c83c90..fae534b7ef 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -57,6 +57,9 @@ bh_static_assert(sizeof(AOTMemoryInstance) == 120); bh_static_assert(offsetof(AOTTableInstance, elems) == 24); bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0); +bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj) + == 8); +bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_start_off) == 16); bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3); @@ -1885,6 +1888,24 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, extra->stack_sizes = aot_get_data_section_addr(module, AOT_STACK_SIZES_SECTION_NAME, NULL); + /* + * The AOT code checks whether the n bytes to access are in shared heap + * by checking whether the beginning address meets: + * addr >= start_off && addr <= end_off - n-bytes + 1 + * where n is 1/2/4/8/16 and `end_off - n-bytes + 1` is constant, e.g., + * UINT32_MAX, UINT32_MAX-1, UINT32_MAX-3 for n = 1, 2 or 4 in 32-bit + * target. To simplify the check, when shared heap is disabled, we set + * the start off to UINT64_MAX in 64-bit target and UINT32_MAX in 32-bit + * target, so in the checking, the above formula will be false, we don't + * need to check whether the shared heap is enabled or not in the AOT + * code. + */ +#if UINTPTR_MAX == UINT64_MAX + extra->shared_heap_start_off.u64 = UINT64_MAX; +#else + extra->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif + #if WASM_ENABLE_PERF_PROFILING != 0 total_size = sizeof(AOTFuncPerfProfInfo) * ((uint64)module->import_func_count + module->func_count); diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 2728e57ef6..bf5e4366c7 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -111,6 +111,14 @@ typedef struct AOTFunctionInstance { typedef struct AOTModuleInstanceExtra { DefPointer(const uint32 *, stack_sizes); + /* + * Adjusted shared heap based addr to simple the calculation + * in the aot code. The value is: + * shared_heap->base_addr - shared_heap->start_off + */ + DefPointer(uint8 *, shared_heap_base_addr_adj); + MemBound shared_heap_start_off; + WASMModuleInstanceExtraCommon common; AOTFunctionInstance **functions; uint32 function_count; diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index e70cc2a5b6..d2d89e5952 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -165,7 +165,7 @@ runtime_malloc(uint64 size) WASMSharedHeap * wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args) { - uint64 heap_struct_size = sizeof(WASMSharedHeap); + uint64 heap_struct_size = sizeof(WASMSharedHeap), map_size; uint32 size = init_args->size; WASMSharedHeap *heap; @@ -192,7 +192,18 @@ wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args) goto fail3; } - if (!(heap->base_addr = wasm_mmap_linear_memory(size, size))) { +#ifndef OS_ENABLE_HW_BOUND_CHECK + map_size = size; +#else + /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G: + * ea = i + memarg.offset + * both i and memarg.offset are u32 in range 0 to 4G + * so the range of ea is 0 to 8G + */ + map_size = 8 * (uint64)BH_GB; +#endif + + if (!(heap->base_addr = wasm_mmap_linear_memory(map_size, size))) { goto fail3; } if (!mem_allocator_create_with_struct_and_pool( @@ -213,7 +224,7 @@ wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args) return heap; fail4: - wasm_munmap_linear_memory(heap->base_addr, size, size); + wasm_munmap_linear_memory(heap->base_addr, size, map_size); fail3: wasm_runtime_free(heap->heap_handle); fail2: @@ -245,18 +256,52 @@ wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { - if (((WASMModuleInstance *)module_inst)->e->shared_heap) { + WASMModuleInstanceExtra *e = + (WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e; + if (e->shared_heap) { LOG_WARNING("A shared heap is already attached"); return false; } - ((WASMModuleInstance *)module_inst)->e->shared_heap = shared_heap; - } + e->shared_heap = shared_heap; +#if WASM_ENABLE_JIT != 0 +#if UINTPTR_MAX == UINT64_MAX + if (memory->is_memory64) + e->shared_heap_start_off.u64 = shared_heap->start_off_mem64; + else + e->shared_heap_start_off.u64 = shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u64; +#else + e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u32[0]; #endif +#endif /* end of WASM_ENABLE_JIT != 0 */ + } +#endif /* end of WASM_ENABLE_INTERP != 0 */ #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { - // TODO - } + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + if (e->shared_heap) { + LOG_WARNING("A shared heap is already attached"); + return false; + } + e->shared_heap = shared_heap; +#if UINTPTR_MAX == UINT64_MAX + if (memory->is_memory64) + e->shared_heap_start_off.u64 = shared_heap->start_off_mem64; + else + e->shared_heap_start_off.u64 = shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u64; +#else + e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32; + e->shared_heap_base_addr_adj = + shared_heap->base_addr - e->shared_heap_start_off.u32[0]; #endif + } +#endif /* end of WASM_ENABLE_AOT != 0 */ return true; } @@ -277,14 +322,32 @@ wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { - ((WASMModuleInstance *)module_inst)->e->shared_heap = NULL; - } + WASMModuleInstanceExtra *e = + (WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e; + e->shared_heap = NULL; +#if WASM_ENABLE_JIT != 0 +#if UINTPTR_MAX == UINT64_MAX + e->shared_heap_start_off.u64 = UINT64_MAX; +#else + e->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif + e->shared_heap_base_addr_adj = NULL; #endif + } +#endif /* end of WASM_ENABLE_INTERP != 0 */ #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { - // TODO - } + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + e->shared_heap = NULL; +#if UINTPTR_MAX == UINT64_MAX + e->shared_heap_start_off.u64 = UINT64_MAX; +#else + e->shared_heap_start_off.u32[0] = UINT32_MAX; #endif + e->shared_heap_base_addr_adj = NULL; + } +#endif /* end of WASM_ENABLE_AOT != 0 */ } void @@ -307,13 +370,21 @@ get_shared_heap(WASMModuleInstanceCommon *module_inst_comm) #endif #if WASM_ENABLE_AOT != 0 if (module_inst_comm->module_type == Wasm_Module_AoT) { - // TODO - return NULL; + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_comm) + ->e; + return e->shared_heap; } #endif return NULL; } +WASMSharedHeap * +wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm) +{ + return get_shared_heap(module_inst_comm); +} + static bool is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst, bool is_memory64, uint64 app_offset, uint32 bytes) @@ -324,6 +395,10 @@ is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst, return false; } + if (bytes == 0) { + bytes = 1; + } + if (!is_memory64) { if (app_offset >= heap->start_off_mem32 && app_offset <= UINT32_MAX - bytes + 1) { @@ -457,17 +532,23 @@ wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, #if WASM_ENABLE_SHARED_HEAP != 0 static void -wasm_runtime_destroy_shared_heaps() +destroy_shared_heaps() { WASMSharedHeap *heap = shared_heap_list; WASMSharedHeap *cur; + uint64 map_size; while (heap) { cur = heap; heap = heap->next; mem_allocator_destroy(cur->heap_handle); wasm_runtime_free(cur->heap_handle); - wasm_munmap_linear_memory(cur->base_addr, cur->size, cur->size); +#ifndef OS_ENABLE_HW_BOUND_CHECK + map_size = cur->size; +#else + map_size = 8 * (uint64)BH_GB; +#endif + wasm_munmap_linear_memory(cur->base_addr, cur->size, map_size); wasm_runtime_free(cur); } } @@ -477,7 +558,7 @@ void wasm_runtime_memory_destroy(void) { #if WASM_ENABLE_SHARED_HEAP != 0 - wasm_runtime_destroy_shared_heaps(); + destroy_shared_heaps(); #endif if (memory_mode == MEMORY_MODE_POOL) { @@ -1178,7 +1259,7 @@ wasm_mremap_linear_memory(void *mapped_mem, uint64 old_size, uint64 new_size, } static void * -wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size) +wasm_mmap_linear_memory(uint64 map_size, uint64 commit_size) { return wasm_mremap_linear_memory(NULL, 0, map_size, commit_size); } diff --git a/core/iwasm/common/wasm_memory.h b/core/iwasm/common/wasm_memory.h index cc6418e841..bceea0ee43 100644 --- a/core/iwasm/common/wasm_memory.h +++ b/core/iwasm/common/wasm_memory.h @@ -54,9 +54,13 @@ wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst, void wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst); + void wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst); +WASMSharedHeap * +wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm); + uint64 wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst, uint64 size, void **p_native_addr); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index dc20edba20..aa929e9716 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -185,6 +185,9 @@ static bool is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst) { WASMMemoryInstance *memory_inst; +#if WASM_ENABLE_SHARED_HEAP != 0 + WASMSharedHeap *shared_heap; +#endif uint8 *mapped_mem_start_addr = NULL; uint8 *mapped_mem_end_addr = NULL; uint32 i; @@ -202,6 +205,21 @@ is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst) } } +#if WASM_ENABLE_SHARED_HEAP != 0 + shared_heap = + wasm_runtime_get_shared_heap((WASMModuleInstanceCommon *)module_inst); + if (shared_heap) { + mapped_mem_start_addr = shared_heap->base_addr; + mapped_mem_end_addr = shared_heap->base_addr + 8 * (uint64)BH_GB; + if (mapped_mem_start_addr <= (uint8 *)sig_addr + && (uint8 *)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + the shared heap's guard regions */ + return true; + } + } +#endif + return false; } diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index e0d86d6f40..2027a57200 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -8,6 +8,9 @@ #if WASM_ENABLE_THREAD_MGR != 0 #include "../libraries/thread-mgr/thread_manager.h" #endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif /* * Note: this lock can be per memory. @@ -257,7 +260,9 @@ is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst, #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { - // TODO + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e; + shared_heap = e->shared_heap; } #endif diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 806150ff19..869a1dbb27 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -118,10 +118,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef offset_const = MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset)); - LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp; + LLVMValueRef addr, maddr, maddr_phi = NULL, offset1, cmp1, cmp2, cmp; LLVMValueRef mem_base_addr, mem_check_bound; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ; + LLVMBasicBlockRef check_succ, block_maddr_phi = NULL; AOTValue *aot_value_top; uint32 local_idx_of_aot_value = 0; uint64 const_value; @@ -131,6 +131,11 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, bool is_shared_memory = comp_ctx->comp_data->memories[0].flags & SHARED_MEMORY_FLAG; #endif +#if WASM_ENABLE_MEMORY64 == 0 + bool is_memory64 = false; +#else + bool is_memory64 = IS_MEMORY64; +#endif is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false; @@ -268,8 +273,137 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* offset1 = offset + addr; */ + /* TODO: check whether integer overflow occurs when memory is 64-bit + and boundary check is enabled */ BUILD_OP(Add, offset_const, addr, offset1, "offset1"); + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem; + LLVMValueRef is_in_shared_heap, shared_heap_check_bound = NULL; + + /* Add basic blocks */ + ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap"); + ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem"); + ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi"); + + LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr); + LLVMMoveBasicBlockAfter(app_addr_in_linear_mem, + app_addr_in_shared_heap); + LLVMMoveBasicBlockAfter(block_maddr_phi, app_addr_in_linear_mem); + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + if (!(maddr_phi = + LLVMBuildPhi(comp_ctx->builder, + enable_segue ? INT8_PTR_TYPE_GS : INT8_PTR_TYPE, + "maddr_phi"))) { + aot_set_last_error("llvm build phi failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); + + if (!is_target_64bit) { + /* Check whether interger overflow occurs in addr + offset */ + LLVMBasicBlockRef check_integer_overflow_end; + ADD_BASIC_BLOCK(check_integer_overflow_end, + "check_integer_overflow_end"); + LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr); + + BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); + if (!aot_emit_exception(comp_ctx, func_ctx, + EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, + cmp1, check_integer_overflow_end)) { + goto fail; + } + SET_BUILD_POS(check_integer_overflow_end); + } + + shared_heap_check_bound = + is_memory64 ? I64_CONST(UINT64_MAX - bytes + 1) + : (comp_ctx->pointer_size == sizeof(uint64) + ? I64_CONST(UINT32_MAX - bytes + 1) + : I32_CONST(UINT32_MAX - bytes + 1)); + CHECK_LLVM_CONST(shared_heap_check_bound); + + /* Check whether the bytes to access are in shared heap */ + if (!comp_ctx->enable_bound_check) { + /* Use IntUGT but not IntUGE to compare, since (1) in the ems + memory allocator, the hmu node includes hmu header and hmu + memory, only the latter is returned to the caller as the + allocated memory, the hmu header isn't returned so the + first byte of the shared heap won't be accesed, (2) using + IntUGT gets better performance than IntUGE in some cases */ + BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off, + is_in_shared_heap, "is_in_shared_heap"); + /* We don't check the shared heap's upper boundary if boundary + check isn't enabled, the runtime may also use the guard pages + of shared heap to check the boundary if hardware boundary + check feature is enabled. */ + } + else { + /* Use IntUGT but not IntUGE to compare, same as above */ + BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off, + cmp1, "cmp1"); + /* Check the shared heap's upper boundary if boundary check is + enabled */ + BUILD_ICMP(LLVMIntULE, offset1, shared_heap_check_bound, cmp2, + "cmp2"); + BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap"); + } + + if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap, + app_addr_in_shared_heap, app_addr_in_linear_mem)) { + aot_set_last_error("llvm build cond br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap); + + /* Get native address inside shared heap */ + if (!(maddr = + LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->shared_heap_base_addr_adj, + &offset1, 1, "maddr_shared_heap"))) { + aot_set_last_error("llvm build inbounds gep failed"); + goto fail; + } + + if (enable_segue) { + LLVMValueRef mem_base_addr_u64, maddr_u64, offset_to_mem_base; + + if (!(maddr_u64 = LLVMBuildPtrToInt(comp_ctx->builder, maddr, + I64_TYPE, "maddr_u64")) + || !(mem_base_addr_u64 = + LLVMBuildPtrToInt(comp_ctx->builder, mem_base_addr, + I64_TYPE, "mem_base_addr_u64"))) { + aot_set_last_error("llvm build ptr to int failed"); + goto fail; + } + if (!(offset_to_mem_base = + LLVMBuildSub(comp_ctx->builder, maddr_u64, + mem_base_addr_u64, "offset_to_mem_base"))) { + aot_set_last_error("llvm build sub failed"); + goto fail; + } + if (!(maddr = LLVMBuildIntToPtr( + comp_ctx->builder, offset_to_mem_base, INT8_PTR_TYPE_GS, + "maddr_shared_heap_segue"))) { + aot_set_last_error("llvm build int to ptr failed."); + goto fail; + } + } + + LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1); + + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem); + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + } + if (comp_ctx->enable_bound_check && !(is_local_of_aot_value && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value, @@ -305,10 +439,16 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); } else { - /* Check integer overflow */ - BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); - BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); - BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + /* Check integer overflow has been checked above */ + BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); + } + else { + /* Check integer overflow */ + BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); + BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); + BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + } } /* Add basic blocks */ @@ -354,7 +494,19 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } } - return maddr; + + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1); + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + return maddr_phi; + } + else + return maddr; fail: return NULL; } @@ -985,10 +1137,15 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef offset, LLVMValueRef bytes) { LLVMValueRef maddr, max_addr, cmp; - LLVMValueRef mem_base_addr; + LLVMValueRef mem_base_addr, maddr_phi = NULL; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ; + LLVMBasicBlockRef check_succ, block_maddr_phi = NULL; LLVMValueRef mem_size; +#if WASM_ENABLE_MEMORY64 == 0 + bool is_memory64 = false; +#else + bool is_memory64 = IS_MEMORY64; +#endif /* Get memory base address and memory data size */ #if WASM_ENABLE_SHARED_MEMORY != 0 @@ -1053,9 +1210,96 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, offset = LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset"); bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len"); + if (!offset || !bytes) { + aot_set_last_error("llvm build zext failed."); + goto fail; + } + /* TODO: check whether integer overflow occurs when memory is 64-bit + and boundary check is enabled */ BUILD_OP(Add, offset, bytes, max_addr, "max_addr"); + + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem; + LLVMValueRef shared_heap_start_off, shared_heap_check_bound; + LLVMValueRef max_offset, cmp1, cmp2, is_in_shared_heap; + + /* Add basic blocks */ + ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap"); + ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem"); + ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi"); + + LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr); + LLVMMoveBasicBlockAfter(app_addr_in_linear_mem, + app_addr_in_shared_heap); + LLVMMoveBasicBlockAfter(block_maddr_phi, check_succ); + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + if (!(maddr_phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE, + "maddr_phi"))) { + aot_set_last_error("llvm build phi failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); + + shared_heap_start_off = func_ctx->shared_heap_start_off; + if (comp_ctx->pointer_size == sizeof(uint32)) { + if (!(shared_heap_start_off = + LLVMBuildZExt(comp_ctx->builder, shared_heap_start_off, + I64_TYPE, "shared_heap_start_off_u64"))) { + aot_set_last_error("llvm build zext failed"); + goto fail; + } + } + shared_heap_check_bound = + is_memory64 ? I64_CONST(UINT64_MAX) : I64_CONST(UINT32_MAX); + CHECK_LLVM_CONST(shared_heap_check_bound); + + /* Check whether the bytes to access are in shared heap */ + if (!comp_ctx->enable_bound_check) { + /* Use IntUGT but not IntUGE to compare, same as the check + in aot_check_memory_overflow */ + BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off, + is_in_shared_heap, "is_in_shared_heap"); + } + else { + BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off, + cmp1, "cmp1"); + BUILD_OP(Add, max_addr, I64_NEG_ONE, max_offset, "max_offset"); + BUILD_ICMP(LLVMIntULE, max_offset, shared_heap_check_bound, cmp2, + "cmp2"); + BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap"); + } + + if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap, + app_addr_in_shared_heap, app_addr_in_linear_mem)) { + aot_set_last_error("llvm build cond br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap); + + /* Get native address inside shared heap */ + if (!(maddr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->shared_heap_base_addr_adj, + &offset, 1, "maddr_shared_heap"))) { + aot_set_last_error("llvm build inbounds gep failed"); + goto fail; + } + LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1); + + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem); + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + } + BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr"); + if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, check_succ)) { @@ -1068,11 +1312,23 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build add failed."); goto fail; } - return maddr; + + if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { + block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1); + if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { + aot_set_last_error("llvm build br failed"); + goto fail; + } + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); + return maddr_phi; + } + else + return maddr; fail: return NULL; } -#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 or WASM_ENABLE_STRINGREF != 0 */ +#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0 */ #if WASM_ENABLE_BULK_MEMORY != 0 bool diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 820a55e965..fb1c4308b2 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -1518,6 +1518,75 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +static bool +create_shared_heap_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef offset, base_addr_p, start_off_p, cmp; + uint32 offset_u32; + + /* Load aot_inst->e->shared_heap_base_addr_adj */ + offset_u32 = get_module_inst_extra_offset(comp_ctx); +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 + if (comp_ctx->is_jit_mode) + offset_u32 += + offsetof(WASMModuleInstanceExtra, shared_heap_base_addr_adj); + else +#endif + offset_u32 += + offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj); + offset = I32_CONST(offset_u32); + CHECK_LLVM_CONST(offset); + + if (!(base_addr_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->aot_inst, &offset, 1, + "shared_heap_base_addr_adj_p"))) { + aot_set_last_error("llvm build inbounds gep failed"); + return false; + } + if (!(func_ctx->shared_heap_base_addr_adj = + LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, base_addr_p, + "shared_heap_base_addr_adj"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + /* Load aot_inst->e->shared_heap_start_off */ + offset_u32 = get_module_inst_extra_offset(comp_ctx); +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 + if (comp_ctx->is_jit_mode) + offset_u32 += offsetof(WASMModuleInstanceExtra, shared_heap_start_off); + else +#endif + offset_u32 += offsetof(AOTModuleInstanceExtra, shared_heap_start_off); + offset = I32_CONST(offset_u32); + CHECK_LLVM_CONST(offset); + + if (!(start_off_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->aot_inst, &offset, 1, + "shared_heap_start_off_p"))) { + aot_set_last_error("llvm build inbounds gep failed"); + return false; + } + if (!(func_ctx->shared_heap_start_off = LLVMBuildLoad2( + comp_ctx->builder, + comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE, + start_off_p, "shared_heap_start_off"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + if (!(cmp = LLVMBuildIsNotNull(comp_ctx->builder, + func_ctx->shared_heap_base_addr_adj, + "has_shared_heap"))) { + aot_set_last_error("llvm build is not null failed"); + return false; + } + + return true; +fail: + return false; +} + static bool create_cur_exception(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -1808,6 +1877,12 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx, goto fail; } + /* Load shared heap, shared heap start off mem32 or mem64 */ + if (comp_ctx->enable_shared_heap + && !create_shared_heap_info(comp_ctx, func_ctx)) { + goto fail; + } + return func_ctx; fail: @@ -2619,6 +2694,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) if (option->enable_gc) comp_ctx->enable_gc = true; + if (option->enable_shared_heap) + comp_ctx->enable_shared_heap = true; + comp_ctx->opt_level = option->opt_level; comp_ctx->size_level = option->size_level; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 43212e5027..0dce988bc9 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -242,6 +242,9 @@ typedef struct AOTFuncContext { bool mem_space_unchanged; AOTCheckedAddrList checked_addr_list; + LLVMValueRef shared_heap_base_addr_adj; + LLVMValueRef shared_heap_start_off; + LLVMBasicBlockRef got_exception_block; LLVMBasicBlockRef func_return_block; LLVMValueRef exception_id_phi; @@ -467,6 +470,8 @@ typedef struct AOTCompContext { /* Enable GC */ bool enable_gc; + bool enable_shared_heap; + uint32 opt_level; uint32 size_level; diff --git a/core/iwasm/include/aot_comp_option.h b/core/iwasm/include/aot_comp_option.h index 98f33a1608..4df80ec58c 100644 --- a/core/iwasm/include/aot_comp_option.h +++ b/core/iwasm/include/aot_comp_option.h @@ -71,6 +71,7 @@ typedef struct AOTCompOption { bool enable_llvm_pgo; bool enable_stack_estimation; bool quick_invoke_c_api_import; + bool enable_shared_heap; char *use_prof_file; uint32_t opt_level; uint32_t size_level; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index ecbe408ff9..cb385ce9cb 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -47,8 +47,14 @@ typedef float64 CellType_F64; #endif #if WASM_ENABLE_SHARED_HEAP != 0 -#define app_addr_in_shared_heap(app_addr, bytes) \ - (shared_heap && (app_addr) >= shared_heap_start_off \ +#if WASM_ENABLE_MULTI_MEMORY != 0 +/* Only enable shared heap for the default memory */ +#define is_default_memory (memidx == 0) +#else +#define is_default_memory true +#endif +#define app_addr_in_shared_heap(app_addr, bytes) \ + (shared_heap && is_default_memory && (app_addr) >= shared_heap_start_off \ && (app_addr) <= shared_heap_end_off - bytes + 1) #define shared_heap_addr_app_to_native(app_addr, native_addr) \ diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ff3501e3d0..e61e7677dd 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -5330,6 +5330,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, option.enable_memory_profiling = true; option.enable_stack_estimation = true; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + option.enable_shared_heap = true; +#endif module->comp_ctx = aot_create_comp_context(module->comp_data, &option); if (!module->comp_ctx) { diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 968eaf0096..ff0a4f403c 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2158,6 +2158,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, option.enable_memory_profiling = true; option.enable_stack_estimation = true; #endif +#if WASM_ENABLE_SHARED_HEAP != 0 + option.enable_shared_heap = true; +#endif module->comp_ctx = aot_create_comp_context(module->comp_data, &option); if (!module->comp_ctx) { diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index e4142ab88c..d474f6eae6 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2791,6 +2791,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, } } +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 +#if UINTPTR_MAX == UINT64_MAX + module_inst->e->shared_heap_start_off.u64 = UINT64_MAX; +#else + module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX; +#endif +#endif + #if WASM_ENABLE_GC != 0 /* Initialize the table data with init expr */ for (i = 0; i < module->table_count; i++) { diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 48c333f4cb..2644b00162 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -92,7 +92,6 @@ typedef union { uint32 u32[2]; } MemBound; -#if WASM_ENABLE_SHARED_HEAP != 0 typedef struct WASMSharedHeap { struct WASMSharedHeap *next; void *heap_handle; @@ -101,7 +100,6 @@ typedef struct WASMSharedHeap { uint64 start_off_mem64; uint64 start_off_mem32; } WASMSharedHeap; -#endif struct WASMMemoryInstance { /* Module type */ @@ -366,6 +364,15 @@ typedef struct WASMModuleInstanceExtra { #if WASM_ENABLE_SHARED_HEAP != 0 WASMSharedHeap *shared_heap; +#if WASM_ENABLE_JIT != 0 + /* + * Adjusted shared heap based addr to simple the calculation + * in the aot code. The value is: + * shared_heap->base_addr - shared_heap->start_off + */ + uint8 *shared_heap_base_addr_adj; + MemBound shared_heap_start_off; +#endif #endif #if WASM_ENABLE_DEBUG_INTERP != 0 \ diff --git a/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c b/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c index 76e662dacd..b7b78307ae 100644 --- a/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c +++ b/core/iwasm/libraries/shared-heap/shared_heap_wrapper.c @@ -20,14 +20,14 @@ /* clang-format on */ static uint32 -shared_malloc_wrapper(wasm_exec_env_t exec_env, uint32 size) +shared_heap_malloc_wrapper(wasm_exec_env_t exec_env, uint32 size) { wasm_module_inst_t module_inst = get_module_inst(exec_env); return (uint32)module_shared_malloc((uint64)size, NULL); } static void -shared_free_wrapper(wasm_exec_env_t exec_env, void *ptr) +shared_heap_free_wrapper(wasm_exec_env_t exec_env, void *ptr) { wasm_module_inst_t module_inst = get_module_inst(exec_env); @@ -45,8 +45,8 @@ shared_free_wrapper(wasm_exec_env_t exec_env, void *ptr) /* clang-format on */ static NativeSymbol native_symbols_shared_heap[] = { - REG_NATIVE_FUNC(shared_malloc, "(i)i"), - REG_NATIVE_FUNC(shared_free, "(*)"), + REG_NATIVE_FUNC(shared_heap_malloc, "(i)i"), + REG_NATIVE_FUNC(shared_heap_free, "(*)"), }; uint32 diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 46a1bb329a..55e0526c3b 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -1428,16 +1428,6 @@ wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst, { WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); - if (module_inst->module_type == Wasm_Module_Bytecode) { - if (((WASMModuleInstance *)module_inst)->e->shared_heap) { - LOG_WARNING("A shared heap is already attached"); - return false; - } - } - else if (module_inst->module_type == Wasm_Module_AoT) { - // TODO - } - if (exec_env == NULL) { /* Maybe threads have not been started yet. */ return wasm_runtime_attach_shared_heap_internal(module_inst, heap); diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 2adb17f6a1..4537ee0841 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -300,6 +300,22 @@ Currently we only profile the memory consumption of module, module_instance and wasm_runtime_get_context ``` +#### **Shared heap among wasm apps and host native** +- **WAMR_BUILD_SHARED_HEAP**=1/0, default to disable if not set +> Note: If it is enabled, allow to create one or more shared heaps, and attach one to a module instance, the belows APIs ared provided: +```C + wasm_runtime_create_shared_heap + wasm_runtime_attach_shared_heap + wasm_runtime_detach_shared_heap + wasm_runtime_shared_heap_malloc + wasm_runtime_shared_heap_free +``` +And the wasm app can calls below APIs to allocate/free memory from/to the shared heap if it is attached to the app's module instance: +```C + void *shared_heap_malloc(); + void shared_heap_free(void *ptr); +``` + **Combination of configurations:** We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: diff --git a/samples/shared-heap/CMakeLists.txt b/samples/shared-heap/CMakeLists.txt index 382ddd5460..6346d077e7 100644 --- a/samples/shared-heap/CMakeLists.txt +++ b/samples/shared-heap/CMakeLists.txt @@ -48,6 +48,7 @@ if (NOT CMAKE_BUILD_TYPE) endif () set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_FAST_INTERP 1) set (WAMR_BUILD_AOT 1) set (WAMR_BUILD_JIT 0) set (WAMR_BUILD_LIBC_BUILTIN 1) @@ -72,7 +73,11 @@ endif () set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) +if (MSVC) + target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=) +endif() +target_link_libraries(vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) ################ application related ################ include_directories(${CMAKE_CURRENT_LIST_DIR}/src) @@ -90,3 +95,33 @@ else () endif () add_subdirectory(wasm-apps) + +if (WAMR_BUILD_AOT EQUAL 1) + set (WAMR_COMPILER_DIR ${CMAKE_CURRENT_LIST_DIR}/../../wamr-compiler/build) + message (CHECK_START "Detecting WAMR_COMPILER at ${WAMR_COMPILER_DIR}") + find_file (WAMR_COMPILER + wamrc + PATHS "${CMAKE_CURRENT_LIST_DIR}/../../wamr-compiler/build" + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + if (WAMR_COMPILER) + message (CHECK_PASS "found") + else() + message (CHECK_FAIL "not found") + endif() + if (NOT EXISTS ${WAMR_COMPILER}) + message (FATAL_ERROR "Please build wamrc under ${WAMR_ROOT_DIR}/wamr-compiler") + else() + message (STATUS "WAMR_COMPILER is ${WAMR_COMPILER}") + endif() + + add_custom_target( + wasm_to_aot + ALL + DEPENDS wasm-apps/test1.wasm wasm-apps/test2.wasm ${WAMR_COMPILER} + COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test1.aot wasm-apps/test1.wasm + COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test2.aot wasm-apps/test2.wasm + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) +endif() diff --git a/samples/shared-heap/src/main.c b/samples/shared-heap/src/main.c index 416652a3e7..f4024f08c2 100644 --- a/samples/shared-heap/src/main.c +++ b/samples/shared-heap/src/main.c @@ -19,15 +19,15 @@ thread1_callback(void *arg) wasm_module_inst_t module_inst = targ->module_inst; bh_queue *queue = targ->queue; wasm_exec_env_t exec_env; - wasm_function_inst_t my_shared_malloc_func; - wasm_function_inst_t my_shared_free_func; + wasm_function_inst_t my_shared_heap_malloc_func; + wasm_function_inst_t my_shared_heap_free_func; uint32 i, argv[2]; /* lookup wasm functions */ - if (!(my_shared_malloc_func = - wasm_runtime_lookup_function(module_inst, "my_shared_malloc")) - || !(my_shared_free_func = - wasm_runtime_lookup_function(module_inst, "my_shared_free"))) { + if (!(my_shared_heap_malloc_func = wasm_runtime_lookup_function( + module_inst, "my_shared_heap_malloc")) + || !(my_shared_heap_free_func = wasm_runtime_lookup_function( + module_inst, "my_shared_heap_free"))) { printf("Failed to lookup function.\n"); } @@ -62,17 +62,17 @@ thread1_callback(void *arg) } } - /* allocate memory by calling my_shared_malloc function and send it + /* allocate memory by calling my_shared_heap_malloc function and send it to wasm app2 */ for (i = 5; i < 10; i++) { uint8 *buf; argv[0] = 1024 * (i + 1); argv[1] = i + 1; - wasm_runtime_call_wasm(exec_env, my_shared_malloc_func, 2, argv); + wasm_runtime_call_wasm(exec_env, my_shared_heap_malloc_func, 2, argv); if (wasm_runtime_get_exception(module_inst)) { - printf("Failed to call 'my_shared_malloc` function: %s\n", + printf("Failed to call 'my_shared_heap_malloc' function: %s\n", wasm_runtime_get_exception(module_inst)); break; } @@ -118,6 +118,10 @@ queue_callback(void *message, void *arg) /* call wasm function */ argv[0] = wasm_runtime_addr_native_to_app(module_inst, buf); wasm_runtime_call_wasm(exec_env, print_buf_func, 1, argv); + if (wasm_runtime_get_exception(module_inst)) { + printf("Failed to call 'print_buf' function: %s\n", + wasm_runtime_get_exception(module_inst)); + } } static void * @@ -159,8 +163,17 @@ main(int argc, char **argv) RuntimeInitArgs init_args; SharedHeapInitArgs heap_init_args; char error_buf[128] = { 0 }; + bool aot_mode = false; int ret = -1; + if (argc > 1 && !strcmp(argv[1], "--aot")) + aot_mode = true; + + if (!aot_mode) + printf("Test shared heap in interpreter mode\n\n"); + else + printf("Test shared heap in AOT mode\n\n"); + memset(&init_args, 0, sizeof(RuntimeInitArgs)); init_args.mem_alloc_type = Alloc_With_Pool; @@ -180,7 +193,10 @@ main(int argc, char **argv) } /* read wasm file */ - wasm_file1 = "./wasm-apps/test1.wasm"; + if (!aot_mode) + wasm_file1 = "./wasm-apps/test1.wasm"; + else + wasm_file1 = "./wasm-apps/test1.aot"; if (!(wasm_file1_buf = bh_read_file_to_buffer(wasm_file1, &wasm_file1_size))) { printf("Open wasm file %s failed.\n", wasm_file1); @@ -204,7 +220,10 @@ main(int argc, char **argv) } /* read wasm file */ - wasm_file2 = "./wasm-apps/test2.wasm"; + if (!aot_mode) + wasm_file2 = "./wasm-apps/test2.wasm"; + else + wasm_file2 = "./wasm-apps/test2.aot"; if (!(wasm_file2_buf = bh_read_file_to_buffer(wasm_file2, &wasm_file2_size))) { printf("Open wasm file %s failed.\n", wasm_file1); @@ -273,7 +292,7 @@ main(int argc, char **argv) /* wait until all messages are post to wasm app2 and wasm app2 handles all of them, then exit the queue message loop */ - usleep(2000); + usleep(10000); bh_queue_exit_loop_run(queue); os_thread_join(tid1, NULL); diff --git a/samples/shared-heap/wasm-apps/CMakeLists.txt b/samples/shared-heap/wasm-apps/CMakeLists.txt index 819c4aca36..c0010af6a8 100644 --- a/samples/shared-heap/wasm-apps/CMakeLists.txt +++ b/samples/shared-heap/wasm-apps/CMakeLists.txt @@ -26,12 +26,12 @@ set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") set (DEFINED_SYMBOLS "${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt") set (CMAKE_EXE_LINKER_FLAGS - "-Wl,--initial-memory=65536, \ + "-O0 -Wl,--initial-memory=65536, \ -Wl,--no-entry,--strip-all, \ -Wl,--export=__heap_base,--export=__data_end \ -Wl,--export=__wasm_call_ctors \ - -Wl,--export=my_shared_malloc \ - -Wl,--export=my_shared_free \ + -Wl,--export=my_shared_heap_malloc \ + -Wl,--export=my_shared_heap_free \ -Wl,--export=print_buf \ -Wl,--allow-undefined" ) diff --git a/samples/shared-heap/wasm-apps/test1.c b/samples/shared-heap/wasm-apps/test1.c index 9186df2ce3..c8fe0c7553 100644 --- a/samples/shared-heap/wasm-apps/test1.c +++ b/samples/shared-heap/wasm-apps/test1.c @@ -5,26 +5,56 @@ #include #include +#include extern void * -shared_malloc(uint32_t size); +shared_heap_malloc(uint32_t size); extern void -shared_free(void *ptr); +shared_heap_free(void *ptr); void * -my_shared_malloc(uint32_t size, uint32_t index) +my_shared_heap_malloc(uint32_t size, uint32_t index) { - char *buf = shared_malloc(size); + char *buf1 = NULL, *buf2 = NULL, *buf; - if (buf) - snprintf(buf, 1024, "Hello, this is buf %u allocated from shared heap", - index); + buf1 = shared_heap_malloc(128); + if (!buf1) + return NULL; + buf1[0] = 'H'; + buf1[1] = 'e'; + buf1[2] = 'l'; + buf1[3] = 'l'; + buf1[4] = 'o'; + buf1[5] = ','; + buf1[6] = ' '; + + buf2 = shared_heap_malloc(128); + if (!buf2) { + shared_heap_free(buf1); + return NULL; + } + + snprintf(buf2, 128, "this is buf %u allocated from shared heap", index); + + buf = shared_heap_malloc(size); + if (!buf) { + shared_heap_free(buf1); + shared_heap_free(buf2); + return NULL; + } + + memset(buf, 0, size); + memcpy(buf, buf1, strlen(buf1)); + memcpy(buf + strlen(buf1), buf2, strlen(buf2)); + + shared_heap_free(buf1); + shared_heap_free(buf2); return buf; } void -my_shared_free(void *ptr) +my_shared_heap_free(void *ptr) { - shared_free(ptr); + shared_heap_free(ptr); } diff --git a/samples/shared-heap/wasm-apps/test2.c b/samples/shared-heap/wasm-apps/test2.c index 12af9e52b9..b63efcd1a2 100644 --- a/samples/shared-heap/wasm-apps/test2.c +++ b/samples/shared-heap/wasm-apps/test2.c @@ -8,11 +8,11 @@ #include extern void -shared_free(void *ptr); +shared_heap_free(void *ptr); void print_buf(char *buf) { printf("wasm app2's wasm func received buf: %s\n\n", buf); - shared_free(buf); + shared_heap_free(buf); } diff --git a/tests/unit/shared-heap/wasm-apps/test.c b/tests/unit/shared-heap/wasm-apps/test.c index ce59903c6c..b83ee64ffa 100644 --- a/tests/unit/shared-heap/wasm-apps/test.c +++ b/tests/unit/shared-heap/wasm-apps/test.c @@ -6,17 +6,17 @@ #include extern void * -shared_malloc(int size); +shared_heap_malloc(int size); extern void -shared_free(void *offset); +shared_heap_free(void *offset); int test() { - int *ptr = (int *)shared_malloc(10); + int *ptr = (int *)shared_heap_malloc(10); *ptr = 10; int a = *ptr; - shared_free(ptr); + shared_heap_free(ptr); return a; -} \ No newline at end of file +} diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 8dca712cd1..3efe344e6a 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -206,6 +206,7 @@ print_help() printf(" --enable-linux-perf Enable linux perf support\n"); #endif printf(" --mllvm=