Compare commits

...

2 Commits

Author SHA1 Message Date
TianlongLiang
969072567a
Address cr comments and some refactor (#4439)
Some checks are pending
compilation on SGX / run_samples_file (-DWAMR_BUILD_SGX_IPFS=1, $AOT_BUILD_OPTIONS, ${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, linux-sgx) (push) Blocked by required conditions
compilation on SGX / run_samples_file (-DWAMR_BUILD_SGX_IPFS=1, $CLASSIC_INTERP_BUILD_OPTIONS, ${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, linux-sgx) (push) Blocked by required conditions
compilation on SGX / run_samples_file (-DWAMR_BUILD_SGX_IPFS=1, $FAST_INTERP_BUILD_OPTIONS, ${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, linux-sgx) (push) Blocked by required conditions
compilation on SGX / run_samples_file (-DWAMR_BUILD_SGX_IPFS=1, $FAST_JIT_BUILD_OPTIONS, ${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, linux-sgx) (push) Blocked by required conditions
compilation on SGX / spec_test_default (${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, aot, $DEFAULT_TEST_OPTIONS) (push) Blocked by required conditions
compilation on SGX / spec_test_default (${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, aot, $SIMD_TEST_OPTIONS) (push) Blocked by required conditions
compilation on SGX / spec_test_default (${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, aot, $XIP_TEST_OPTIONS) (push) Blocked by required conditions
compilation on SGX / spec_test_default (${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, classic-interp, $DEFAULT_TEST_OPTIONS) (push) Blocked by required conditions
compilation on SGX / spec_test_default (${{ needs.build_llvm_libraries.outputs.cache_key }}, ubuntu-22.04, fast-jit, $DEFAULT_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / build_llvm_libraries_on_windows (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_AOT=0) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_CUSTOM_NAME_SECTION=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_DEBUG_INTERP=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_LIB_PTHREAD=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_LIB_WASI_THREADS=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_REF_TYPES=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_SIMD=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_BUILD_TAIL_CALL=1) (push) Waiting to run
compilation on windows-latest / build_iwasm (-DWAMR_DISABLE_HW_BOUND_CHECK=1) (push) Waiting to run
compilation on windows-latest / build_wamrc (${{ needs.build_llvm_libraries_on_windows.outputs.cache_key }}, windows-latest) (push) Blocked by required conditions
compilation on windows-latest / test (classic-interp, $DEFAULT_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (classic-interp, $MULTI_MODULES_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (classic-interp, $THREADS_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (classic-interp, $WASI_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (fast-interp, $DEFAULT_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (fast-interp, $MULTI_MODULES_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (fast-interp, $THREADS_TEST_OPTIONS) (push) Blocked by required conditions
compilation on windows-latest / test (fast-interp, $WASI_TEST_OPTIONS) (push) Blocked by required conditions
2025-07-02 20:19:42 +08:00
TianlongLiang
ccdc8369d6
Shared heap enhancement for AOT and update tests and samples (#4226)
* shared heap enhancement: modify memory check for aot_check_memory_overflow to accomodate shared heap chain
* shared heap enhancement in AOT
* use alloca for func ctx shared heap cache value
* use correct alloca for func ctx shared heap cache value
* enable shared heap chain aot test and bug fix
* Fix a missing argument on 32bits platform, still has the shared heap chain iteration problem
* Fix shared heap chain iteration problem on 32bits platform
* fix AOT bulk memory bounds checks compliation issue
* fix AOT bulk memory bounds checks on 64 bits platform
* refactor aot memory check
* refactor AOT bulk memory bounds checks
* add more unit test for shared heap
* finished organizing unit test for shared heap and enable x86_32 for shared heap unit test
* cover a corner case for bulk memory overflow check
* try func call to replace shared heap chain traverse
* fix compilation error in JIT and potentially load nullptr
* add option for wamrc to enable single shared heap/multi shared heap, and update shared heap unit tests and sample
* cr suggestions: 1. check potiential underflow 2. refactor and use separate function for bulk memory and normal memroy 3. static assert 4. add more comments 5. remove unused code
2025-06-19 21:42:53 +08:00
25 changed files with 1376 additions and 410 deletions

View File

@ -185,6 +185,13 @@ typedef struct {
#define REG_STRINGREF_SYM() #define REG_STRINGREF_SYM()
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
#define REG_SHARED_HEAP_SYM() \
REG_SYM(wasm_runtime_check_and_update_last_used_shared_heap),
#else
#define REG_SHARED_HEAP_SYM()
#endif
#define REG_COMMON_SYMBOLS \ #define REG_COMMON_SYMBOLS \
REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_set_exception_with_id), \
REG_SYM(aot_invoke_native), \ REG_SYM(aot_invoke_native), \
@ -218,6 +225,7 @@ typedef struct {
REG_LLVM_PGO_SYM() \ REG_LLVM_PGO_SYM() \
REG_GC_SYM() \ REG_GC_SYM() \
REG_STRINGREF_SYM() \ REG_STRINGREF_SYM() \
REG_SHARED_HEAP_SYM() \
#define CHECK_RELOC_OFFSET(data_size) do { \ #define CHECK_RELOC_OFFSET(data_size) do { \
if (!check_reloc_offset(target_section_size, \ if (!check_reloc_offset(target_section_size, \

View File

@ -63,6 +63,14 @@ bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_start_off) == 16);
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_end_off) == 24); bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_end_off) == 24);
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap) == 32); bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap) == 32);
bh_static_assert(offsetof(WASMSharedHeap, next) == 0);
bh_static_assert(offsetof(WASMSharedHeap, chain_next) == 8);
bh_static_assert(offsetof(WASMSharedHeap, heap_handle) == 16);
bh_static_assert(offsetof(WASMSharedHeap, base_addr) == 24);
bh_static_assert(offsetof(WASMSharedHeap, size) == 32);
bh_static_assert(offsetof(WASMSharedHeap, start_off_mem64) == 40);
bh_static_assert(offsetof(WASMSharedHeap, start_off_mem32) == 48);
bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3); bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3);
bh_static_assert(sizeof(wasm_val_t) == 16); bh_static_assert(sizeof(wasm_val_t) == 16);
@ -1991,6 +1999,8 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
#else #else
extra->shared_heap_start_off.u32[0] = UINT32_MAX; extra->shared_heap_start_off.u32[0] = UINT32_MAX;
#endif #endif
/* After shared heap chain, will early stop if shared heap is NULL */
extra->shared_heap = NULL;
#if WASM_ENABLE_PERF_PROFILING != 0 #if WASM_ENABLE_PERF_PROFILING != 0
total_size = sizeof(AOTFuncPerfProfInfo) total_size = sizeof(AOTFuncPerfProfInfo)

View File

@ -178,16 +178,16 @@ wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args)
} }
size = align_uint(size, os_getpagesize()); size = align_uint(size, os_getpagesize());
heap->size = size;
heap->start_off_mem64 = UINT64_MAX - heap->size + 1;
heap->start_off_mem32 = UINT32_MAX - heap->size + 1;
heap->attached_count = 0;
if (size > APP_HEAP_SIZE_MAX || size < APP_HEAP_SIZE_MIN) { if (size > APP_HEAP_SIZE_MAX || size < APP_HEAP_SIZE_MIN) {
LOG_WARNING("Invalid size of shared heap"); LOG_WARNING("Invalid size of shared heap");
goto fail2; goto fail2;
} }
heap->size = size;
heap->start_off_mem64 = UINT64_MAX - heap->size + 1;
heap->start_off_mem32 = UINT32_MAX - heap->size + 1;
heap->attached_count = 0;
if (init_args->pre_allocated_addr != NULL) { if (init_args->pre_allocated_addr != NULL) {
/* Create shared heap from a pre allocated buffer, its size need to /* Create shared heap from a pre allocated buffer, its size need to
* align with system page */ * align with system page */
@ -275,6 +275,13 @@ wasm_runtime_chain_shared_heaps(WASMSharedHeap *head, WASMSharedHeap *body)
os_mutex_unlock(&shared_heap_list_lock); os_mutex_unlock(&shared_heap_list_lock);
return NULL; return NULL;
} }
if (cur == head && cur->chain_next) {
LOG_WARNING(
"To create shared heap chain, the 'head' shared heap can't "
"already be the 'head' in another a chain");
os_mutex_unlock(&shared_heap_list_lock);
return NULL;
}
} }
for (cur = body; cur; cur = cur->chain_next) { for (cur = body; cur; cur = cur->chain_next) {
if (cur->heap_handle && heap_handle_exist) { if (cur->heap_handle && heap_handle_exist) {
@ -519,6 +526,10 @@ wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
void void
wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst) wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst)
{ {
/* Reset shared_heap_end_off = UINT64/32_MAX - 1 to handling a corner case,
app_offset >= shared_heap_start && app_offset <= shared_heap_end-bytes+1
when bytes=1 and both e->shared_heap_start_off and e->shared_heap_end_off
is 0xffffffff */
#if WASM_ENABLE_INTERP != 0 #if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) { if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMModuleInstanceExtra *e = WASMModuleInstanceExtra *e =
@ -614,7 +625,7 @@ is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
shared_heap_start = shared_heap_start =
(uint64)get_last_used_shared_heap_start_offset(module_inst); (uint64)get_last_used_shared_heap_start_offset(module_inst);
shared_heap_end = (uint64)get_last_used_shared_heap_end_offset(module_inst); shared_heap_end = (uint64)get_last_used_shared_heap_end_offset(module_inst);
if (app_offset >= shared_heap_start if (bytes - 1 <= shared_heap_end && app_offset >= shared_heap_start
&& app_offset <= shared_heap_end - bytes + 1) { && app_offset <= shared_heap_end - bytes + 1) {
return true; return true;
} }
@ -623,7 +634,7 @@ is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
shared_heap_start = shared_heap_start =
is_memory64 ? heap->start_off_mem64 : heap->start_off_mem32; is_memory64 ? heap->start_off_mem64 : heap->start_off_mem32;
shared_heap_end = is_memory64 ? UINT64_MAX : UINT32_MAX; shared_heap_end = is_memory64 ? UINT64_MAX : UINT32_MAX;
if (app_offset < shared_heap_start if (bytes - 1 > shared_heap_end || app_offset < shared_heap_start
|| app_offset > shared_heap_end - bytes + 1) { || app_offset > shared_heap_end - bytes + 1) {
goto fail; goto fail;
} }
@ -634,7 +645,7 @@ is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
shared_heap_start = shared_heap_start =
is_memory64 ? cur->start_off_mem64 : cur->start_off_mem32; is_memory64 ? cur->start_off_mem64 : cur->start_off_mem32;
shared_heap_end = shared_heap_start - 1 + cur->size; shared_heap_end = shared_heap_start - 1 + cur->size;
if (app_offset >= shared_heap_start if (bytes - 1 <= shared_heap_end && app_offset >= shared_heap_start
&& app_offset <= shared_heap_end - bytes + 1) { && app_offset <= shared_heap_end - bytes + 1) {
update_last_used_shared_heap(module_inst, cur, is_memory64); update_last_used_shared_heap(module_inst, cur, is_memory64);
return true; return true;
@ -1072,7 +1083,7 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
shared_heap_base_addr_adj = shared_heap_base_addr_adj =
(char *)get_last_used_shared_heap_base_addr_adj(module_inst_comm); (char *)get_last_used_shared_heap_base_addr_adj(module_inst_comm);
str = shared_heap_base_addr_adj + app_str_offset; str = shared_heap_base_addr_adj + app_str_offset;
str_end = shared_heap_base_addr_adj + shared_heap_end_off; str_end = shared_heap_base_addr_adj + shared_heap_end_off + 1;
} }
else else
#endif #endif
@ -1227,7 +1238,9 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
#if WASM_ENABLE_SHARED_HEAP != 0 #if WASM_ENABLE_SHARED_HEAP != 0
if (is_native_addr_in_shared_heap(module_inst_comm, if (is_native_addr_in_shared_heap(module_inst_comm,
memory_inst->is_memory64, addr, 1)) { memory_inst->is_memory64, addr, 1)) {
return addr - get_last_used_shared_heap_base_addr_adj(module_inst_comm); return (uint64)(uintptr_t)(addr
- get_last_used_shared_heap_base_addr_adj(
module_inst_comm));
} }
#endif #endif
@ -1349,11 +1362,12 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
(WASMModuleInstanceCommon *)module_inst); (WASMModuleInstanceCommon *)module_inst);
shared_heap_end_off = get_last_used_shared_heap_end_offset( shared_heap_end_off = get_last_used_shared_heap_end_offset(
(WASMModuleInstanceCommon *)module_inst); (WASMModuleInstanceCommon *)module_inst);
native_addr = shared_heap_base_addr_adj + app_buf_addr; native_addr = shared_heap_base_addr_adj + (uintptr_t)app_buf_addr;
/* The whole string must be in the shared heap */ /* The whole string must be in the shared heap */
str = (const char *)native_addr; str = (const char *)native_addr;
str_end = (const char *)shared_heap_base_addr_adj + shared_heap_end_off; str_end =
(const char *)shared_heap_base_addr_adj + shared_heap_end_off + 1;
while (str < str_end && *str != '\0') while (str < str_end && *str != '\0')
str++; str++;
if (str == str_end) { if (str == str_end) {

View File

@ -7883,3 +7883,37 @@ wasm_runtime_is_underlying_binary_freeable(WASMModuleCommon *const module)
return true; return true;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
bool
wasm_runtime_check_and_update_last_used_shared_heap(
WASMModuleInstanceCommon *module_inst, uintptr_t app_offset, size_t bytes,
uintptr_t *shared_heap_start_off_p, uintptr_t *shared_heap_end_off_p,
uint8 **shared_heap_base_addr_adj_p, bool is_memory64)
{
WASMSharedHeap *heap = wasm_runtime_get_shared_heap(module_inst), *cur;
uint64 shared_heap_start, shared_heap_end;
if (bytes == 0) {
bytes = 1;
}
/* Find the exact shared heap that app addr is in, and update last used
* shared heap info in func context */
for (cur = heap; cur; cur = cur->chain_next) {
shared_heap_start =
is_memory64 ? cur->start_off_mem64 : cur->start_off_mem32;
shared_heap_end = shared_heap_start - 1 + cur->size;
if (bytes - 1 <= shared_heap_end && app_offset >= shared_heap_start
&& app_offset <= shared_heap_end - bytes + 1) {
*shared_heap_start_off_p = (uintptr_t)shared_heap_start;
*shared_heap_end_off_p = (uintptr_t)shared_heap_end;
*shared_heap_base_addr_adj_p =
cur->base_addr - (uintptr_t)shared_heap_start;
return true;
}
}
return false;
}
#endif

View File

@ -1336,6 +1336,14 @@ void
wasm_runtime_set_linux_perf(bool flag); wasm_runtime_set_linux_perf(bool flag);
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
bool
wasm_runtime_check_and_update_last_used_shared_heap(
WASMModuleInstanceCommon *module_inst, uintptr_t app_offset, size_t bytes,
uintptr_t *shared_heap_start_off_p, uintptr_t *shared_heap_end_off_p,
uint8 **shared_heap_base_addr_adj_p, bool is_memory64);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -10,6 +10,40 @@
#include "aot_intrinsic.h" #include "aot_intrinsic.h"
#include "aot_emit_control.h" #include "aot_emit_control.h"
#define BUILD_IS_NOT_NULL(value, res, name) \
do { \
if (!(res = LLVMBuildIsNotNull(comp_ctx->builder, value, name))) { \
aot_set_last_error("llvm build is not null failed."); \
goto fail; \
} \
} while (0)
#define BUILD_BR(llvm_block) \
do { \
if (!LLVMBuildBr(comp_ctx->builder, llvm_block)) { \
aot_set_last_error("llvm build br failed."); \
goto fail; \
} \
} while (0)
#define BUILD_COND_BR(value_if, block_then, block_else) \
do { \
if (!LLVMBuildCondBr(comp_ctx->builder, value_if, block_then, \
block_else)) { \
aot_set_last_error("llvm build cond br failed."); \
goto fail; \
} \
} while (0)
#define BUILD_TRUNC(value, data_type) \
do { \
if (!(value = LLVMBuildTrunc(comp_ctx->builder, value, data_type, \
"val_trunc"))) { \
aot_set_last_error("llvm build trunc failed."); \
goto fail; \
} \
} while (0)
#define BUILD_ICMP(op, left, right, res, name) \ #define BUILD_ICMP(op, left, right, res, name) \
do { \ do { \
if (!(res = \ if (!(res = \
@ -111,6 +145,418 @@ ffs(int n)
static LLVMValueRef static LLVMValueRef
get_memory_curr_page_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); get_memory_curr_page_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
#if WASM_ENABLE_SHARED_HEAP != 0
uint32
get_module_inst_extra_offset(AOTCompContext *comp_ctx);
#define BUILD_LOAD_PTR(ptr, data_type, res) \
do { \
if (!(res = LLVMBuildLoad2(comp_ctx->builder, data_type, ptr, \
"load_value"))) { \
aot_set_last_error("llvm build load failed"); \
goto fail; \
} \
} while (0)
/* Update last used shared heap info(alloc ptr) in function ctx:
* 1. shared_heap_start_off 2. shared_heap_end_off 3. shared_heap_base_addr_adj
*/
bool
aot_check_shared_heap_chain_and_update(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMBasicBlockRef check_succ,
LLVMValueRef start_offset,
LLVMValueRef bytes, bool is_memory64)
{
LLVMValueRef param_values[7], ret_value, func, value, cmp;
LLVMTypeRef param_types[7], ret_type, func_type, func_ptr_type;
param_types[0] = INT8_PTR_TYPE;
param_types[1] = INTPTR_T_TYPE;
param_types[2] = SIZE_T_TYPE;
param_types[3] = INTPTR_T_PTR_TYPE;
param_types[4] = INTPTR_T_PTR_TYPE;
param_types[5] = INT8_PTR_TYPE;
param_types[6] = INT8_TYPE;
ret_type = INT8_TYPE;
GET_AOT_FUNCTION(wasm_runtime_check_and_update_last_used_shared_heap, 7);
/* Call function */
param_values[0] = func_ctx->aot_inst;
param_values[1] = start_offset;
param_values[2] = bytes;
/* pass alloc ptr */
param_values[3] = func_ctx->shared_heap_start_off;
param_values[4] = func_ctx->shared_heap_end_off;
param_values[5] = func_ctx->shared_heap_base_addr_adj;
param_values[6] = is_memory64 ? I8_ONE : I8_ZERO;
if (!(ret_value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
param_values, 7, "call"))) {
aot_set_last_error("llvm build call failed.");
goto fail;
}
BUILD_ICMP(LLVMIntEQ, ret_value, I8_ZERO, cmp, "shared_heap_oob");
if (!aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp,
check_succ)) {
goto fail;
}
return true;
fail:
return false;
}
/*
* Setup the basic blocks for shared heap and shared chain memory checks.
*
* Arguments:
* block_curr: The current basic block.
* app_addr_in_cache_shared_heap: Output, block for cache shared heap.
* app_addr_in_linear_mem: Output, block for linear memory.
* app_addr_in_shared_heap_chain: Output, block for shared heap chain
* (only for shared heap chain).
* check_shared_heap_chain: Output, block for checking shared heap chain
* (only for shared heap chain).
*
* Topology:
* If enable_shared_heap:
* block_curr -> app_addr_in_cache_shared_heap
* -> app_addr_in_linear_mem
* If enable_shared_chain:
* block_curr -> app_addr_in_shared_heap_chain
* -> app_addr_in_cache_shared_heap
* -> check_shared_heap_chain
* -> app_addr_in_linear_mem
*/
static bool
setup_shared_heap_blocks(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef block_curr,
LLVMBasicBlockRef *app_addr_in_cache_shared_heap,
LLVMBasicBlockRef *app_addr_in_linear_mem,
LLVMBasicBlockRef *app_addr_in_shared_heap_chain,
LLVMBasicBlockRef *check_shared_heap_chain)
{
ADD_BASIC_BLOCK(*app_addr_in_cache_shared_heap,
"app_addr_in_cache_shared_heap");
ADD_BASIC_BLOCK(*app_addr_in_linear_mem, "app_addr_in_linear_mem");
if (comp_ctx->enable_shared_heap) {
LLVMMoveBasicBlockAfter(*app_addr_in_cache_shared_heap, block_curr);
LLVMMoveBasicBlockAfter(*app_addr_in_linear_mem,
*app_addr_in_cache_shared_heap);
}
else if (comp_ctx->enable_shared_chain) {
ADD_BASIC_BLOCK(*app_addr_in_shared_heap_chain,
"app_addr_in_shared_heap_chain");
ADD_BASIC_BLOCK(*check_shared_heap_chain, "check_shared_heap_chain");
LLVMMoveBasicBlockAfter(*app_addr_in_shared_heap_chain, block_curr);
LLVMMoveBasicBlockAfter(*app_addr_in_cache_shared_heap,
*app_addr_in_shared_heap_chain);
LLVMMoveBasicBlockAfter(*check_shared_heap_chain,
*app_addr_in_cache_shared_heap);
LLVMMoveBasicBlockAfter(*app_addr_in_linear_mem,
*app_addr_in_cache_shared_heap);
}
return true;
fail:
return false;
}
/*
* Build a branch to check if start_offset is in the shared heap chain region.
*
* Arguments:
* start_offset: The offset to check.
* app_addr_in_shared_heap_chain: Block to branch if in shared heap chain.
* app_addr_in_linear_mem: Block to branch if not in shared heap chain.
*/
static bool
build_check_app_addr_in_shared_heap_chain(
AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef start_offset, LLVMBasicBlockRef app_addr_in_shared_heap_chain,
LLVMBasicBlockRef app_addr_in_linear_mem)
{
LLVMValueRef is_in_shared_heap = NULL;
/* Use start_offset > func_ctx->shared_heap_head_start_off to test
* start_off falls in shared heap chain memory region. The shared heap
* chain oob will be detected in app_addr_in_shared_heap block or
* aot_check_shared_heap_chain_and_update function
*/
BUILD_ICMP(LLVMIntUGT, start_offset, func_ctx->shared_heap_head_start_off,
is_in_shared_heap, "shared_heap_lb_cmp");
BUILD_COND_BR(is_in_shared_heap, app_addr_in_shared_heap_chain,
app_addr_in_linear_mem);
SET_BUILD_POS(app_addr_in_shared_heap_chain);
return true;
fail:
return false;
}
/*
* Build the conditional branch for cache shared heap or shared heap chain.
*
* Arguments:
* cmp: The condition for being in cache shared heap.
* app_addr_in_cache_shared_heap: Block for cache shared heap.
* app_addr_in_linear_mem: Block for linear memory.
* check_shared_heap_chain: Block for checking shared heap chain.
* bytes: The access size in bytes.
* start_offset: The offset to check.
* is_memory64: Whether memory is 64-bit.
*/
static bool
build_shared_heap_conditional_branching(
AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef cmp,
LLVMBasicBlockRef app_addr_in_cache_shared_heap,
LLVMBasicBlockRef app_addr_in_linear_mem,
LLVMBasicBlockRef check_shared_heap_chain, LLVMValueRef bytes,
LLVMValueRef start_offset, bool is_memory64)
{
if (comp_ctx->enable_shared_heap) {
BUILD_COND_BR(cmp, app_addr_in_cache_shared_heap,
app_addr_in_linear_mem);
}
else if (comp_ctx->enable_shared_chain) {
BUILD_COND_BR(cmp, app_addr_in_cache_shared_heap,
check_shared_heap_chain);
SET_BUILD_POS(check_shared_heap_chain);
if (!aot_check_shared_heap_chain_and_update(
comp_ctx, func_ctx, app_addr_in_cache_shared_heap, start_offset,
bytes, is_memory64))
goto fail;
}
return true;
fail:
return false;
}
/*
* Get the native address in the cache shared heap.
*
* Arguments:
* start_offset: The offset to use for address calculation.
* maddr: Output, the native address that in the cache shared heap.
*/
static bool
build_get_maddr_in_cache_shared_heap(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMValueRef start_offset,
LLVMValueRef *maddr)
{
LLVMValueRef shared_heap_base_addr_adj;
/* load the local variable */
BUILD_LOAD_PTR(func_ctx->shared_heap_base_addr_adj, INT8_PTR_TYPE,
shared_heap_base_addr_adj);
if (!(*maddr = LLVMBuildInBoundsGEP2(
comp_ctx->builder, INT8_TYPE, shared_heap_base_addr_adj,
&start_offset, 1, "maddr_cache_shared_heap"))) {
aot_set_last_error("llvm build inbounds gep failed");
goto fail;
}
return true;
fail:
return false;
}
/*
* Check for memory overflow in shared heap for normal memory access.
*
* Arguments:
* block_curr: The current basic block.
* block_maddr_phi: The phi block for memory address.
* maddr_phi: The phi node for memory address.
* start_offset: The first offset to check.
* mem_base_addr: The base address of memory. Only used with segue.
* bytes_u32: The access size in bytes.
* is_memory64: Whether memory is wasm64 memory.
* is_target_64bit: Whether target is 64-bit.
* enable_segue: Whether to use segment register addressing.
*/
static bool
aot_check_shared_heap_memory_overflow(
AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef block_curr, LLVMBasicBlockRef block_maddr_phi,
LLVMValueRef maddr_phi, LLVMValueRef start_offset,
LLVMValueRef mem_base_addr, uint32 bytes_u32, bool is_memory64,
bool is_target_64bit, bool enable_segue)
{
LLVMBasicBlockRef app_addr_in_cache_shared_heap, app_addr_in_linear_mem;
LLVMBasicBlockRef app_addr_in_shared_heap_chain = NULL,
check_shared_heap_chain = NULL;
LLVMValueRef cmp, cmp1, cmp2, shared_heap_start_off, shared_heap_end_off,
shared_heap_check_bound, maddr = NULL;
/* On 64/32-bit target, the offset is 64/32-bit */
LLVMTypeRef offset_type = is_target_64bit ? I64_TYPE : I32_TYPE;
LLVMValueRef length, bytes;
if (!setup_shared_heap_blocks(
comp_ctx, func_ctx, block_curr, &app_addr_in_cache_shared_heap,
&app_addr_in_linear_mem, &app_addr_in_shared_heap_chain,
&check_shared_heap_chain))
goto fail;
LLVMMoveBasicBlockAfter(block_maddr_phi, app_addr_in_linear_mem);
/* Early branching when it's not in shared heap chain at all */
if (comp_ctx->enable_shared_chain
&& !build_check_app_addr_in_shared_heap_chain(
comp_ctx, func_ctx, start_offset, app_addr_in_shared_heap_chain,
app_addr_in_linear_mem))
goto fail;
/* Load the local variable of the function */
BUILD_LOAD_PTR(func_ctx->shared_heap_start_off, offset_type,
shared_heap_start_off);
BUILD_LOAD_PTR(func_ctx->shared_heap_end_off, offset_type,
shared_heap_end_off);
/* Check if the app address is in the cache shared heap range.
* If yes, branch to the cache branch; if not, check the shared heap chain
*/
BUILD_ICMP(LLVMIntUGE, start_offset, shared_heap_start_off, cmp,
"cmp_cache_shared_heap_start");
length =
is_target_64bit ? I64_CONST(bytes_u32 - 1) : I32_CONST(bytes_u32 - 1);
CHECK_LLVM_CONST(length);
BUILD_OP(Sub, shared_heap_end_off, length, shared_heap_check_bound,
"cache_shared_heap_end_bound");
BUILD_ICMP(LLVMIntULE, start_offset, shared_heap_check_bound, cmp1,
"cmp_cache_shared_heap_end");
BUILD_OP(And, cmp, cmp1, cmp2, "is_in_cache_shared_heap");
/* Conditional branching based on whether in cached shared heap */
bytes = is_target_64bit ? I64_CONST(bytes_u32) : I32_CONST(bytes_u32);
if (!build_shared_heap_conditional_branching(
comp_ctx, func_ctx, cmp2, app_addr_in_cache_shared_heap,
app_addr_in_linear_mem, check_shared_heap_chain, bytes,
start_offset, is_memory64))
goto fail;
SET_BUILD_POS(app_addr_in_cache_shared_heap);
if (!build_get_maddr_in_cache_shared_heap(comp_ctx, func_ctx, start_offset,
&maddr))
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_cache_shared_heap, 1);
BUILD_BR(block_maddr_phi);
SET_BUILD_POS(app_addr_in_linear_mem);
return true;
fail:
return false;
}
/*
* Check for memory overflow in shared heap for bulk memory access.
*
* Arguments:
* block_curr: The current basic block.
* block_maddr_phi: The phi block for memory address.
* check_succ: The block to branch to on success.
* maddr_phi: The phi node for memory address.
* start_offset: The offset to check.
* max_addr: The maximum address to check.
* bytes: The access size in bytes (LLVMValueRef).
* is_memory64: Whether memory is wasm64 memory.
* is_target_64bit: Whether target is 64-bit.
*/
static bool
aot_check_bulk_memory_shared_heap_memory_overflow(
AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMBasicBlockRef block_curr, LLVMBasicBlockRef block_maddr_phi,
LLVMBasicBlockRef check_succ, LLVMValueRef maddr_phi,
LLVMValueRef start_offset, LLVMValueRef max_addr, LLVMValueRef bytes,
bool is_memory64, bool is_target_64bit)
{
LLVMBasicBlockRef app_addr_in_cache_shared_heap, app_addr_in_linear_mem;
LLVMBasicBlockRef app_addr_in_shared_heap_chain = NULL,
check_shared_heap_chain = NULL;
LLVMValueRef cmp, cmp1, cmp2, shared_heap_start_off, shared_heap_end_off,
maddr = NULL, max_offset;
/* On 64/32-bit target, the offset is 64/32-bit */
LLVMTypeRef offset_type = is_target_64bit ? I64_TYPE : I32_TYPE;
if (!setup_shared_heap_blocks(
comp_ctx, func_ctx, block_curr, &app_addr_in_cache_shared_heap,
&app_addr_in_linear_mem, &app_addr_in_shared_heap_chain,
&check_shared_heap_chain))
goto fail;
LLVMMoveBasicBlockAfter(block_maddr_phi, check_succ);
/* Early branching when it's not in shared heap chain at all */
if (comp_ctx->enable_shared_chain
&& !build_check_app_addr_in_shared_heap_chain(
comp_ctx, func_ctx, start_offset, app_addr_in_shared_heap_chain,
app_addr_in_linear_mem))
goto fail;
/* Load the local variable of the function */
BUILD_LOAD_PTR(func_ctx->shared_heap_start_off, offset_type,
shared_heap_start_off);
BUILD_LOAD_PTR(func_ctx->shared_heap_end_off, offset_type,
shared_heap_end_off);
/* Check if the app address is in the cache shared heap range.
* If yes, branch to the cache branch; if not, check the shared heap chain
*/
BUILD_ICMP(LLVMIntUGE, start_offset, shared_heap_start_off, cmp,
"cmp_cache_shared_heap_start");
BUILD_OP(Add, max_addr, is_target_64bit ? I64_NEG_ONE : I32_NEG_ONE,
max_offset, "max_offset");
BUILD_ICMP(LLVMIntULE, max_offset, shared_heap_end_off, cmp1,
"cmp_cache_shared_heap_end");
BUILD_OP(And, cmp, cmp1, cmp2, "is_in_cache_shared_heap");
/* Conditional branching based on whether in cached shared heap */
if (!build_shared_heap_conditional_branching(
comp_ctx, func_ctx, cmp2, app_addr_in_cache_shared_heap,
app_addr_in_linear_mem, check_shared_heap_chain, bytes,
start_offset, is_memory64))
goto fail;
SET_BUILD_POS(app_addr_in_cache_shared_heap);
if (!build_get_maddr_in_cache_shared_heap(comp_ctx, func_ctx, start_offset,
&maddr))
goto fail;
LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_cache_shared_heap, 1);
BUILD_BR(block_maddr_phi);
SET_BUILD_POS(app_addr_in_linear_mem);
return true;
fail:
return false;
}
#endif
LLVMValueRef LLVMValueRef
aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
mem_offset_t offset, uint32 bytes, bool enable_segue, mem_offset_t offset, uint32 bytes, bool enable_segue,
@ -118,10 +564,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
{ {
LLVMValueRef offset_const = LLVMValueRef offset_const =
MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset)); MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset));
LLVMValueRef addr, maddr, maddr_phi = NULL, offset1, cmp1, cmp2, cmp; LLVMValueRef addr, maddr, offset1, cmp1, cmp;
LLVMValueRef mem_base_addr, mem_check_bound; LLVMValueRef mem_base_addr, mem_check_bound;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef check_succ, block_maddr_phi = NULL; LLVMBasicBlockRef check_succ;
AOTValue *aot_value_top; AOTValue *aot_value_top;
uint32 local_idx_of_aot_value = 0; uint32 local_idx_of_aot_value = 0;
uint64 const_value; uint64 const_value;
@ -136,6 +582,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
#else #else
bool is_memory64 = IS_MEMORY64; bool is_memory64 = IS_MEMORY64;
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
LLVMValueRef maddr_phi = NULL;
LLVMBasicBlockRef block_maddr_phi = NULL;
#endif
is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false; is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
@ -262,6 +712,13 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
*alignp = 1; *alignp = 1;
} }
/* The overflow check needs to be done under following conditions:
* 1. In 64-bit target, offset and addr will be extended to 64-bit
* 1.1 offset + addr can overflow when it's memory64
* 1.2 no overflow when it's memory32
* 2. In 32-bit target, offset and addr will be 32-bit
* 2.1 offset + addr can overflow when it's memory32
*/
if (is_target_64bit) { if (is_target_64bit) {
if (!(offset_const = LLVMBuildZExt(comp_ctx->builder, offset_const, if (!(offset_const = LLVMBuildZExt(comp_ctx->builder, offset_const,
I64_TYPE, "offset_i64")) I64_TYPE, "offset_i64"))
@ -275,7 +732,9 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* offset1 = offset + addr; */ /* offset1 = offset + addr; */
BUILD_OP(Add, offset_const, addr, offset1, "offset1"); BUILD_OP(Add, offset_const, addr, offset1, "offset1");
if (is_memory64 && comp_ctx->enable_bound_check) { /* 1.1 offset + addr can overflow when it's memory64
* 2.1 Or when it's on 32-bit platform */
if (is_memory64 || !is_target_64bit) {
/* Check whether integer overflow occurs in offset + addr */ /* Check whether integer overflow occurs in offset + addr */
LLVMBasicBlockRef check_integer_overflow_end; LLVMBasicBlockRef check_integer_overflow_end;
ADD_BASIC_BLOCK(check_integer_overflow_end, ADD_BASIC_BLOCK(check_integer_overflow_end,
@ -289,23 +748,14 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail; goto fail;
} }
SET_BUILD_POS(check_integer_overflow_end); SET_BUILD_POS(check_integer_overflow_end);
block_curr = check_integer_overflow_end;
} }
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { #if WASM_ENABLE_SHARED_HEAP != 0
LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem; if (comp_ctx->enable_shared_heap
LLVMValueRef is_in_shared_heap, shared_heap_check_bound = NULL; || comp_ctx->enable_shared_chain /* TODO: && mem_idx == 0 */) {
/* 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"); ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
SET_BUILD_POS(block_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 = if (!(maddr_phi =
LLVMBuildPhi(comp_ctx->builder, LLVMBuildPhi(comp_ctx->builder,
enable_segue ? INT8_PTR_TYPE_GS : INT8_PTR_TYPE, enable_segue ? INT8_PTR_TYPE_GS : INT8_PTR_TYPE,
@ -313,110 +763,16 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
aot_set_last_error("llvm build phi failed"); aot_set_last_error("llvm build phi failed");
goto fail; goto fail;
} }
SET_BUILD_POS(block_curr);
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); if (!aot_check_shared_heap_memory_overflow(
comp_ctx, func_ctx, block_curr, block_maddr_phi, maddr_phi,
if (!is_target_64bit) { offset1, mem_base_addr, bytes, is_memory64, is_target_64bit,
/* Check whether integer overflow occurs in addr + offset */ enable_segue)) {
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 accessed, (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; goto fail;
} }
} }
#endif
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 if (comp_ctx->enable_bound_check
&& !(is_local_of_aot_value && !(is_local_of_aot_value
@ -449,21 +805,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail; goto fail;
} }
if (is_target_64bit) {
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
}
else {
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 */ /* Add basic blocks */
ADD_BASIC_BLOCK(check_succ, "check_succ"); ADD_BASIC_BLOCK(check_succ, "check_succ");
@ -509,17 +851,20 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
} }
} }
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { #if WASM_ENABLE_SHARED_HEAP != 0
if (comp_ctx->enable_shared_heap
|| comp_ctx->enable_shared_chain /* TODO: && mem_idx == 0 */) {
block_curr = LLVMGetInsertBlock(comp_ctx->builder); block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1); LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
aot_set_last_error("llvm build br failed"); aot_set_last_error("llvm build br failed");
goto fail; goto fail;
} }
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi); SET_BUILD_POS(block_maddr_phi);
return maddr_phi; return maddr_phi;
} }
else else
#endif
return maddr; return maddr;
fail: fail:
return NULL; return NULL;
@ -544,15 +889,6 @@ fail:
LLVMSetAlignment(value, known_align); \ LLVMSetAlignment(value, known_align); \
} while (0) } while (0)
#define BUILD_TRUNC(value, data_type) \
do { \
if (!(value = LLVMBuildTrunc(comp_ctx->builder, value, data_type, \
"val_trunc"))) { \
aot_set_last_error("llvm build trunc failed."); \
goto fail; \
} \
} while (0)
#define BUILD_STORE() \ #define BUILD_STORE() \
do { \ do { \
LLVMValueRef res; \ LLVMValueRef res; \
@ -1150,16 +1486,23 @@ LLVMValueRef
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef offset, LLVMValueRef bytes) LLVMValueRef offset, LLVMValueRef bytes)
{ {
LLVMValueRef maddr, max_addr, cmp; LLVMValueRef maddr, max_addr, cmp, cmp1;
LLVMValueRef mem_base_addr, maddr_phi = NULL; LLVMValueRef mem_base_addr;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef check_succ, block_maddr_phi = NULL; LLVMBasicBlockRef check_succ;
LLVMValueRef mem_size; LLVMValueRef mem_size;
bool is_target_64bit;
#if WASM_ENABLE_MEMORY64 == 0 #if WASM_ENABLE_MEMORY64 == 0
bool is_memory64 = false; bool is_memory64 = false;
#else #else
bool is_memory64 = IS_MEMORY64; bool is_memory64 = IS_MEMORY64;
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
LLVMValueRef maddr_phi = NULL;
LLVMBasicBlockRef block_maddr_phi = NULL;
#endif
is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
/* Get memory base address and memory data size */ /* Get memory base address and memory data size */
#if WASM_ENABLE_SHARED_MEMORY != 0 #if WASM_ENABLE_SHARED_MEMORY != 0
@ -1221,6 +1564,9 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
ADD_BASIC_BLOCK(check_succ, "check_succ"); ADD_BASIC_BLOCK(check_succ, "check_succ");
LLVMMoveBasicBlockAfter(check_succ, block_curr); LLVMMoveBasicBlockAfter(check_succ, block_curr);
/* Same logic with aot_check_memory_overflow, offset and bytes are 32/64
* bits on 32/64 bits platform */
if (is_target_64bit) {
offset = offset =
LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset"); LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len"); bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
@ -1228,104 +1574,61 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
aot_set_last_error("llvm build zext failed."); aot_set_last_error("llvm build zext failed.");
goto fail; goto fail;
} }
}
BUILD_OP(Add, offset, bytes, max_addr, "max_addr"); BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
if (is_memory64 && comp_ctx->enable_bound_check) { /* Check overflow when it's memory64 or it's on 32 bits platform */
/* Check whether integer overflow occurs in offset + addr */ if (is_memory64 || !is_target_64bit) {
/* Check whether integer overflow occurs in offset + bytes */
LLVMBasicBlockRef check_integer_overflow_end; LLVMBasicBlockRef check_integer_overflow_end;
ADD_BASIC_BLOCK(check_integer_overflow_end, ADD_BASIC_BLOCK(check_integer_overflow_end,
"check_integer_overflow_end"); "check_integer_overflow_end");
LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr); LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr);
/* offset + bytes can overflow yet is valid(for example, 0xffffffff, 1),
* allow it to be 0(either 0, 0 or overflow and valid) */
BUILD_ICMP(LLVMIntULT, max_addr, offset, cmp, "cmp"); BUILD_ICMP(LLVMIntULT, max_addr, offset, cmp, "cmp");
BUILD_ICMP(LLVMIntNE, max_addr, is_target_64bit ? I64_ZERO : I32_ZERO,
cmp1, "cmp1");
BUILD_OP(And, cmp, cmp1, cmp, "overflow");
if (!aot_emit_exception(comp_ctx, func_ctx, if (!aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp,
check_integer_overflow_end)) { check_integer_overflow_end)) {
goto fail; goto fail;
} }
SET_BUILD_POS(check_integer_overflow_end); SET_BUILD_POS(check_integer_overflow_end);
block_curr = check_integer_overflow_end;
} }
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { #if WASM_ENABLE_SHARED_HEAP != 0
LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem; if (comp_ctx->enable_shared_heap
LLVMValueRef shared_heap_start_off, shared_heap_check_bound; || comp_ctx->enable_shared_chain /* TODO: && mem_idx == 0 */) {
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"); ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
SET_BUILD_POS(block_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, if (!(maddr_phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE,
"maddr_phi"))) { "maddr_phi"))) {
aot_set_last_error("llvm build phi failed"); aot_set_last_error("llvm build phi failed");
goto fail; goto fail;
} }
SET_BUILD_POS(block_curr);
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); if (!aot_check_bulk_memory_shared_heap_memory_overflow(
comp_ctx, func_ctx, block_curr, block_maddr_phi, check_succ,
shared_heap_start_off = func_ctx->shared_heap_start_off; maddr_phi, offset, max_addr, bytes, is_memory64,
if (comp_ctx->pointer_size == sizeof(uint32)) { is_target_64bit)) {
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; goto fail;
} }
} }
shared_heap_check_bound = #endif
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 */ /* mem_size is always 64-bit, extend max_addr on 32 bits platform */
if (!comp_ctx->enable_bound_check) { if (!is_target_64bit
/* Use IntUGT but not IntUGE to compare, same as the check && !(max_addr = LLVMBuildZExt(comp_ctx->builder, max_addr, I64_TYPE,
in aot_check_memory_overflow */ "extend_max_addr"))) {
BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off, aot_set_last_error("llvm build zext failed.");
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; 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"); BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr");
if (!aot_emit_exception(comp_ctx, func_ctx, if (!aot_emit_exception(comp_ctx, func_ctx,
@ -1341,7 +1644,9 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail; goto fail;
} }
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) { #if WASM_ENABLE_SHARED_HEAP != 0
if (comp_ctx->enable_shared_heap
|| comp_ctx->enable_shared_chain /* TODO: && mem_idx == 0 */) {
block_curr = LLVMGetInsertBlock(comp_ctx->builder); block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1); LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) { if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
@ -1352,6 +1657,7 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return maddr_phi; return maddr_phi;
} }
else else
#endif
return maddr; return maddr;
fail: fail:
return NULL; return NULL;

View File

@ -1517,73 +1517,154 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true; return true;
} }
#define BUILD_IS_NOT_NULL(value, res, name) \
do { \
if (!(res = LLVMBuildIsNotNull(comp_ctx->builder, value, name))) { \
aot_set_last_error("llvm build is not null failed."); \
goto fail; \
} \
} while (0)
#define get_module_extra_field_offset(field) \
do { \
offset_u32 = get_module_inst_extra_offset(comp_ctx); \
if (comp_ctx->is_jit_mode) \
offset_u32 += offsetof(WASMModuleInstanceExtra, field); \
else \
offset_u32 += offsetof(AOTModuleInstanceExtra, field); \
} while (0)
#define LOAD_MODULE_EXTRA_FIELD_AND_ALLOCA(field, type) \
do { \
get_module_extra_field_offset(field); \
offset = I32_CONST(offset_u32); \
CHECK_LLVM_CONST(offset); \
if (!(field_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, \
func_ctx->aot_inst, &offset, 1, \
#field "_p"))) { \
aot_set_last_error("llvm build inbounds gep failed"); \
goto fail; \
} \
if (!(load_val = \
LLVMBuildLoad2(comp_ctx->builder, type, field_p, #field))) { \
aot_set_last_error("llvm build load failed"); \
goto fail; \
} \
if (!(func_ctx->field = \
LLVMBuildAlloca(comp_ctx->builder, type, #field))) { \
aot_set_last_error("llvm build alloca failed"); \
goto fail; \
} \
if (!LLVMBuildStore(comp_ctx->builder, load_val, func_ctx->field)) { \
aot_set_last_error("llvm build store failed"); \
goto fail; \
} \
} while (0)
static bool static bool
create_shared_heap_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) create_shared_heap_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{ {
LLVMValueRef offset, base_addr_p, start_off_p, cmp; #if WASM_ENABLE_SHARED_HEAP != 0
LLVMValueRef offset, field_p, load_val, shared_heap_head_p,
shared_heap_head, cmp, field_p_or_default, shared_heap_head_start_off,
shared_heap_head_start_off_minus_one;
LLVMTypeRef shared_heap_offset_type;
uint32 offset_u32; uint32 offset_u32;
#if WASM_ENABLE_MEMORY64 == 0
/* Load aot_inst->e->shared_heap_base_addr_adj */ bool is_memory64 = false;
offset_u32 = get_module_inst_extra_offset(comp_ctx); #else
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 bool is_memory64 = IS_MEMORY64;
if (comp_ctx->is_jit_mode)
offset_u32 +=
offsetof(WASMModuleInstanceExtra, shared_heap_base_addr_adj);
else
#endif #endif
offset_u32 +=
offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj); shared_heap_offset_type =
comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE;
/* shared_heap_base_addr_adj, shared_heap_start_off, and
* shared_heap_end_off can be updated later, use local variable to
* represent them */
LOAD_MODULE_EXTRA_FIELD_AND_ALLOCA(shared_heap_base_addr_adj,
INT8_PTR_TYPE);
LOAD_MODULE_EXTRA_FIELD_AND_ALLOCA(shared_heap_start_off,
shared_heap_offset_type);
LOAD_MODULE_EXTRA_FIELD_AND_ALLOCA(shared_heap_end_off,
shared_heap_offset_type);
/* Shared Heap head start off won't be updated, no need to alloca */
get_module_extra_field_offset(shared_heap);
offset = I32_CONST(offset_u32); offset = I32_CONST(offset_u32);
CHECK_LLVM_CONST(offset); CHECK_LLVM_CONST(offset);
if (!(shared_heap_head_p = LLVMBuildInBoundsGEP2(
if (!(base_addr_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
func_ctx->aot_inst, &offset, 1, "shared_heap_head_p"))) {
"shared_heap_base_addr_adj_p"))) {
aot_set_last_error("llvm build inbounds gep failed"); aot_set_last_error("llvm build inbounds gep failed");
return false; goto fail;
} }
if (!(func_ctx->shared_heap_base_addr_adj = if (!(shared_heap_head =
LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, base_addr_p, LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE,
"shared_heap_base_addr_adj"))) { shared_heap_head_p, "shared_heap_head"))) {
aot_set_last_error("llvm build load failed"); aot_set_last_error("llvm build load failed");
return false; goto fail;
} }
BUILD_IS_NOT_NULL(shared_heap_head, cmp, "has_shared_heap");
/* Load aot_inst->e->shared_heap_start_off */ if (is_memory64) {
offset_u32 = get_module_inst_extra_offset(comp_ctx); offset_u32 = offsetof(WASMSharedHeap, start_off_mem64);
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0 }
if (comp_ctx->is_jit_mode) else {
offset_u32 += offsetof(WASMModuleInstanceExtra, shared_heap_start_off); offset_u32 = offsetof(WASMSharedHeap, start_off_mem32);
else }
#endif
offset_u32 += offsetof(AOTModuleInstanceExtra, shared_heap_start_off);
offset = I32_CONST(offset_u32); offset = I32_CONST(offset_u32);
CHECK_LLVM_CONST(offset); CHECK_LLVM_CONST(offset);
if (!(field_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
if (!(start_off_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, shared_heap_head, &offset, 1,
func_ctx->aot_inst, &offset, 1, "head_start_off_p"))) {
"shared_heap_start_off_p"))) {
aot_set_last_error("llvm build inbounds gep failed"); aot_set_last_error("llvm build inbounds gep failed");
return false; goto fail;
} }
if (!(func_ctx->shared_heap_start_off = LLVMBuildLoad2(
comp_ctx->builder, /* Select a valid shared heap head ptr or safe alloca ptr stores
comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE, * shared_heap_start_off(UINT32_MAX/UINT64_MAX) */
start_off_p, "shared_heap_start_off"))) { if (!(field_p_or_default = LLVMBuildSelect(comp_ctx->builder, cmp, field_p,
func_ctx->shared_heap_start_off,
"ptr_or_default"))) {
aot_set_last_error("llvm build select failed");
goto fail;
}
if (!(shared_heap_head_start_off = LLVMBuildLoad2(
comp_ctx->builder, shared_heap_offset_type, field_p_or_default,
"shared_heap_head_start_off"))) {
aot_set_last_error("llvm build load failed"); aot_set_last_error("llvm build load failed");
return false; goto fail;
}
if (!(shared_heap_head_start_off_minus_one = LLVMBuildAdd(
comp_ctx->builder, shared_heap_head_start_off,
comp_ctx->pointer_size == sizeof(uint64) ? I64_NEG_ONE
: I32_NEG_ONE,
"head_start_off_minus_one"))) {
aot_set_last_error("llvm build load failed");
goto fail;
} }
if (!(cmp = LLVMBuildIsNotNull(comp_ctx->builder, /* if there is attached shared heap(s), the value will be valid start_off-1,
func_ctx->shared_heap_base_addr_adj, * otherwise it will be UINT32_MAX/UINT64_MAX, so during the bounds checks,
"has_shared_heap"))) { * when has attached shared heap:
aot_set_last_error("llvm build is not null failed"); * offset > start_off - 1 => offset >= start_off
return false; * when no attached shared heap:
* offset > UINT32_MAX/UINT64_MAX is always false
* */
if (!(func_ctx->shared_heap_head_start_off = LLVMBuildSelect(
comp_ctx->builder, cmp, shared_heap_head_start_off_minus_one,
shared_heap_head_start_off, "head_start_off"))) {
aot_set_last_error("llvm build select failed");
goto fail;
} }
return true; return true;
fail: fail:
return false; return false;
#else /* else of WASM_ENABLE_SHARED_HEAP != 0 */
return true;
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
} }
static bool static bool
@ -1877,7 +1958,7 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
} }
/* Load shared heap, shared heap start off mem32 or mem64 */ /* Load shared heap, shared heap start off mem32 or mem64 */
if (comp_ctx->enable_shared_heap if ((comp_ctx->enable_shared_heap || comp_ctx->enable_shared_chain)
&& !create_shared_heap_info(comp_ctx, func_ctx)) { && !create_shared_heap_info(comp_ctx, func_ctx)) {
goto fail; goto fail;
} }
@ -2703,6 +2784,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
if (option->enable_shared_heap) if (option->enable_shared_heap)
comp_ctx->enable_shared_heap = true; comp_ctx->enable_shared_heap = true;
if (option->enable_shared_chain)
comp_ctx->enable_shared_chain = true;
comp_ctx->opt_level = option->opt_level; comp_ctx->opt_level = option->opt_level;
comp_ctx->size_level = option->size_level; comp_ctx->size_level = option->size_level;

View File

@ -254,8 +254,12 @@ typedef struct AOTFuncContext {
bool mem_space_unchanged; bool mem_space_unchanged;
AOTCheckedAddrList checked_addr_list; AOTCheckedAddrList checked_addr_list;
/* The last accessed shared heap info */
LLVMValueRef shared_heap_base_addr_adj; LLVMValueRef shared_heap_base_addr_adj;
LLVMValueRef shared_heap_start_off; LLVMValueRef shared_heap_start_off;
LLVMValueRef shared_heap_end_off;
/* The start offset of the head of shared heap chain */
LLVMValueRef shared_heap_head_start_off;
LLVMBasicBlockRef got_exception_block; LLVMBasicBlockRef got_exception_block;
LLVMBasicBlockRef func_return_block; LLVMBasicBlockRef func_return_block;
@ -486,6 +490,7 @@ typedef struct AOTCompContext {
bool enable_gc; bool enable_gc;
bool enable_shared_heap; bool enable_shared_heap;
bool enable_shared_chain;
uint32 opt_level; uint32 opt_level;
uint32 size_level; uint32 size_level;

View File

@ -79,6 +79,7 @@ typedef struct AOTCompOption {
bool enable_stack_estimation; bool enable_stack_estimation;
bool quick_invoke_c_api_import; bool quick_invoke_c_api_import;
bool enable_shared_heap; bool enable_shared_heap;
bool enable_shared_chain;
char *use_prof_file; char *use_prof_file;
uint32_t opt_level; uint32_t opt_level;
uint32_t size_level; uint32_t size_level;

View File

@ -2818,6 +2818,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
#else #else
module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX; module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX;
#endif #endif
module_inst->e->shared_heap = NULL;
#endif #endif
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0

View File

@ -95,13 +95,13 @@ typedef union {
typedef struct WASMSharedHeap { typedef struct WASMSharedHeap {
/* The global shared heap list maintained in runtime, used for runtime /* The global shared heap list maintained in runtime, used for runtime
* destroy */ * destroy */
struct WASMSharedHeap *next; DefPointer(struct WASMSharedHeap *, next);
/* The logical shared heap chain the shared heap in */ /* The logical shared heap chain the shared heap in */
struct WASMSharedHeap *chain_next; DefPointer(struct WASMSharedHeap *, chain_next);
/* Will be null if shared heap is created from pre allocated memory chunk /* Will be null if shared heap is created from pre allocated memory chunk
* and don't need to dynamic malloc and free */ * and don't need to dynamic malloc and free */
void *heap_handle; DefPointer(void *, heap_handle);
uint8 *base_addr; DefPointer(uint8 *, base_addr);
uint64 size; uint64 size;
uint64 start_off_mem64; uint64 start_off_mem64;
uint64 start_off_mem32; uint64 start_off_mem32;

View File

@ -120,12 +120,22 @@ if (WAMR_BUILD_AOT EQUAL 1)
message (STATUS "WAMR_COMPILER is ${WAMR_COMPILER}") message (STATUS "WAMR_COMPILER is ${WAMR_COMPILER}")
endif () endif ()
if (WAMR_BUILD_TARGET STREQUAL "X86_32")
set (WAMR_COMPILER_FLAGS --enable-shared-heap --target=i386)
set (WAMR_COMPILER_CHAIN_FLAGS --enable-shared-chain --target=i386)
else ()
set (WAMR_COMPILER_FLAGS --enable-shared-heap)
set (WAMR_COMPILER_CHAIN_FLAGS --enable-shared-chain)
endif ()
add_custom_target( add_custom_target(
wasm_to_aot wasm_to_aot
ALL ALL
DEPENDS wasm-apps/test1.wasm wasm-apps/test2.wasm ${WAMR_COMPILER} 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} ${WAMR_COMPILER_FLAGS} -o wasm-apps/test1.aot wasm-apps/test1.wasm
COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test2.aot wasm-apps/test2.wasm COMMAND ${WAMR_COMPILER} ${WAMR_COMPILER_FLAGS} -o wasm-apps/test2.aot wasm-apps/test2.wasm
COMMAND ${WAMR_COMPILER} ${WAMR_COMPILER_CHAIN_FLAGS} -o wasm-apps/test1_chain.aot wasm-apps/test1.wasm
COMMAND ${WAMR_COMPILER} ${WAMR_COMPILER_CHAIN_FLAGS} -o wasm-apps/test2_chain.aot wasm-apps/test2.wasm
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
) )
endif() endif()

View File

@ -24,7 +24,7 @@ produce_data(wasm_module_inst_t module_inst, wasm_exec_env_t exec_env,
wasm_runtime_get_exception(module_inst)); wasm_runtime_get_exception(module_inst));
return false; return false;
} }
if (free_on_fail && argv[0] == 0) { if (argv[0] == 0) {
printf("Failed to allocate memory from shared heap\n"); printf("Failed to allocate memory from shared heap\n");
return false; return false;
} }
@ -34,7 +34,7 @@ produce_data(wasm_module_inst_t module_inst, wasm_exec_env_t exec_env,
/* Passes wasm address directly between wasm apps since memory in shared /* Passes wasm address directly between wasm apps since memory in shared
* heap chain is viewed as single address space in wasm's perspective */ * heap chain is viewed as single address space in wasm's perspective */
buf = (uint8 *)(uint64)argv[0]; buf = (uint8 *)(uintptr_t)argv[0];
if (!bh_post_msg(queue, 1, buf, buf_size)) { if (!bh_post_msg(queue, 1, buf, buf_size)) {
printf("Failed to post message to queue\n"); printf("Failed to post message to queue\n");
if (free_on_fail) if (free_on_fail)
@ -130,7 +130,7 @@ wasm_consumer(wasm_module_inst_t module_inst, bh_queue *queue)
buf = bh_message_payload(msg); buf = bh_message_payload(msg);
/* call wasm function */ /* call wasm function */
argv[0] = (uint32)(uint64)buf; argv[0] = (uint32)(uintptr_t)buf;
if (i < 8) if (i < 8)
wasm_runtime_call_wasm(exec_env, print_buf_func, 1, argv); wasm_runtime_call_wasm(exec_env, print_buf_func, 1, argv);
else else
@ -198,7 +198,7 @@ main(int argc, char **argv)
if (!aot_mode) if (!aot_mode)
wasm_file1 = "./wasm-apps/test1.wasm"; wasm_file1 = "./wasm-apps/test1.wasm";
else else
wasm_file1 = "./wasm-apps/test1.aot"; wasm_file1 = "./wasm-apps/test1_chain.aot";
if (!(wasm_file1_buf = if (!(wasm_file1_buf =
bh_read_file_to_buffer(wasm_file1, &wasm_file1_size))) { bh_read_file_to_buffer(wasm_file1, &wasm_file1_size))) {
printf("Open wasm file %s failed.\n", wasm_file1); printf("Open wasm file %s failed.\n", wasm_file1);
@ -225,7 +225,7 @@ main(int argc, char **argv)
if (!aot_mode) if (!aot_mode)
wasm_file2 = "./wasm-apps/test2.wasm"; wasm_file2 = "./wasm-apps/test2.wasm";
else else
wasm_file2 = "./wasm-apps/test2.aot"; wasm_file2 = "./wasm-apps/test2_chain.aot";
if (!(wasm_file2_buf = if (!(wasm_file2_buf =
bh_read_file_to_buffer(wasm_file2, &wasm_file2_size))) { bh_read_file_to_buffer(wasm_file2, &wasm_file2_size))) {
printf("Open wasm file %s failed.\n", wasm_file1); printf("Open wasm file %s failed.\n", wasm_file1);

View File

@ -62,6 +62,10 @@ my_shared_heap_free(void *ptr)
void * void *
produce_str(char *addr, uint32_t index) produce_str(char *addr, uint32_t index)
{ {
char c;
snprintf(addr, 512, "Data: %u stores to pre-allocated shared heap", index); snprintf(addr, 512, "Data: %u stores to pre-allocated shared heap", index);
/* Actually access it in wasm */
c = addr[0];
printf("In WASM: the first char is %c\n", c);
return addr; return addr;
} }

View File

@ -19,7 +19,10 @@ print_buf(char *buf)
void void
consume_str(char *buf) consume_str(char *buf)
{ {
printf("wasm app2's wasm func received buf in pre-allocated shared buf: " /* Actually access it in wasm */
"%s\n\n", char c = buf[0];
buf); printf("In WASM: wasm app2's wasm func received buf in pre-allocated "
"shared buf: "
"%s with its first char is %c\n\n",
buf, c);
} }

View File

@ -19,8 +19,15 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
if(WAMR_BUILD_TARGET STREQUAL "X86_32") if(WAMR_BUILD_TARGET STREQUAL "X86_32")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") # 1) Force -m32
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32" CACHE STRING "" FORCE)
# 2) Make CMake prefer i386 libraries
set(CMAKE_SYSTEM_PROCESSOR i386 CACHE STRING "" FORCE)
set(CMAKE_LIBRARY_ARCHITECTURE "i386-linux-gnu" CACHE STRING "" FORCE)
endif() endif()
# Prevent overriding the parent project's compiler/linker # Prevent overriding the parent project's compiler/linker
@ -29,11 +36,20 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Fetch Google test # Fetch Google test
include (FetchContent) include (FetchContent)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24")
FetchContent_Declare ( FetchContent_Declare (
googletest googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
DOWNLOAD_EXTRACT_TIMESTAMP TRUE DOWNLOAD_EXTRACT_TIMESTAMP ON
) )
else()
FetchContent_Declare (
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
endif()
FetchContent_MakeAvailable(googletest) FetchContent_MakeAvailable(googletest)
SET(GOOGLETEST_INCLUDED 1) SET(GOOGLETEST_INCLUDED 1)

View File

@ -12,12 +12,20 @@ set(WAMR_BUILD_AOT 1)
set(WAMR_BUILD_INTERP 1) set(WAMR_BUILD_INTERP 1)
set(WAMR_BUILD_FAST_INTERP 1) set(WAMR_BUILD_FAST_INTERP 1)
set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_JIT 0)
if(WAMR_BUILD_TARGET STREQUAL "X86_32")
set(WAMR_BUILD_MEMORY64 0)
else()
set(WAMR_BUILD_MEMORY64 1) set(WAMR_BUILD_MEMORY64 1)
endif()
set(WAMR_BUILD_SHARED_HEAP 1) set(WAMR_BUILD_SHARED_HEAP 1)
# Compile wasm modules # Compile wasm modules
add_subdirectory(wasm-apps) add_subdirectory(wasm-apps)
if (WAMR_BUILD_MEMORY64 EQUAL 1)
add_subdirectory(wasm-apps/memory64)
endif ()
# if only load this CMake other than load it as subdirectory # if only load this CMake other than load it as subdirectory
include(../unit_common.cmake) include(../unit_common.cmake)

View File

@ -35,7 +35,7 @@ static bool
load_wasm(char *wasm_file_tested, unsigned int app_heap_size, load_wasm(char *wasm_file_tested, unsigned int app_heap_size,
ret_env &ret_module_env) ret_env &ret_module_env)
{ {
const char *wasm_file = strdup(wasm_file_tested); char *wasm_file = strdup(wasm_file_tested);
unsigned int wasm_file_size = 0; unsigned int wasm_file_size = 0;
unsigned int stack_size = 16 * 1024, heap_size = app_heap_size; unsigned int stack_size = 16 * 1024, heap_size = app_heap_size;
char error_buf[128] = { 0 }; char error_buf[128] = { 0 };
@ -68,8 +68,10 @@ load_wasm(char *wasm_file_tested, unsigned int app_heap_size,
goto fail; goto fail;
} }
free(wasm_file);
return true; return true;
fail: fail:
free(wasm_file);
destroy_module_env(ret_module_env); destroy_module_env(ret_module_env);
return false; return false;
} }
@ -155,6 +157,9 @@ TEST_F(shared_heap_test, test_shared_heap_basic)
test_shared_heap(shared_heap, "test.aot", "test", 0, argv); test_shared_heap(shared_heap, "test.aot", "test", 0, argv);
EXPECT_EQ(10, argv[0]); EXPECT_EQ(10, argv[0]);
test_shared_heap(shared_heap, "test_chain.aot", "test", 0, argv);
EXPECT_EQ(10, argv[0]);
} }
TEST_F(shared_heap_test, test_shared_heap_malloc_fail) TEST_F(shared_heap_test, test_shared_heap_malloc_fail)
@ -175,6 +180,10 @@ TEST_F(shared_heap_test, test_shared_heap_malloc_fail)
test_shared_heap(shared_heap, "test.aot", "test_malloc_fail", 0, argv); test_shared_heap(shared_heap, "test.aot", "test_malloc_fail", 0, argv);
EXPECT_EQ(1, argv[0]); EXPECT_EQ(1, argv[0]);
test_shared_heap(shared_heap, "test_chain.aot", "test_malloc_fail", 0,
argv);
EXPECT_EQ(1, argv[0]);
} }
TEST_F(shared_heap_test, test_preallocated_shared_heap_malloc_fail) TEST_F(shared_heap_test, test_preallocated_shared_heap_malloc_fail)
@ -201,20 +210,41 @@ TEST_F(shared_heap_test, test_preallocated_shared_heap_malloc_fail)
argv[0] = 1024; argv[0] = 1024;
test_shared_heap(shared_heap, "test.aot", "my_shared_heap_malloc", 1, argv); test_shared_heap(shared_heap, "test.aot", "my_shared_heap_malloc", 1, argv);
EXPECT_EQ(0, argv[0]); EXPECT_EQ(0, argv[0]);
argv[0] = 1024;
test_shared_heap(shared_heap, "test_chain.aot", "my_shared_heap_malloc", 1,
argv);
EXPECT_EQ(0, argv[0]);
} }
TEST_F(shared_heap_test, test_shared_heap_chain_rmw) static void
create_test_shared_heap(uint8 *preallocated_buf, size_t size,
WASMSharedHeap **shared_heap_res)
{ {
SharedHeapInitArgs args = { 0 }; SharedHeapInitArgs args = { 0 };
WASMSharedHeap *shared_heap = nullptr, *shared_heap2 = nullptr, WASMSharedHeap *shared_heap = nullptr;
*shared_heap_chain = nullptr;
uint32 argv[2] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE] = { 0 },
preallocated_buf2[BUF_SIZE] = { 0 };
uint32 start1, end1, start2, end2;
args.pre_allocated_addr = preallocated_buf; args.pre_allocated_addr = preallocated_buf;
args.size = BUF_SIZE; args.size = size;
shared_heap = wasm_runtime_create_shared_heap(&args);
if (!shared_heap) {
FAIL() << "Create preallocated shared heap failed.\n";
}
*shared_heap_res = shared_heap;
if (!*shared_heap_res) {
FAIL() << "Create shared heap chain failed.\n";
}
}
static void
create_test_shared_heap_chain(uint8 *preallocated_buf, size_t size,
uint8 *preallocated_buf2, size_t size2,
WASMSharedHeap **shared_heap_chain)
{
SharedHeapInitArgs args = { 0 };
WASMSharedHeap *shared_heap = nullptr, *shared_heap2 = nullptr;
args.pre_allocated_addr = preallocated_buf;
args.size = size;
shared_heap = wasm_runtime_create_shared_heap(&args); shared_heap = wasm_runtime_create_shared_heap(&args);
if (!shared_heap) { if (!shared_heap) {
FAIL() << "Create preallocated shared heap failed.\n"; FAIL() << "Create preallocated shared heap failed.\n";
@ -222,23 +252,74 @@ TEST_F(shared_heap_test, test_shared_heap_chain_rmw)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.pre_allocated_addr = preallocated_buf2; args.pre_allocated_addr = preallocated_buf2;
args.size = BUF_SIZE; args.size = size2;
shared_heap2 = wasm_runtime_create_shared_heap(&args); shared_heap2 = wasm_runtime_create_shared_heap(&args);
if (!shared_heap2) { if (!shared_heap2) {
FAIL() << "Create preallocated shared heap failed.\n"; FAIL() << "Create preallocated shared heap failed.\n";
} }
shared_heap_chain = *shared_heap_chain =
wasm_runtime_chain_shared_heaps(shared_heap, shared_heap2); wasm_runtime_chain_shared_heaps(shared_heap, shared_heap2);
if (!shared_heap_chain) { if (!*shared_heap_chain) {
FAIL() << "Create shared heap chain failed.\n"; FAIL() << "Create shared heap chain failed.\n";
} }
}
TEST_F(shared_heap_test, test_shared_heap_rmw)
{
WASMSharedHeap *shared_heap = nullptr;
uint32 argv[2] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE] = { 0 };
uint32 start1, end1;
create_test_shared_heap(preallocated_buf, BUF_SIZE, &shared_heap);
/* app addr for shared heap */ /* app addr for shared heap */
start1 = 0xFFFFFFFF - 2 * BUF_SIZE + 1; start1 = UINT32_MAX - BUF_SIZE + 1;
end1 = 0xFFFFFFFF - BUF_SIZE; end1 = UINT32_MAX;
start2 = 0xFFFFFFFF - BUF_SIZE + 1;
end2 = 0xFFFFFFFF; argv[0] = end1;
argv[1] = 101;
test_shared_heap(shared_heap, "test.wasm", "read_modify_write_8", 2, argv);
EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf[BUF_SIZE - 1], 101);
argv[0] = start1;
argv[1] = 37;
test_shared_heap(shared_heap, "test.wasm", "read_modify_write_8", 2, argv);
EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf[0], 37);
argv[0] = end1;
argv[1] = 81;
test_shared_heap(shared_heap, "test.aot", "read_modify_write_8", 2, argv);
EXPECT_EQ(101, argv[0]);
EXPECT_EQ(preallocated_buf[BUF_SIZE - 1], 81);
argv[0] = start1;
argv[1] = 98;
test_shared_heap(shared_heap, "test.aot", "read_modify_write_8", 2, argv);
EXPECT_EQ(37, argv[0]);
EXPECT_EQ(preallocated_buf[0], 98);
}
TEST_F(shared_heap_test, test_shared_heap_chain_rmw)
{
SharedHeapInitArgs args = { 0 };
WASMSharedHeap *shared_heap_chain = nullptr;
uint32 argv[2] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE] = { 0 },
preallocated_buf2[BUF_SIZE] = { 0 };
uint32 start1, end1, start2, end2;
create_test_shared_heap_chain(preallocated_buf, BUF_SIZE, preallocated_buf2,
BUF_SIZE, &shared_heap_chain);
/* app addr for shared heap */
start1 = UINT32_MAX - 2 * BUF_SIZE + 1;
end1 = UINT32_MAX - BUF_SIZE;
start2 = UINT32_MAX - BUF_SIZE + 1;
end2 = UINT32_MAX;
/* shared heap 1 */ /* shared heap 1 */
argv[0] = end1; argv[0] = end1;
@ -256,76 +337,309 @@ TEST_F(shared_heap_test, test_shared_heap_chain_rmw)
EXPECT_EQ(0, argv[0]); EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf2[0], 129); EXPECT_EQ(preallocated_buf2[0], 129);
/* TODO: test aot when chain is supported in AOT */
/*
argv[0] = start1; argv[0] = start1;
argv[1] = 98; argv[1] = 98;
test_shared_heap(shared_heap_chain, "test.aot", "read_modify_write_8", 2, test_shared_heap(shared_heap_chain, "test_chain.aot", "read_modify_write_8",
argv); 2, argv);
EXPECT_EQ(0, argv[0]); EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf[0], 98); EXPECT_EQ(preallocated_buf[0], 98);
argv[0] = end2; argv[0] = end2;
argv[1] = 81; argv[1] = 81;
test_shared_heap(shared_heap_chain, "test.aot", "read_modify_write_8", 2, test_shared_heap(shared_heap_chain, "test_chain.aot", "read_modify_write_8",
argv); 2, argv);
EXPECT_EQ(0, argv[0]); EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf2[BUF_SIZE - 1], 81); EXPECT_EQ(preallocated_buf2[BUF_SIZE - 1], 81);
*/
} }
TEST_F(shared_heap_test, test_shared_heap_chain_rmw_oob) TEST_F(shared_heap_test, test_shared_heap_chain_rmw_bulk_memory)
{ {
SharedHeapInitArgs args = { 0 }; SharedHeapInitArgs args = { 0 };
WASMSharedHeap *shared_heap = nullptr, *shared_heap2 = nullptr, WASMSharedHeap *shared_heap_chain = nullptr;
*shared_heap_chain = nullptr; uint32 argv[3] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE] = { 0 },
preallocated_buf2[BUF_SIZE] = { 0 };
uint32 start1, end1, start2, end2;
create_test_shared_heap_chain(preallocated_buf, BUF_SIZE, preallocated_buf2,
BUF_SIZE, &shared_heap_chain);
/* app addr for shared heap */
start1 = UINT32_MAX - 2 * BUF_SIZE + 1;
end1 = UINT32_MAX - BUF_SIZE;
start2 = UINT32_MAX - BUF_SIZE + 1;
end2 = UINT32_MAX;
argv[0] = end1;
argv[1] = 101;
argv[2] = 1;
test_shared_heap(shared_heap_chain, "test_bulk_memory.wasm",
"memory_fill_test", 3, argv);
/* no modification since no return value */
EXPECT_EQ(end1, argv[0]);
EXPECT_EQ(preallocated_buf[BUF_SIZE - 1], 101);
argv[0] = start1;
argv[1] = 14;
argv[2] = 1;
test_shared_heap(shared_heap_chain, "test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv);
/* no modification since no return value */
EXPECT_EQ(start1, argv[0]);
EXPECT_EQ(preallocated_buf[0], 14);
/* nothing happen when memory fill 0 byte */
argv[0] = start2;
argv[1] = 68;
argv[2] = 0;
test_shared_heap(shared_heap_chain, "test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv);
/* no modification since no return value */
EXPECT_EQ(start2, argv[0]);
EXPECT_EQ(preallocated_buf2[0], 0);
argv[0] = end2;
argv[1] = 98;
argv[2] = 1;
test_shared_heap(shared_heap_chain, "test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv);
/* no modification since no return value */
EXPECT_EQ(end2, argv[0]);
EXPECT_EQ(preallocated_buf2[BUF_SIZE - 1], 98);
}
TEST_F(shared_heap_test, test_shared_heap_chain_rmw_bulk_memory_oob)
{
SharedHeapInitArgs args = { 0 };
WASMSharedHeap *shared_heap_chain = nullptr;
uint32 argv[3] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE] = { 0 },
preallocated_buf2[BUF_SIZE] = { 0 };
uint32 start1, end1, start2, end2;
create_test_shared_heap_chain(preallocated_buf, BUF_SIZE, preallocated_buf2,
BUF_SIZE, &shared_heap_chain);
/* app addr for shared heap */
start1 = UINT32_MAX - 2 * BUF_SIZE + 1;
end1 = UINT32_MAX - BUF_SIZE;
start2 = UINT32_MAX - BUF_SIZE + 1;
end2 = UINT32_MAX;
/* shared heap 1 */
argv[0] = end1;
argv[1] = 101;
argv[2] = 2;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory.wasm",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = end2;
argv[1] = 98;
argv[2] = 2;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory.wasm",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = start1;
argv[1] = 98;
argv[2] = BUF_SIZE + 1;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory.wasm",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = start2;
argv[1] = 98;
argv[2] = BUF_SIZE + 1;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory.wasm",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = end1;
argv[1] = 101;
argv[2] = 2;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = end2;
argv[1] = 98;
argv[2] = 2;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = start1;
argv[1] = 98;
argv[2] = BUF_SIZE + 1;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
argv[0] = start2;
argv[1] = 98;
argv[2] = BUF_SIZE + 1;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_bulk_memory_chain.aot",
"memory_fill_test", 3, argv),
"Exception: out of bounds memory access");
}
TEST_F(shared_heap_test, test_shared_heap_rmw_oob)
{
WASMSharedHeap *shared_heap = nullptr;
uint32 argv[2] = { 0 }, BUF_SIZE = os_getpagesize(); uint32 argv[2] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE], preallocated_buf2[BUF_SIZE]; uint8 preallocated_buf[BUF_SIZE], preallocated_buf2[BUF_SIZE];
uint32 start1, end1, start2, end2; uint32 start1, end1, start2, end2;
args.pre_allocated_addr = preallocated_buf; create_test_shared_heap(preallocated_buf, BUF_SIZE, &shared_heap);
args.size = BUF_SIZE;
shared_heap = wasm_runtime_create_shared_heap(&args);
if (!shared_heap) {
FAIL() << "Create preallocated shared heap failed.\n";
}
memset(&args, 0, sizeof(args));
args.pre_allocated_addr = preallocated_buf2;
args.size = BUF_SIZE;
shared_heap2 = wasm_runtime_create_shared_heap(&args);
if (!shared_heap2) {
FAIL() << "Create preallocated shared heap failed.\n";
}
shared_heap_chain =
wasm_runtime_chain_shared_heaps(shared_heap, shared_heap2);
if (!shared_heap_chain) {
FAIL() << "Create shared heap chain failed.\n";
}
/* app addr for shared heap */ /* app addr for shared heap */
start1 = 0xFFFFFFFF - 2 * BUF_SIZE + 1; start1 = UINT32_MAX - BUF_SIZE + 1;
end1 = 0xFFFFFFFF - BUF_SIZE; end1 = UINT32_MAX;
start2 = 0xFFFFFFFF - BUF_SIZE + 1;
end2 = 0xFFFFFFFF;
/* try to rmw an u16, first u8 is in the first shared heap and second u8 is /* try to rmw an u16, first u8 is in the first shared heap and second u8 is
* in the second shared heap, will be seen as oob */ * in the second shared heap, will be seen as oob */
argv[0] = end1; argv[0] = end1;
argv[1] = 12025; argv[1] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap, "test.wasm",
"read_modify_write_16", 2, argv),
"Exception: out of bounds memory access");
argv[0] = start1 - 1;
argv[1] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap, "test.aot",
"read_modify_write_16", 2, argv),
"Exception: out of bounds memory access");
argv[0] = end1;
argv[1] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap, "test.aot",
"read_modify_write_16", 2, argv),
"Exception: out of bounds memory access");
}
TEST_F(shared_heap_test, test_shared_heap_chain_rmw_oob)
{
WASMSharedHeap *shared_heap_chain = nullptr;
uint32 argv[2] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE], preallocated_buf2[BUF_SIZE];
uint32 start1, end1, start2, end2;
create_test_shared_heap_chain(preallocated_buf, BUF_SIZE, preallocated_buf2,
BUF_SIZE, &shared_heap_chain);
/* app addr for shared heap */
start1 = UINT32_MAX - 2 * BUF_SIZE + 1;
end1 = UINT32_MAX - BUF_SIZE;
start2 = UINT32_MAX - BUF_SIZE + 1;
end2 = UINT32_MAX;
/* try to rmw an u16, first u8 is in the first shared heap and second u8 is
* in the second shared heap, will be seen as oob */
argv[0] = end2;
argv[1] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain, "test.wasm", EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain, "test.wasm",
"read_modify_write_16", 2, argv), "read_modify_write_16", 2, argv),
"Exception: out of bounds memory access"); "Exception: out of bounds memory access");
/* TODO: test aot when chain is supported in AOT */ argv[0] = end1;
/*argv[0] = end1;
argv[1] = 12025; argv[1] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain, "test.wasm", EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_chain.aot",
"read_modify_write_16", 2, argv), "read_modify_write_16", 2, argv),
"Exception: out of bounds memory access");*/ "Exception: out of bounds memory access");
} }
#if WASM_ENABLE_MEMORY64 != 0
TEST_F(shared_heap_test, test_shared_heap_chain_memory64_rmw)
{
WASMSharedHeap *shared_heap_chain = nullptr;
uint32 argv[3] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE] = { 0 },
preallocated_buf2[BUF_SIZE] = { 0 };
uint64 start1, end1, start2, end2;
create_test_shared_heap_chain(preallocated_buf, BUF_SIZE, preallocated_buf2,
BUF_SIZE, &shared_heap_chain);
/* app addr for shared heap */
start1 = UINT64_MAX - 2 * BUF_SIZE + 1;
end1 = UINT64_MAX - BUF_SIZE;
start2 = UINT64_MAX - BUF_SIZE + 1;
end2 = UINT64_MAX;
/* shared heap 1 */
PUT_I64_TO_ADDR(argv, end1);
argv[2] = 101;
test_shared_heap(shared_heap_chain, "test64.wasm", "read_modify_write_8", 3,
argv);
EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf[BUF_SIZE - 1], 101);
/* shared heap 2 */
PUT_I64_TO_ADDR(argv, start2);
argv[2] = 129;
test_shared_heap(shared_heap_chain, "test64.wasm", "read_modify_write_8", 3,
argv);
EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf2[0], 129);
PUT_I64_TO_ADDR(argv, start1);
argv[2] = 98;
test_shared_heap(shared_heap_chain, "test64_chain.aot",
"read_modify_write_8", 3, argv);
EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf[0], 98);
PUT_I64_TO_ADDR(argv, end2);
argv[2] = 81;
test_shared_heap(shared_heap_chain, "test64_chain.aot",
"read_modify_write_8", 3, argv);
EXPECT_EQ(0, argv[0]);
EXPECT_EQ(preallocated_buf2[BUF_SIZE - 1], 81);
}
TEST_F(shared_heap_test, test_shared_heap_chain_memory64_rmw_oob)
{
WASMSharedHeap *shared_heap_chain = nullptr;
uint32 argv[3] = { 0 }, BUF_SIZE = os_getpagesize();
uint8 preallocated_buf[BUF_SIZE], preallocated_buf2[BUF_SIZE];
uint64 start1, end1, start2, end2;
create_test_shared_heap_chain(preallocated_buf, BUF_SIZE, preallocated_buf2,
BUF_SIZE, &shared_heap_chain);
/* app addr for shared heap */
start1 = UINT64_MAX - 2 * BUF_SIZE + 1;
end1 = UINT64_MAX - BUF_SIZE;
start2 = UINT64_MAX - BUF_SIZE + 1;
end2 = UINT64_MAX;
/* try to rmw an u16, first u8 is in the first shared heap and second u8 is
* in the second shared heap, will be seen as oob */
PUT_I64_TO_ADDR(argv, end1);
argv[2] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain, "test64.wasm",
"read_modify_write_16", 3, argv),
"Exception: out of bounds memory access");
PUT_I64_TO_ADDR(argv, end1);
argv[2] = 12025;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test64_chain.aot",
"read_modify_write_16", 3, argv),
"Exception: out of bounds memory access");
}
#endif
#ifndef native_function #ifndef native_function
/* clang-format off */ /* clang-format off */
#define native_function(func_name, signature) \ #define native_function(func_name, signature) \
@ -378,6 +692,9 @@ TEST_F(shared_heap_test, test_addr_conv)
test_shared_heap(shared_heap, "test_addr_conv.aot", "test", 0, argv); test_shared_heap(shared_heap, "test_addr_conv.aot", "test", 0, argv);
EXPECT_EQ(1, argv[0]); EXPECT_EQ(1, argv[0]);
test_shared_heap(shared_heap, "test_addr_conv_chain.aot", "test", 0, argv);
EXPECT_EQ(1, argv[0]);
} }
TEST_F(shared_heap_test, test_addr_conv_pre_allocated_oob) TEST_F(shared_heap_test, test_addr_conv_pre_allocated_oob)
@ -412,6 +729,12 @@ TEST_F(shared_heap_test, test_addr_conv_pre_allocated_oob)
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap, "test_addr_conv.aot", EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap, "test_addr_conv.aot",
"test_preallocated", 1, argv), "test_preallocated", 1, argv),
"Exception: out of bounds memory access"); "Exception: out of bounds memory access");
argv[0] = app_addr;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap,
"test_addr_conv_chain.aot",
"test_preallocated", 1, argv),
"Exception: out of bounds memory access");
} }
TEST_F(shared_heap_test, test_shared_heap_chain) TEST_F(shared_heap_test, test_shared_heap_chain)
@ -453,9 +776,8 @@ TEST_F(shared_heap_test, test_shared_heap_chain)
test_shared_heap(shared_heap_chain, "test_addr_conv.wasm", "test", 0, argv); test_shared_heap(shared_heap_chain, "test_addr_conv.wasm", "test", 0, argv);
EXPECT_EQ(1, argv[0]); EXPECT_EQ(1, argv[0]);
/* TODO: test aot when chain is supported in AOT */ test_shared_heap(shared_heap, "test_addr_conv.aot", "test", 0, argv);
/*test_shared_heap(shared_heap, "test_addr_conv.aot", "test", 1, argv); EXPECT_EQ(1, argv[0]);
EXPECT_EQ(1, argv[0]);*/
} }
TEST_F(shared_heap_test, test_shared_heap_chain_create_fail) TEST_F(shared_heap_test, test_shared_heap_chain_create_fail)
@ -666,14 +988,15 @@ TEST_F(shared_heap_test, test_shared_heap_chain_addr_conv)
"test_preallocated", 1, argv); "test_preallocated", 1, argv);
EXPECT_EQ(1, argv[0]); EXPECT_EQ(1, argv[0]);
/* TODO: test aot when chain is supported in AOT */ argv[0] = 0xFFFFFFFF;
/*argv[0] = 0xFFFFFFFF; test_shared_heap(shared_heap, "test_addr_conv_chain.aot",
test_shared_heap(shared_heap, "test_addr_conv.aot", "test", 1, argv); "test_preallocated", 1, argv);
EXPECT_EQ(1, argv[0]); EXPECT_EQ(1, argv[0]);
argv[0] = 0xFFFFF000; argv[0] = 0xFFFFF000;
test_shared_heap(shared_heap, "test_addr_conv.aot", "test", 1, argv); test_shared_heap(shared_heap, "test_addr_conv_chain.aot",
EXPECT_EQ(1, argv[0]); */ "test_preallocated", 1, argv);
EXPECT_EQ(1, argv[0]);
} }
TEST_F(shared_heap_test, test_shared_heap_chain_addr_conv_oob) TEST_F(shared_heap_test, test_shared_heap_chain_addr_conv_oob)
@ -719,10 +1042,10 @@ TEST_F(shared_heap_test, test_shared_heap_chain_addr_conv_oob)
"test_preallocated", 1, argv), "test_preallocated", 1, argv),
"Exception: out of bounds memory access"); "Exception: out of bounds memory access");
/* TODO: test aot when chain is supported in AOT */ /* test aot */
/*argv[0] = 0xFFFFFFFF - BUF_SIZE - 4096; argv[0] = 0xFFFFFFFF - BUF_SIZE - 4096;
EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain, EXPECT_NONFATAL_FAILURE(test_shared_heap(shared_heap_chain,
"test_addr_conv.aot", "test_addr_conv_chain.aot",
"test_preallocated", 1, argv), "test_preallocated", 1, argv),
"Exception: out of bounds memory access");*/ "Exception: out of bounds memory access");
} }

View File

@ -29,44 +29,81 @@ set(CMAKE_EXE_LINKER_FLAGS
-Wl,--allow-undefined" -Wl,--allow-undefined"
) )
if (WAMR_BUILD_TARGET STREQUAL "X86_32")
set (WAMR_COMPILER_FLAGS --opt-level=3 --bounds-checks=1 --enable-shared-heap --target=i386)
set (WAMR_COMPILER_CHAIN_FLAGS --opt-level=3 --bounds-checks=1 --enable-shared-chain --target=i386)
else ()
set (WAMR_COMPILER_FLAGS --opt-level=3 --bounds-checks=1 --enable-shared-heap)
set (WAMR_COMPILER_CHAIN_FLAGS --opt-level=3 --bounds-checks=1 --enable-shared-chain)
endif ()
function(copy_wasm TARGET_NAME)
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
${CMAKE_CURRENT_BINARY_DIR}/../
COMMENT "Copy ${TARGET_NAME} to the same directory of google test"
)
endfunction()
function(compile_and_copy_aot_from TARGET_NAME)
string(REPLACE ".wasm" ".aot" AOT_TARGET ${TARGET_NAME})
string(REPLACE ".wasm" "_chain.aot" AOT_CHAIN_TARGET ${TARGET_NAME})
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_FLAGS}
-o ${AOT_TARGET}
${TARGET_NAME}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${AOT_TARGET}
${CMAKE_CURRENT_BINARY_DIR}/../
COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_CHAIN_FLAGS}
-o ${AOT_CHAIN_TARGET}
${TARGET_NAME}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${AOT_CHAIN_TARGET}
${CMAKE_CURRENT_BINARY_DIR}/../
COMMENT "Compile and copy ${AOT_TARGET} to the same directory of google test"
)
endfunction()
add_executable(test.wasm test.c) add_executable(test.wasm test.c)
target_link_libraries(test.wasm) target_link_libraries(test.wasm)
copy_wasm(test.wasm)
add_custom_command(TARGET test.wasm POST_BUILD compile_and_copy_aot_from(test.wasm)
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/test.wasm
${CMAKE_CURRENT_BINARY_DIR}/../
COMMENT "Copy test.wasm to the same directory of google test"
)
add_custom_command(TARGET test.wasm POST_BUILD
COMMAND ${WAMRC_ROOT_DIR}/wamrc --opt-level=0 --enable-shared-heap --bounds-checks=1
-o
test.aot
test.wasm
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/test.aot
${CMAKE_CURRENT_BINARY_DIR}/../
COMMENT "Copy test.aot to the same directory of google test"
)
add_executable(test_addr_conv.wasm test_addr_conv.c) add_executable(test_addr_conv.wasm test_addr_conv.c)
target_link_libraries(test.wasm) target_link_libraries(test_addr_conv.wasm)
copy_wasm(test_addr_conv.wasm)
compile_and_copy_aot_from(test_addr_conv.wasm)
add_custom_command(TARGET test_addr_conv.wasm POST_BUILD # copy and compile aot for bulk memory test
set(SOURCE_WASM ${CMAKE_CURRENT_SOURCE_DIR}/bulk-memory/test_bulk_memory.wasm)
set(BUILD_WASM ${CMAKE_CURRENT_BINARY_DIR}/../test_bulk_memory.wasm)
set(OUTPUT_AOT ${CMAKE_CURRENT_BINARY_DIR}/../test_bulk_memory.aot)
set(OUTPUT_CHAIN_AOT ${CMAKE_CURRENT_BINARY_DIR}/../test_bulk_memory_chain.aot)
add_custom_command(
OUTPUT ${BUILD_WASM}
COMMAND ${CMAKE_COMMAND} -E copy COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/test_addr_conv.wasm ${SOURCE_WASM}
${CMAKE_CURRENT_BINARY_DIR}/../ ${BUILD_WASM}
COMMENT "Copy test_addr_conv.wasm to the same directory of google test" DEPENDS ${SOURCE_WASM}
COMMENT "Copying bulk memory WASM to build directory"
) )
add_custom_command(TARGET test_addr_conv.wasm POST_BUILD add_custom_command(
COMMAND ${WAMRC_ROOT_DIR}/wamrc --opt-level=0 --enable-shared-heap --bounds-checks=1 OUTPUT ${OUTPUT_AOT}
-o COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_FLAGS}
test_addr_conv.aot -o ${OUTPUT_AOT}
test_addr_conv.wasm ${BUILD_WASM}
COMMAND ${CMAKE_COMMAND} -E copy COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_CHAIN_FLAGS}
${CMAKE_CURRENT_BINARY_DIR}/test_addr_conv.aot -o ${OUTPUT_CHAIN_AOT}
${CMAKE_CURRENT_BINARY_DIR}/../ ${BUILD_WASM}
COMMENT "Copy test_addr_conv.aot to the same directory of google test" DEPENDS ${BUILD_WASM}
COMMENT "Compiling bulk memory AOT from copied WASM"
)
add_custom_target(compile_bulk_memory_aot ALL
DEPENDS ${OUTPUT_AOT}
) )

View File

@ -0,0 +1,12 @@
(module
(memory 1)
(func $memory_fill_test (param $dst i32) (param $val i32) (param $len i32)
local.get $dst
local.get $val
local.get $len
memory.fill
)
(export "memory_fill_test" (func $memory_fill_test))
)

View File

@ -0,0 +1,68 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required(VERSION 3.14)
project(wasm-apps-wasm64)
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..)
set(WAMRC_ROOT_DIR ${WAMR_ROOT_DIR}/wamr-compiler/build)
set(CMAKE_SYSTEM_PROCESSOR wasm64)
set(CMAKE_SYSROOT ${WAMR_ROOT_DIR}/wamr-sdk/app/libc-builtin-sysroot)
if (NOT DEFINED WASI_SDK_DIR)
set(WASI_SDK_DIR "/opt/wasi-sdk")
endif ()
set(CMAKE_C_FLAGS "-nostdlib -pthread -Qunused-arguments")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z stack-size=8192 -nostdlib -O0 --target=wasm64")
set(CMAKE_C_COMPILER_TARGET "wasm64")
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,--no-entry \
-Wl,--initial-memory=65536 \
-Wl,--export-all \
-Wl,--allow-undefined"
)
set (WAMR_COMPILER_FLAGS --opt-level=3 --bounds-checks=1 --enable-shared-heap)
set (WAMR_COMPILER_CHAIN_FLAGS --opt-level=3 --bounds-checks=1 --enable-shared-chain)
function(copy_wasm TARGET_NAME)
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
${CMAKE_CURRENT_BINARY_DIR}/../../
COMMENT "Copy ${TARGET_NAME} to the same directory of google test"
)
endfunction()
function(compile_and_copy_aot_from TARGET_NAME)
string(REPLACE ".wasm" ".aot" AOT_TARGET ${TARGET_NAME})
string(REPLACE ".wasm" "_chain.aot" AOT_CHAIN_TARGET ${TARGET_NAME})
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_FLAGS}
-o ${AOT_TARGET}
${TARGET_NAME}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${AOT_TARGET}
${CMAKE_CURRENT_BINARY_DIR}/../../
COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_CHAIN_FLAGS}
-o ${AOT_CHAIN_TARGET}
${TARGET_NAME}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${AOT_CHAIN_TARGET}
${CMAKE_CURRENT_BINARY_DIR}/../../
COMMENT "Compile and copy ${AOT_TARGET} ${AOT_CHAIN_TARGET} to the same directory of google test"
)
endfunction()
add_executable(test64.wasm ../test.c)
target_link_libraries(test64.wasm)
copy_wasm(test64.wasm)
compile_and_copy_aot_from(test64.wasm)

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/ */
#include <stdio.h> #define NULL 0
extern void * extern void *
shared_heap_malloc(int size); shared_heap_malloc(int size);

View File

@ -284,6 +284,7 @@ include (${IWASM_DIR}/interpreter/iwasm_interp.cmake)
include (${IWASM_DIR}/aot/iwasm_aot.cmake) include (${IWASM_DIR}/aot/iwasm_aot.cmake)
include (${IWASM_DIR}/compilation/iwasm_compl.cmake) include (${IWASM_DIR}/compilation/iwasm_compl.cmake)
include (${PROJECT_SOURCE_DIR}/../build-scripts/version.cmake) include (${PROJECT_SOURCE_DIR}/../build-scripts/version.cmake)
include (${IWASM_DIR}/libraries/shared-heap/shared_heap.cmake)
if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
@ -366,6 +367,7 @@ add_library (vmlib
${LIBC_WASI_SOURCE} ${LIBC_WASI_SOURCE}
${LIB_PTHREAD_SOURCE} ${LIB_PTHREAD_SOURCE}
${LIB_WASI_THREADS_SOURCE} ${LIB_WASI_THREADS_SOURCE}
${LIB_SHARED_HEAP_SOURCE}
${IWASM_COMMON_SOURCE} ${IWASM_COMMON_SOURCE}
${IWASM_INTERP_SOURCE} ${IWASM_INTERP_SOURCE}
${IWASM_AOT_SOURCE} ${IWASM_AOT_SOURCE}

View File

@ -210,7 +210,9 @@ print_help()
printf(" --enable-linux-perf Enable linux perf support\n"); printf(" --enable-linux-perf Enable linux perf support\n");
#endif #endif
printf(" --mllvm=<option> Add the LLVM command line option\n"); printf(" --mllvm=<option> Add the LLVM command line option\n");
printf(" --enable-shared-heap Enable shared heap feature\n"); printf(" --enable-shared-heap Enable shared heap feature, assuming only one shared heap will be attached\n");
printf(" --enable-shared-chain Enable shared heap chain feature, works for more than one shared heap\n");
printf(" WARNING: enable this feature will largely increase code size\n");
printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
printf(" --version Show version information\n"); printf(" --version Show version information\n");
printf("Examples: wamrc -o test.aot test.wasm\n"); printf("Examples: wamrc -o test.aot test.wasm\n");
@ -658,6 +660,9 @@ main(int argc, char *argv[])
else if (!strcmp(argv[0], "--enable-shared-heap")) { else if (!strcmp(argv[0], "--enable-shared-heap")) {
option.enable_shared_heap = true; option.enable_shared_heap = true;
} }
else if (!strcmp(argv[0], "--enable-shared-chain")) {
option.enable_shared_chain = true;
}
else if (!strcmp(argv[0], "--version")) { else if (!strcmp(argv[0], "--version")) {
uint32 major, minor, patch; uint32 major, minor, patch;
wasm_runtime_get_version(&major, &minor, &patch); wasm_runtime_get_version(&major, &minor, &patch);
@ -720,6 +725,13 @@ main(int argc, char *argv[])
option.enable_ref_types = false; option.enable_ref_types = false;
} }
if (option.enable_shared_chain) {
LOG_VERBOSE("Enable shared chain will overwrite shared heap and sw "
"bounds control");
option.enable_shared_heap = false;
option.bounds_checks = true;
}
if (!use_dummy_wasm) { if (!use_dummy_wasm) {
wasm_file_name = argv[0]; wasm_file_name = argv[0];