mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-09-05 17:32:26 +00:00
Shared heap enhancements for Interpreter and AOT (#4400)
Propose two enhancements: - Shared heap created from preallocated memory buffer: The user can create a shared heap from a pre-allocated buffer and see that memory region as one large chunk; there's no need to dynamically manage it(malloc/free). The user needs to make sure the native address and size of that memory region are valid. - Introduce shared heap chain: The user can create a shared heap chain, from the wasm app point of view, it's still a continuous memory region in wasm app's point of view while in the native it can consist of multiple shared heaps (each of which is a continuous memory region). For example, one 500MB shared heap 1 and one 500 MB shared heap 2 form a chain, in Wasm's point of view, it's one 1GB shared heap. After these enhancements, the data sharing between wasm apps, and between hosts can be more efficient and flexible. Admittedly shared heap management can be more complex for users, but it's similar to the zero-overhead principle. No overhead will be imposed for the users who don't use the shared heap enhancement or don't use the shared heap at all.
This commit is contained in:
parent
ee056d8076
commit
8a55a1e7a1
|
@ -185,6 +185,13 @@ typedef struct {
|
|||
#define REG_STRINGREF_SYM()
|
||||
#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 \
|
||||
REG_SYM(aot_set_exception_with_id), \
|
||||
REG_SYM(aot_invoke_native), \
|
||||
|
@ -218,6 +225,7 @@ typedef struct {
|
|||
REG_LLVM_PGO_SYM() \
|
||||
REG_GC_SYM() \
|
||||
REG_STRINGREF_SYM() \
|
||||
REG_SHARED_HEAP_SYM() \
|
||||
|
||||
#define CHECK_RELOC_OFFSET(data_size) do { \
|
||||
if (!check_reloc_offset(target_section_size, \
|
||||
|
|
|
@ -60,6 +60,16 @@ bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0);
|
|||
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj)
|
||||
== 8);
|
||||
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_start_off) == 16);
|
||||
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_end_off) == 24);
|
||||
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);
|
||||
|
||||
|
@ -1989,6 +1999,8 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
|
|||
#else
|
||||
extra->shared_heap_start_off.u32[0] = UINT32_MAX;
|
||||
#endif
|
||||
/* After shared heap chain, will early stop if shared heap is NULL */
|
||||
extra->shared_heap = NULL;
|
||||
|
||||
#if WASM_ENABLE_PERF_PROFILING != 0
|
||||
total_size = sizeof(AOTFuncPerfProfInfo)
|
||||
|
|
|
@ -125,6 +125,8 @@ typedef struct AOTModuleInstanceExtra {
|
|||
*/
|
||||
DefPointer(uint8 *, shared_heap_base_addr_adj);
|
||||
MemBound shared_heap_start_off;
|
||||
MemBound shared_heap_end_off;
|
||||
DefPointer(WASMSharedHeap *, shared_heap);
|
||||
|
||||
WASMModuleInstanceExtraCommon common;
|
||||
|
||||
|
@ -142,9 +144,6 @@ typedef struct AOTModuleInstanceExtra {
|
|||
WASMModuleInstanceCommon **import_func_module_insts;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
WASMSharedHeap *shared_heap;
|
||||
#endif
|
||||
} AOTModuleInstanceExtra;
|
||||
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
||||
|
|
|
@ -143,7 +143,7 @@ is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
|
|||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
static void *
|
||||
wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size);
|
||||
wasm_mmap_linear_memory(uint64 map_size, uint64 commit_size);
|
||||
static void
|
||||
wasm_munmap_linear_memory(void *mapped_mem, uint64 commit_size,
|
||||
uint64 map_size);
|
||||
|
@ -177,39 +177,54 @@ wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args)
|
|||
goto fail1;
|
||||
}
|
||||
|
||||
if (!(heap->heap_handle =
|
||||
runtime_malloc(mem_allocator_get_heap_struct_size()))) {
|
||||
size = align_uint(size, os_getpagesize());
|
||||
if (size > APP_HEAP_SIZE_MAX || size < APP_HEAP_SIZE_MIN) {
|
||||
LOG_WARNING("Invalid size of shared heap");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
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) {
|
||||
LOG_WARNING("Invalid size of shared heap");
|
||||
goto fail3;
|
||||
if (init_args->pre_allocated_addr != NULL) {
|
||||
/* Create shared heap from a pre allocated buffer, its size need to
|
||||
* align with system page */
|
||||
if (size != init_args->size) {
|
||||
LOG_WARNING("Pre allocated size need to be aligned with system "
|
||||
"page size to create shared heap");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
heap->heap_handle = NULL;
|
||||
heap->base_addr = init_args->pre_allocated_addr;
|
||||
}
|
||||
else {
|
||||
if (!(heap->heap_handle =
|
||||
runtime_malloc(mem_allocator_get_heap_struct_size()))) {
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
map_size = size;
|
||||
map_size = size;
|
||||
#else
|
||||
/* Totally 8G is mapped, the opcode load/store address range is 0 to 8G:
|
||||
* ea = i + memarg.offset
|
||||
* both i and memarg.offset are u32 in range 0 to 4G
|
||||
* so the range of ea is 0 to 8G
|
||||
*/
|
||||
map_size = 8 * (uint64)BH_GB;
|
||||
/* Totally 8G is mapped, the opcode load/store address range is 0 to 8G:
|
||||
* ea = i + memarg.offset
|
||||
* both i and memarg.offset are u32 in range 0 to 4G
|
||||
* so the range of ea is 0 to 8G
|
||||
*/
|
||||
map_size = 8 * (uint64)BH_GB;
|
||||
#endif
|
||||
|
||||
if (!(heap->base_addr = wasm_mmap_linear_memory(map_size, size))) {
|
||||
goto fail3;
|
||||
}
|
||||
if (!mem_allocator_create_with_struct_and_pool(
|
||||
heap->heap_handle, heap_struct_size, heap->base_addr, size)) {
|
||||
LOG_WARNING("init share heap failed");
|
||||
goto fail4;
|
||||
if (!(heap->base_addr = wasm_mmap_linear_memory(map_size, size))) {
|
||||
goto fail3;
|
||||
}
|
||||
if (!mem_allocator_create_with_struct_and_pool(
|
||||
heap->heap_handle, heap_struct_size, heap->base_addr, size)) {
|
||||
LOG_WARNING("init share heap failed");
|
||||
goto fail4;
|
||||
}
|
||||
}
|
||||
|
||||
os_mutex_lock(&shared_heap_list_lock);
|
||||
|
@ -233,6 +248,219 @@ fail1:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
WASMSharedHeap *
|
||||
wasm_runtime_chain_shared_heaps(WASMSharedHeap *head, WASMSharedHeap *body)
|
||||
{
|
||||
WASMSharedHeap *cur;
|
||||
bool heap_handle_exist = false;
|
||||
|
||||
if (!head || !body) {
|
||||
LOG_WARNING("Invalid shared heap to chain.");
|
||||
return NULL;
|
||||
}
|
||||
heap_handle_exist = head->heap_handle != NULL;
|
||||
|
||||
os_mutex_lock(&shared_heap_list_lock);
|
||||
if (head->attached_count != 0 || body->attached_count != 0) {
|
||||
LOG_WARNING("To create shared heap chain, all shared heap need to be "
|
||||
"detached first.");
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
return NULL;
|
||||
}
|
||||
for (cur = shared_heap_list; cur; cur = cur->next) {
|
||||
if (cur->chain_next == body || cur->chain_next == head) {
|
||||
LOG_WARNING(
|
||||
"To create shared heap chain, both the 'head' and 'body' "
|
||||
"shared heap can't already be the 'body' in another a chain");
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
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) {
|
||||
if (cur->heap_handle && heap_handle_exist) {
|
||||
LOG_WARNING(
|
||||
"To create shared heap chain, only one of shared heap can "
|
||||
"dynamically shared_heap_malloc and shared_heap_free, the rest "
|
||||
"can only be pre-allocated shared heap");
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
return NULL;
|
||||
}
|
||||
if (cur->heap_handle)
|
||||
heap_handle_exist = true;
|
||||
}
|
||||
|
||||
head->start_off_mem64 = body->start_off_mem64 - head->size;
|
||||
head->start_off_mem32 = body->start_off_mem32 - head->size;
|
||||
head->chain_next = body;
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
return head;
|
||||
}
|
||||
|
||||
WASMSharedHeap *
|
||||
wasm_runtime_unchain_shared_heaps(WASMSharedHeap *head, bool entire_chain)
|
||||
{
|
||||
WASMSharedHeap *cur, *tmp;
|
||||
|
||||
if (!head || !head->chain_next) {
|
||||
LOG_WARNING("Invalid shared heap chain to disconnect the head from.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_mutex_lock(&shared_heap_list_lock);
|
||||
if (head->attached_count != 0) {
|
||||
LOG_WARNING("To disconnect the shared heap head from the shared heap "
|
||||
"chain, the shared heap chain needs to be detached first.");
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur = head;
|
||||
while (cur && cur->chain_next) {
|
||||
cur->start_off_mem64 = UINT64_MAX - cur->size + 1;
|
||||
cur->start_off_mem32 = UINT32_MAX - cur->size + 1;
|
||||
tmp = cur;
|
||||
cur = cur->chain_next;
|
||||
tmp->chain_next = NULL;
|
||||
if (!entire_chain)
|
||||
break;
|
||||
}
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static uint8 *
|
||||
get_last_used_shared_heap_base_addr_adj(WASMModuleInstanceCommon *module_inst)
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMModuleInstanceExtra *e =
|
||||
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
|
||||
return e->shared_heap_base_addr_adj;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
AOTModuleInstanceExtra *e =
|
||||
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
|
||||
return e->shared_heap_base_addr_adj;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_AOT != 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
get_last_used_shared_heap_start_offset(WASMModuleInstanceCommon *module_inst)
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMModuleInstanceExtra *e =
|
||||
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
return e->shared_heap_start_off.u64;
|
||||
#else
|
||||
return e->shared_heap_start_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
AOTModuleInstanceExtra *e =
|
||||
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
return e->shared_heap_start_off.u64;
|
||||
#else
|
||||
return e->shared_heap_start_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_AOT != 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
get_last_used_shared_heap_end_offset(WASMModuleInstanceCommon *module_inst)
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMModuleInstanceExtra *e =
|
||||
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
return e->shared_heap_end_off.u64;
|
||||
#else
|
||||
return e->shared_heap_end_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
AOTModuleInstanceExtra *e =
|
||||
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
return e->shared_heap_end_off.u64;
|
||||
#else
|
||||
return e->shared_heap_end_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_AOT != 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
update_last_used_shared_heap(WASMModuleInstanceCommon *module_inst,
|
||||
WASMSharedHeap *shared_heap, bool is_memory64)
|
||||
{
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMModuleInstanceExtra *e =
|
||||
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
if (is_memory64)
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
|
||||
else
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
|
||||
e->shared_heap_end_off.u64 =
|
||||
e->shared_heap_start_off.u64 - 1 + shared_heap->size;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u64;
|
||||
#else
|
||||
e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
|
||||
e->shared_heap_end_off.u32[0] =
|
||||
e->shared_heap_start_off.u32[0] - 1 + shared_heap->size;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
AOTModuleInstanceExtra *e =
|
||||
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
if (is_memory64)
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
|
||||
else
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
|
||||
e->shared_heap_end_off.u64 =
|
||||
e->shared_heap_start_off.u64 - 1 + shared_heap->size;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u64;
|
||||
#else
|
||||
e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
|
||||
e->shared_heap_end_off.u32[0] =
|
||||
e->shared_heap_start_off.u32[0] - 1 + shared_heap->size;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_AOT != 0 */
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
|
||||
WASMSharedHeap *shared_heap)
|
||||
|
@ -263,20 +491,6 @@ wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
|
|||
return false;
|
||||
}
|
||||
e->shared_heap = shared_heap;
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
if (memory->is_memory64)
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
|
||||
else
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u64;
|
||||
#else
|
||||
e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u32[0];
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_JIT != 0 */
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
|
@ -288,21 +502,13 @@ wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
|
|||
return false;
|
||||
}
|
||||
e->shared_heap = shared_heap;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
if (memory->is_memory64)
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
|
||||
else
|
||||
e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u64;
|
||||
#else
|
||||
e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
|
||||
e->shared_heap_base_addr_adj =
|
||||
shared_heap->base_addr - e->shared_heap_start_off.u32[0];
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_AOT != 0 */
|
||||
update_last_used_shared_heap(module_inst, shared_heap, memory->is_memory64);
|
||||
|
||||
os_mutex_lock(&shared_heap_list_lock);
|
||||
shared_heap->attached_count++;
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -320,30 +526,46 @@ wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
|
|||
void
|
||||
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 (module_inst->module_type == Wasm_Module_Bytecode) {
|
||||
WASMModuleInstanceExtra *e =
|
||||
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
|
||||
if (e->shared_heap != NULL) {
|
||||
os_mutex_lock(&shared_heap_list_lock);
|
||||
e->shared_heap->attached_count--;
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
}
|
||||
e->shared_heap = NULL;
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
e->shared_heap_start_off.u64 = UINT64_MAX;
|
||||
e->shared_heap_end_off.u64 = UINT64_MAX - 1;
|
||||
#else
|
||||
e->shared_heap_start_off.u32[0] = UINT32_MAX;
|
||||
e->shared_heap_end_off.u32[0] = UINT32_MAX - 1;
|
||||
#endif
|
||||
e->shared_heap_base_addr_adj = NULL;
|
||||
#endif
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT) {
|
||||
AOTModuleInstanceExtra *e =
|
||||
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
|
||||
if (e->shared_heap != NULL) {
|
||||
os_mutex_lock(&shared_heap_list_lock);
|
||||
e->shared_heap->attached_count--;
|
||||
os_mutex_unlock(&shared_heap_list_lock);
|
||||
}
|
||||
e->shared_heap = NULL;
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
e->shared_heap_start_off.u64 = UINT64_MAX;
|
||||
e->shared_heap_end_off.u64 = UINT64_MAX - 1;
|
||||
#else
|
||||
e->shared_heap_start_off.u32[0] = UINT32_MAX;
|
||||
e->shared_heap_end_off.u32[0] = UINT32_MAX - 1;
|
||||
#endif
|
||||
e->shared_heap_base_addr_adj = NULL;
|
||||
}
|
||||
|
@ -385,71 +607,93 @@ wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm)
|
|||
return get_shared_heap(module_inst_comm);
|
||||
}
|
||||
|
||||
static bool
|
||||
bool
|
||||
is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
|
||||
bool is_memory64, uint64 app_offset, uint32 bytes)
|
||||
{
|
||||
WASMSharedHeap *heap = get_shared_heap(module_inst);
|
||||
WASMSharedHeap *heap = get_shared_heap(module_inst), *cur;
|
||||
uint64 shared_heap_start, shared_heap_end;
|
||||
|
||||
if (!heap) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
bytes = 1;
|
||||
}
|
||||
|
||||
if (!is_memory64) {
|
||||
if (app_offset >= heap->start_off_mem32
|
||||
&& app_offset <= UINT32_MAX - bytes + 1) {
|
||||
return true;
|
||||
}
|
||||
shared_heap_start =
|
||||
(uint64)get_last_used_shared_heap_start_offset(module_inst);
|
||||
shared_heap_end = (uint64)get_last_used_shared_heap_end_offset(module_inst);
|
||||
if (bytes - 1 <= shared_heap_end && app_offset >= shared_heap_start
|
||||
&& app_offset <= shared_heap_end - bytes + 1) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (app_offset >= heap->start_off_mem64
|
||||
&& app_offset <= UINT64_MAX - bytes + 1) {
|
||||
|
||||
/* Early stop for app start address not in the shared heap(chain) at all */
|
||||
shared_heap_start =
|
||||
is_memory64 ? heap->start_off_mem64 : heap->start_off_mem32;
|
||||
shared_heap_end = is_memory64 ? UINT64_MAX : UINT32_MAX;
|
||||
if (bytes - 1 > shared_heap_end || app_offset < shared_heap_start
|
||||
|| app_offset > shared_heap_end - bytes + 1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Find the exact shared heap that app addr is in, and update last used
|
||||
* shared heap info in module inst extra */
|
||||
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) {
|
||||
update_last_used_shared_heap(module_inst, cur, is_memory64);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
|
||||
uint8 *addr, uint32 bytes)
|
||||
bool is_memory64, uint8 *addr, uint32 bytes)
|
||||
{
|
||||
WASMSharedHeap *heap = get_shared_heap(module_inst);
|
||||
uintptr_t base_addr;
|
||||
uintptr_t addr_int;
|
||||
uintptr_t end_addr;
|
||||
WASMSharedHeap *cur, *heap = get_shared_heap(module_inst);
|
||||
uintptr_t base_addr, addr_int, end_addr;
|
||||
|
||||
if (!heap) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
base_addr = (uintptr_t)heap->base_addr;
|
||||
addr_int = (uintptr_t)addr;
|
||||
if (addr_int < base_addr) {
|
||||
return false;
|
||||
/* Iterate through shared heap chain to find whether native addr in one of
|
||||
* shared heap */
|
||||
for (cur = heap; cur != NULL; cur = cur->chain_next) {
|
||||
base_addr = (uintptr_t)cur->base_addr;
|
||||
addr_int = (uintptr_t)addr;
|
||||
if (addr_int < base_addr)
|
||||
continue;
|
||||
|
||||
end_addr = addr_int + bytes;
|
||||
/* Check for overflow */
|
||||
if (end_addr <= addr_int)
|
||||
continue;
|
||||
|
||||
if (end_addr > base_addr + cur->size)
|
||||
continue;
|
||||
|
||||
update_last_used_shared_heap(module_inst, cur, is_memory64);
|
||||
return true;
|
||||
}
|
||||
|
||||
end_addr = addr_int + bytes;
|
||||
/* Check for overflow */
|
||||
if (end_addr <= addr_int) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (end_addr > base_addr + heap->size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64
|
||||
wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
|
||||
uint64_t size, void **p_native_addr)
|
||||
uint64 size, void **p_native_addr)
|
||||
{
|
||||
WASMMemoryInstance *memory =
|
||||
wasm_get_default_memory((WASMModuleInstance *)module_inst);
|
||||
|
@ -459,6 +703,14 @@ wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
|
|||
if (!memory || !shared_heap)
|
||||
return 0;
|
||||
|
||||
while (shared_heap && !shared_heap->heap_handle) {
|
||||
shared_heap = shared_heap->chain_next;
|
||||
}
|
||||
if (!shared_heap) {
|
||||
LOG_WARNING("Can't allocate from pre allocated shared heap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
native_addr = mem_allocator_malloc(shared_heap->heap_handle, size);
|
||||
if (!native_addr)
|
||||
return 0;
|
||||
|
@ -467,12 +719,10 @@ wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
|
|||
*p_native_addr = native_addr;
|
||||
}
|
||||
|
||||
if (memory->is_memory64)
|
||||
return shared_heap->start_off_mem64
|
||||
+ ((uint8 *)native_addr - shared_heap->base_addr);
|
||||
else
|
||||
return shared_heap->start_off_mem32
|
||||
+ ((uint8 *)native_addr - shared_heap->base_addr);
|
||||
return memory->is_memory64
|
||||
? shared_heap->start_off_mem64
|
||||
: shared_heap->start_off_mem32
|
||||
+ ((uint8 *)native_addr - shared_heap->base_addr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -487,6 +737,14 @@ wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst, uint64 ptr)
|
|||
return;
|
||||
}
|
||||
|
||||
while (shared_heap && !shared_heap->heap_handle) {
|
||||
shared_heap = shared_heap->chain_next;
|
||||
}
|
||||
if (!shared_heap) {
|
||||
LOG_WARNING("The address to free is from pre allocated shared heap");
|
||||
return;
|
||||
}
|
||||
|
||||
if (memory->is_memory64) {
|
||||
if (ptr < shared_heap->start_off_mem64) { /* ptr can not > UINT64_MAX */
|
||||
LOG_WARNING("The address to free isn't in shared heap");
|
||||
|
@ -564,14 +822,16 @@ destroy_shared_heaps()
|
|||
while (heap) {
|
||||
cur = heap;
|
||||
heap = heap->next;
|
||||
mem_allocator_destroy(cur->heap_handle);
|
||||
wasm_runtime_free(cur->heap_handle);
|
||||
if (cur->heap_handle) {
|
||||
mem_allocator_destroy(cur->heap_handle);
|
||||
wasm_runtime_free(cur->heap_handle);
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
map_size = cur->size;
|
||||
map_size = cur->size;
|
||||
#else
|
||||
map_size = 8 * (uint64)BH_GB;
|
||||
map_size = 8 * (uint64)BH_GB;
|
||||
#endif
|
||||
wasm_munmap_linear_memory(cur->base_addr, cur->size, map_size);
|
||||
wasm_munmap_linear_memory(cur->base_addr, cur->size, map_size);
|
||||
}
|
||||
wasm_runtime_free(cur);
|
||||
}
|
||||
os_mutex_destroy(&shared_heap_list_lock);
|
||||
|
@ -798,6 +1058,10 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
|
|||
WASMMemoryInstance *memory_inst;
|
||||
uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE;
|
||||
char *str, *str_end;
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
uintptr_t shared_heap_end_off;
|
||||
char *shared_heap_base_addr_adj;
|
||||
#endif
|
||||
|
||||
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|
||||
|| module_inst_comm->module_type == Wasm_Module_AoT);
|
||||
|
@ -814,12 +1078,12 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
|
|||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64,
|
||||
app_str_offset, 1)) {
|
||||
WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm);
|
||||
str = (char *)shared_heap->base_addr
|
||||
+ (memory_inst->is_memory64
|
||||
? (app_str_offset - shared_heap->start_off_mem64)
|
||||
: (app_str_offset - shared_heap->start_off_mem32));
|
||||
str_end = (char *)shared_heap->base_addr + shared_heap->size;
|
||||
shared_heap_end_off =
|
||||
get_last_used_shared_heap_end_offset(module_inst_comm);
|
||||
shared_heap_base_addr_adj =
|
||||
(char *)get_last_used_shared_heap_base_addr_adj(module_inst_comm);
|
||||
str = shared_heap_base_addr_adj + app_str_offset;
|
||||
str_end = shared_heap_base_addr_adj + shared_heap_end_off + 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -884,7 +1148,8 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm,
|
|||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (is_native_addr_in_shared_heap(module_inst_comm, native_ptr, size)) {
|
||||
if (is_native_addr_in_shared_heap(
|
||||
module_inst_comm, memory_inst->is_memory64, native_ptr, size)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -926,17 +1191,8 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
|
|||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64,
|
||||
app_offset, 1)) {
|
||||
WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm);
|
||||
uint64 shared_heap_start = 0;
|
||||
|
||||
if (memory_inst && !memory_inst->is_memory64) {
|
||||
shared_heap_start = shared_heap->start_off_mem32;
|
||||
}
|
||||
else if (memory_inst && memory_inst->is_memory64) {
|
||||
shared_heap_start = shared_heap->start_off_mem64;
|
||||
}
|
||||
|
||||
return shared_heap->base_addr + app_offset - shared_heap_start;
|
||||
return get_last_used_shared_heap_base_addr_adj(module_inst_comm)
|
||||
+ app_offset;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -974,29 +1230,17 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
|
|||
|
||||
bounds_checks = is_bounds_checks_enabled(module_inst_comm);
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
/* If shared heap is enabled, bounds check is always needed */
|
||||
bounds_checks = true;
|
||||
#endif
|
||||
|
||||
memory_inst = wasm_get_default_memory(module_inst);
|
||||
if (!memory_inst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (is_native_addr_in_shared_heap(module_inst_comm, addr, 1)) {
|
||||
WASMSharedHeap *shared_heap = get_shared_heap(module_inst_comm);
|
||||
uint64 shared_heap_start = 0;
|
||||
|
||||
if (memory_inst && !memory_inst->is_memory64) {
|
||||
shared_heap_start = shared_heap->start_off_mem32;
|
||||
}
|
||||
else if (memory_inst && memory_inst->is_memory64) {
|
||||
shared_heap_start = shared_heap->start_off_mem64;
|
||||
}
|
||||
|
||||
return shared_heap_start + (addr - shared_heap->base_addr);
|
||||
if (is_native_addr_in_shared_heap(module_inst_comm,
|
||||
memory_inst->is_memory64, addr, 1)) {
|
||||
return (uint64)(uintptr_t)(addr
|
||||
- get_last_used_shared_heap_base_addr_adj(
|
||||
module_inst_comm));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1098,8 +1342,8 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
|
|||
uint8 *native_addr;
|
||||
bool bounds_checks;
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
WASMSharedHeap *shared_heap;
|
||||
bool is_in_shared_heap = false;
|
||||
uint8 *shared_heap_base_addr_adj = NULL;
|
||||
uintptr_t shared_heap_end_off = 0;
|
||||
#endif
|
||||
|
||||
bh_assert(app_buf_addr <= UINTPTR_MAX && app_buf_size <= UINTPTR_MAX);
|
||||
|
@ -1113,36 +1357,17 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
|
|||
if (is_app_addr_in_shared_heap((WASMModuleInstanceCommon *)module_inst,
|
||||
memory_inst->is_memory64, app_buf_addr,
|
||||
app_buf_size)) {
|
||||
shared_heap = get_shared_heap((WASMModuleInstanceCommon *)module_inst);
|
||||
native_addr = shared_heap->base_addr
|
||||
+ (memory_inst->is_memory64
|
||||
? (app_buf_addr - shared_heap->start_off_mem64)
|
||||
: (app_buf_addr - shared_heap->start_off_mem32));
|
||||
is_in_shared_heap = true;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr;
|
||||
}
|
||||
|
||||
bounds_checks =
|
||||
is_bounds_checks_enabled((WASMModuleInstanceCommon *)module_inst);
|
||||
|
||||
if (!bounds_checks) {
|
||||
if (app_buf_addr == 0) {
|
||||
native_addr = NULL;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (is_in_shared_heap) {
|
||||
const char *str, *str_end;
|
||||
shared_heap_base_addr_adj = get_last_used_shared_heap_base_addr_adj(
|
||||
(WASMModuleInstanceCommon *)module_inst);
|
||||
shared_heap_end_off = get_last_used_shared_heap_end_offset(
|
||||
(WASMModuleInstanceCommon *)module_inst);
|
||||
native_addr = shared_heap_base_addr_adj + (uintptr_t)app_buf_addr;
|
||||
|
||||
/* The whole string must be in the linear memory */
|
||||
/* The whole string must be in the shared heap */
|
||||
str = (const char *)native_addr;
|
||||
str_end = (const char *)shared_heap->base_addr + shared_heap->size;
|
||||
str_end =
|
||||
(const char *)shared_heap_base_addr_adj + shared_heap_end_off + 1;
|
||||
while (str < str_end && *str != '\0')
|
||||
str++;
|
||||
if (str == str_end) {
|
||||
|
@ -1154,6 +1379,17 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
|
|||
}
|
||||
#endif
|
||||
|
||||
native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr;
|
||||
bounds_checks =
|
||||
is_bounds_checks_enabled((WASMModuleInstanceCommon *)module_inst);
|
||||
|
||||
if (!bounds_checks) {
|
||||
if (app_buf_addr == 0) {
|
||||
native_addr = NULL;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* No need to check the app_offset and buf_size if memory access
|
||||
boundary check with hardware trap is enabled */
|
||||
#ifndef OS_ENABLE_HW_BOUND_CHECK
|
||||
|
|
|
@ -41,10 +41,60 @@ SET_LINEAR_MEMORY_SIZE(WASMMemoryInstance *memory, uint64 size)
|
|||
#define SET_LINEAR_MEMORY_SIZE(memory, size) memory->memory_data_size = size
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
|
||||
#if WASM_ENABLE_MULTI_MEMORY != 0
|
||||
/* Only enable shared heap for the default memory */
|
||||
#define is_default_memory (memidx == 0)
|
||||
#else
|
||||
#define is_default_memory true
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
#define get_shared_heap_end_off() module->e->shared_heap_end_off.u64
|
||||
#else
|
||||
#define get_shared_heap_end_off() \
|
||||
(uint64)(module->e->shared_heap_end_off.u32[0])
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MEMORY64 != 0
|
||||
#define shared_heap_is_memory64 is_memory64
|
||||
#else
|
||||
#define shared_heap_is_memory64 false
|
||||
#endif
|
||||
|
||||
#define app_addr_in_shared_heap(app_addr, bytes) \
|
||||
(is_default_memory \
|
||||
&& is_app_addr_in_shared_heap((WASMModuleInstanceCommon *)module, \
|
||||
shared_heap_is_memory64, (uint64)app_addr, \
|
||||
bytes))
|
||||
#define shared_heap_addr_app_to_native(app_addr, native_addr) \
|
||||
native_addr = module->e->shared_heap_base_addr_adj + app_addr
|
||||
#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \
|
||||
if (app_addr_in_shared_heap(app_addr, bytes)) \
|
||||
shared_heap_addr_app_to_native(app_addr, native_addr); \
|
||||
else
|
||||
|
||||
#else /* else of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr)
|
||||
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
#endif /* end of WASM_ENABLE_INTERP != 0 */
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
bool
|
||||
is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
|
||||
bool is_memory64, uint64 app_offset, uint32 bytes);
|
||||
|
||||
WASMSharedHeap *
|
||||
wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);
|
||||
|
||||
WASMSharedHeap *
|
||||
wasm_runtime_chain_shared_heaps(WASMSharedHeap *head, WASMSharedHeap *body);
|
||||
|
||||
WASMSharedHeap *
|
||||
wasm_runtime_unchain_shared_heaps(WASMSharedHeap *head, bool entire_chain);
|
||||
|
||||
bool
|
||||
wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
|
||||
WASMSharedHeap *shared_heap);
|
||||
|
@ -68,7 +118,7 @@ wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
|
|||
void
|
||||
wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst,
|
||||
uint64 ptr);
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
|
||||
bool
|
||||
wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
|
||||
|
|
|
@ -7883,3 +7883,37 @@ wasm_runtime_is_underlying_binary_freeable(WASMModuleCommon *const module)
|
|||
|
||||
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
|
||||
|
|
|
@ -1336,6 +1336,14 @@ void
|
|||
wasm_runtime_set_linux_perf(bool flag);
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,40 @@
|
|||
#include "aot_intrinsic.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) \
|
||||
do { \
|
||||
if (!(res = \
|
||||
|
@ -111,6 +145,418 @@ ffs(int n)
|
|||
static LLVMValueRef
|
||||
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
|
||||
aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
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 =
|
||||
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;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_succ, block_maddr_phi = NULL;
|
||||
LLVMBasicBlockRef check_succ;
|
||||
AOTValue *aot_value_top;
|
||||
uint32 local_idx_of_aot_value = 0;
|
||||
uint64 const_value;
|
||||
|
@ -136,6 +582,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
#else
|
||||
bool is_memory64 = IS_MEMORY64;
|
||||
#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;
|
||||
|
||||
|
@ -262,6 +712,13 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
*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 (!(offset_const = LLVMBuildZExt(comp_ctx->builder, offset_const,
|
||||
I64_TYPE, "offset_i64"))
|
||||
|
@ -275,7 +732,9 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
/* offset1 = offset + addr; */
|
||||
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 */
|
||||
LLVMBasicBlockRef 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;
|
||||
}
|
||||
SET_BUILD_POS(check_integer_overflow_end);
|
||||
block_curr = check_integer_overflow_end;
|
||||
}
|
||||
|
||||
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
|
||||
LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem;
|
||||
LLVMValueRef is_in_shared_heap, shared_heap_check_bound = NULL;
|
||||
|
||||
/* Add basic blocks */
|
||||
ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap");
|
||||
ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem");
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (comp_ctx->enable_shared_heap
|
||||
|| comp_ctx->enable_shared_chain /* TODO: && mem_idx == 0 */) {
|
||||
ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
|
||||
|
||||
LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr);
|
||||
LLVMMoveBasicBlockAfter(app_addr_in_linear_mem,
|
||||
app_addr_in_shared_heap);
|
||||
LLVMMoveBasicBlockAfter(block_maddr_phi, app_addr_in_linear_mem);
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
|
||||
SET_BUILD_POS(block_maddr_phi);
|
||||
if (!(maddr_phi =
|
||||
LLVMBuildPhi(comp_ctx->builder,
|
||||
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");
|
||||
goto fail;
|
||||
}
|
||||
SET_BUILD_POS(block_curr);
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
|
||||
if (!is_target_64bit) {
|
||||
/* Check whether integer overflow occurs in addr + offset */
|
||||
LLVMBasicBlockRef check_integer_overflow_end;
|
||||
ADD_BASIC_BLOCK(check_integer_overflow_end,
|
||||
"check_integer_overflow_end");
|
||||
LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr);
|
||||
|
||||
BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true,
|
||||
cmp1, check_integer_overflow_end)) {
|
||||
goto fail;
|
||||
}
|
||||
SET_BUILD_POS(check_integer_overflow_end);
|
||||
}
|
||||
|
||||
shared_heap_check_bound =
|
||||
is_memory64 ? I64_CONST(UINT64_MAX - bytes + 1)
|
||||
: (comp_ctx->pointer_size == sizeof(uint64)
|
||||
? I64_CONST(UINT32_MAX - bytes + 1)
|
||||
: I32_CONST(UINT32_MAX - bytes + 1));
|
||||
CHECK_LLVM_CONST(shared_heap_check_bound);
|
||||
|
||||
/* Check whether the bytes to access are in shared heap */
|
||||
if (!comp_ctx->enable_bound_check) {
|
||||
/* Use IntUGT but not IntUGE to compare, since (1) in the ems
|
||||
memory allocator, the hmu node includes hmu header and hmu
|
||||
memory, only the latter is returned to the caller as the
|
||||
allocated memory, the hmu header isn't returned so the
|
||||
first byte of the shared heap won't be 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");
|
||||
if (!aot_check_shared_heap_memory_overflow(
|
||||
comp_ctx, func_ctx, block_curr, block_maddr_phi, maddr_phi,
|
||||
offset1, mem_base_addr, bytes, is_memory64, is_target_64bit,
|
||||
enable_segue)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap);
|
||||
|
||||
/* Get native address inside shared heap */
|
||||
if (!(maddr =
|
||||
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
||||
func_ctx->shared_heap_base_addr_adj,
|
||||
&offset1, 1, "maddr_shared_heap"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (enable_segue) {
|
||||
LLVMValueRef mem_base_addr_u64, maddr_u64, offset_to_mem_base;
|
||||
|
||||
if (!(maddr_u64 = LLVMBuildPtrToInt(comp_ctx->builder, maddr,
|
||||
I64_TYPE, "maddr_u64"))
|
||||
|| !(mem_base_addr_u64 =
|
||||
LLVMBuildPtrToInt(comp_ctx->builder, mem_base_addr,
|
||||
I64_TYPE, "mem_base_addr_u64"))) {
|
||||
aot_set_last_error("llvm build ptr to int failed");
|
||||
goto fail;
|
||||
}
|
||||
if (!(offset_to_mem_base =
|
||||
LLVMBuildSub(comp_ctx->builder, maddr_u64,
|
||||
mem_base_addr_u64, "offset_to_mem_base"))) {
|
||||
aot_set_last_error("llvm build sub failed");
|
||||
goto fail;
|
||||
}
|
||||
if (!(maddr = LLVMBuildIntToPtr(
|
||||
comp_ctx->builder, offset_to_mem_base, INT8_PTR_TYPE_GS,
|
||||
"maddr_shared_heap_segue"))) {
|
||||
aot_set_last_error("llvm build int to ptr failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1);
|
||||
|
||||
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
|
||||
aot_set_last_error("llvm build br failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem);
|
||||
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (comp_ctx->enable_bound_check
|
||||
&& !(is_local_of_aot_value
|
||||
|
@ -449,21 +805,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (is_target_64bit) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
|
||||
|
||||
/* Add basic blocks */
|
||||
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);
|
||||
LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
|
||||
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
|
||||
aot_set_last_error("llvm build br failed");
|
||||
goto fail;
|
||||
}
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
|
||||
SET_BUILD_POS(block_maddr_phi);
|
||||
return maddr_phi;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return maddr;
|
||||
fail:
|
||||
return NULL;
|
||||
|
@ -544,15 +889,6 @@ fail:
|
|||
LLVMSetAlignment(value, known_align); \
|
||||
} 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() \
|
||||
do { \
|
||||
LLVMValueRef res; \
|
||||
|
@ -1150,16 +1486,23 @@ LLVMValueRef
|
|||
check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef offset, LLVMValueRef bytes)
|
||||
{
|
||||
LLVMValueRef maddr, max_addr, cmp;
|
||||
LLVMValueRef mem_base_addr, maddr_phi = NULL;
|
||||
LLVMValueRef maddr, max_addr, cmp, cmp1;
|
||||
LLVMValueRef mem_base_addr;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_succ, block_maddr_phi = NULL;
|
||||
LLVMBasicBlockRef check_succ;
|
||||
LLVMValueRef mem_size;
|
||||
bool is_target_64bit;
|
||||
#if WASM_ENABLE_MEMORY64 == 0
|
||||
bool is_memory64 = false;
|
||||
#else
|
||||
bool is_memory64 = IS_MEMORY64;
|
||||
#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 */
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
|
@ -1221,111 +1564,71 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
LLVMMoveBasicBlockAfter(check_succ, block_curr);
|
||||
|
||||
offset =
|
||||
LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
|
||||
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
|
||||
if (!offset || !bytes) {
|
||||
aot_set_last_error("llvm build zext failed.");
|
||||
goto fail;
|
||||
/* Same logic with aot_check_memory_overflow, offset and bytes are 32/64
|
||||
* bits on 32/64 bits platform */
|
||||
if (is_target_64bit) {
|
||||
offset =
|
||||
LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
|
||||
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
|
||||
if (!offset || !bytes) {
|
||||
aot_set_last_error("llvm build zext failed.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
|
||||
|
||||
if (is_memory64 && comp_ctx->enable_bound_check) {
|
||||
/* Check whether integer overflow occurs in offset + addr */
|
||||
/* Check overflow when it's memory64 or it's on 32 bits platform */
|
||||
if (is_memory64 || !is_target_64bit) {
|
||||
/* Check whether integer overflow occurs in offset + bytes */
|
||||
LLVMBasicBlockRef check_integer_overflow_end;
|
||||
ADD_BASIC_BLOCK(check_integer_overflow_end,
|
||||
"check_integer_overflow_end");
|
||||
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(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,
|
||||
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp,
|
||||
check_integer_overflow_end)) {
|
||||
goto fail;
|
||||
}
|
||||
SET_BUILD_POS(check_integer_overflow_end);
|
||||
block_curr = check_integer_overflow_end;
|
||||
}
|
||||
|
||||
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
|
||||
LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem;
|
||||
LLVMValueRef shared_heap_start_off, shared_heap_check_bound;
|
||||
LLVMValueRef max_offset, cmp1, cmp2, is_in_shared_heap;
|
||||
|
||||
/* Add basic blocks */
|
||||
ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap");
|
||||
ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem");
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (comp_ctx->enable_shared_heap
|
||||
|| comp_ctx->enable_shared_chain /* TODO: && mem_idx == 0 */) {
|
||||
ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
|
||||
|
||||
LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr);
|
||||
LLVMMoveBasicBlockAfter(app_addr_in_linear_mem,
|
||||
app_addr_in_shared_heap);
|
||||
LLVMMoveBasicBlockAfter(block_maddr_phi, check_succ);
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
|
||||
SET_BUILD_POS(block_maddr_phi);
|
||||
if (!(maddr_phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE,
|
||||
"maddr_phi"))) {
|
||||
aot_set_last_error("llvm build phi failed");
|
||||
goto fail;
|
||||
}
|
||||
SET_BUILD_POS(block_curr);
|
||||
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
|
||||
|
||||
shared_heap_start_off = func_ctx->shared_heap_start_off;
|
||||
if (comp_ctx->pointer_size == sizeof(uint32)) {
|
||||
if (!(shared_heap_start_off =
|
||||
LLVMBuildZExt(comp_ctx->builder, shared_heap_start_off,
|
||||
I64_TYPE, "shared_heap_start_off_u64"))) {
|
||||
aot_set_last_error("llvm build zext failed");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
shared_heap_check_bound =
|
||||
is_memory64 ? I64_CONST(UINT64_MAX) : I64_CONST(UINT32_MAX);
|
||||
CHECK_LLVM_CONST(shared_heap_check_bound);
|
||||
|
||||
/* Check whether the bytes to access are in shared heap */
|
||||
if (!comp_ctx->enable_bound_check) {
|
||||
/* Use IntUGT but not IntUGE to compare, same as the check
|
||||
in aot_check_memory_overflow */
|
||||
BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off,
|
||||
is_in_shared_heap, "is_in_shared_heap");
|
||||
}
|
||||
else {
|
||||
BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off,
|
||||
cmp1, "cmp1");
|
||||
BUILD_OP(Add, max_addr, I64_NEG_ONE, max_offset, "max_offset");
|
||||
BUILD_ICMP(LLVMIntULE, max_offset, shared_heap_check_bound, cmp2,
|
||||
"cmp2");
|
||||
BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap");
|
||||
}
|
||||
|
||||
if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap,
|
||||
app_addr_in_shared_heap, app_addr_in_linear_mem)) {
|
||||
aot_set_last_error("llvm build cond br failed");
|
||||
if (!aot_check_bulk_memory_shared_heap_memory_overflow(
|
||||
comp_ctx, func_ctx, block_curr, block_maddr_phi, check_succ,
|
||||
maddr_phi, offset, max_addr, bytes, is_memory64,
|
||||
is_target_64bit)) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* mem_size is always 64-bit, extend max_addr on 32 bits platform */
|
||||
if (!is_target_64bit
|
||||
&& !(max_addr = LLVMBuildZExt(comp_ctx->builder, max_addr, I64_TYPE,
|
||||
"extend_max_addr"))) {
|
||||
aot_set_last_error("llvm build zext failed.");
|
||||
goto fail;
|
||||
}
|
||||
BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr");
|
||||
|
||||
if (!aot_emit_exception(comp_ctx, func_ctx,
|
||||
|
@ -1341,7 +1644,9 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
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);
|
||||
LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
|
||||
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;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return maddr;
|
||||
fail:
|
||||
return NULL;
|
||||
|
|
|
@ -1517,73 +1517,154 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
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
|
||||
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;
|
||||
|
||||
/* Load aot_inst->e->shared_heap_base_addr_adj */
|
||||
offset_u32 = get_module_inst_extra_offset(comp_ctx);
|
||||
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (comp_ctx->is_jit_mode)
|
||||
offset_u32 +=
|
||||
offsetof(WASMModuleInstanceExtra, shared_heap_base_addr_adj);
|
||||
else
|
||||
#if WASM_ENABLE_MEMORY64 == 0
|
||||
bool is_memory64 = false;
|
||||
#else
|
||||
bool is_memory64 = IS_MEMORY64;
|
||||
#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);
|
||||
CHECK_LLVM_CONST(offset);
|
||||
|
||||
if (!(base_addr_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
||||
func_ctx->aot_inst, &offset, 1,
|
||||
"shared_heap_base_addr_adj_p"))) {
|
||||
if (!(shared_heap_head_p = LLVMBuildInBoundsGEP2(
|
||||
comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1,
|
||||
"shared_heap_head_p"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed");
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
if (!(func_ctx->shared_heap_base_addr_adj =
|
||||
LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, base_addr_p,
|
||||
"shared_heap_base_addr_adj"))) {
|
||||
if (!(shared_heap_head =
|
||||
LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE,
|
||||
shared_heap_head_p, "shared_heap_head"))) {
|
||||
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 */
|
||||
offset_u32 = get_module_inst_extra_offset(comp_ctx);
|
||||
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
|
||||
if (comp_ctx->is_jit_mode)
|
||||
offset_u32 += offsetof(WASMModuleInstanceExtra, shared_heap_start_off);
|
||||
else
|
||||
#endif
|
||||
offset_u32 += offsetof(AOTModuleInstanceExtra, shared_heap_start_off);
|
||||
if (is_memory64) {
|
||||
offset_u32 = offsetof(WASMSharedHeap, start_off_mem64);
|
||||
}
|
||||
else {
|
||||
offset_u32 = offsetof(WASMSharedHeap, start_off_mem32);
|
||||
}
|
||||
offset = I32_CONST(offset_u32);
|
||||
CHECK_LLVM_CONST(offset);
|
||||
|
||||
if (!(start_off_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
||||
func_ctx->aot_inst, &offset, 1,
|
||||
"shared_heap_start_off_p"))) {
|
||||
if (!(field_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
|
||||
shared_heap_head, &offset, 1,
|
||||
"head_start_off_p"))) {
|
||||
aot_set_last_error("llvm build inbounds gep failed");
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
if (!(func_ctx->shared_heap_start_off = LLVMBuildLoad2(
|
||||
comp_ctx->builder,
|
||||
comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE,
|
||||
start_off_p, "shared_heap_start_off"))) {
|
||||
|
||||
/* Select a valid shared heap head ptr or safe alloca ptr stores
|
||||
* shared_heap_start_off(UINT32_MAX/UINT64_MAX) */
|
||||
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");
|
||||
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,
|
||||
func_ctx->shared_heap_base_addr_adj,
|
||||
"has_shared_heap"))) {
|
||||
aot_set_last_error("llvm build is not null failed");
|
||||
return false;
|
||||
/* if there is attached shared heap(s), the value will be valid start_off-1,
|
||||
* otherwise it will be UINT32_MAX/UINT64_MAX, so during the bounds checks,
|
||||
* when has attached shared heap:
|
||||
* offset > start_off - 1 => offset >= start_off
|
||||
* 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;
|
||||
fail:
|
||||
return false;
|
||||
#else /* else of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
return true;
|
||||
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
}
|
||||
|
||||
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 */
|
||||
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)) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -2703,6 +2784,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
|
|||
if (option->enable_shared_heap)
|
||||
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->size_level = option->size_level;
|
||||
|
||||
|
|
|
@ -254,8 +254,12 @@ typedef struct AOTFuncContext {
|
|||
bool mem_space_unchanged;
|
||||
AOTCheckedAddrList checked_addr_list;
|
||||
|
||||
/* The last accessed shared heap info */
|
||||
LLVMValueRef shared_heap_base_addr_adj;
|
||||
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 func_return_block;
|
||||
|
@ -486,6 +490,7 @@ typedef struct AOTCompContext {
|
|||
bool enable_gc;
|
||||
|
||||
bool enable_shared_heap;
|
||||
bool enable_shared_chain;
|
||||
|
||||
uint32 opt_level;
|
||||
uint32 size_level;
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef struct AOTCompOption {
|
|||
bool enable_stack_estimation;
|
||||
bool quick_invoke_c_api_import;
|
||||
bool enable_shared_heap;
|
||||
bool enable_shared_chain;
|
||||
char *use_prof_file;
|
||||
uint32_t opt_level;
|
||||
uint32_t size_level;
|
||||
|
|
|
@ -349,6 +349,7 @@ typedef enum {
|
|||
|
||||
typedef struct SharedHeapInitArgs {
|
||||
uint32_t size;
|
||||
void *pre_allocated_addr;
|
||||
} SharedHeapInitArgs;
|
||||
|
||||
/**
|
||||
|
@ -2314,7 +2315,37 @@ WASM_RUNTIME_API_EXTERN wasm_shared_heap_t
|
|||
wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);
|
||||
|
||||
/**
|
||||
* Attach a shared heap to a module instance
|
||||
* This function links two shared heap(lists), `head` and `body` in to a single
|
||||
* shared heap list, where `head` becomes the new shared heap list head. The
|
||||
* shared heap list remains one continuous shared heap in wasm app's point of
|
||||
* view. At most one shared heap in shared heap list can be dynamically
|
||||
* allocated, the rest have to be the pre-allocated shared heap. *
|
||||
*
|
||||
* @param head The head of the shared heap chain.
|
||||
* @param body The body of the shared heap chain to be appended.
|
||||
* @return The new head of the shared heap chain. NULL if failed.
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN wasm_shared_heap_t
|
||||
wasm_runtime_chain_shared_heaps(wasm_shared_heap_t head,
|
||||
wasm_shared_heap_t body);
|
||||
|
||||
/**
|
||||
* This function unchains the shared heaps from the given head. If
|
||||
* `entire_chain` is true, it will unchain the entire chain of shared heaps.
|
||||
* Otherwise, it will unchain only the first shared heap in the chain.
|
||||
*
|
||||
* @param head The head of the shared heap chain.
|
||||
* @param entire_chain A boolean flag indicating whether to unchain the entire
|
||||
* chain.
|
||||
* @return The new head of the shared heap chain. Or the last shared heap in the
|
||||
* chain if `entire_chain` is true.
|
||||
*/
|
||||
wasm_shared_heap_t
|
||||
wasm_runtime_unchain_shared_heaps(wasm_shared_heap_t head, bool entire_chain);
|
||||
|
||||
/**
|
||||
* Attach a shared heap, it can be the head of shared heap chain, in that case,
|
||||
* attach the shared heap chain, to a module instance
|
||||
*
|
||||
* @param module_inst the module instance
|
||||
* @param shared_heap the shared heap
|
||||
|
@ -2333,7 +2364,8 @@ WASM_RUNTIME_API_EXTERN void
|
|||
wasm_runtime_detach_shared_heap(wasm_module_inst_t module_inst);
|
||||
|
||||
/**
|
||||
* Allocate memory from a shared heap
|
||||
* Allocate memory from a shared heap, or the non-preallocated shared heap from
|
||||
* the shared heap chain
|
||||
*
|
||||
* @param module_inst the module instance
|
||||
* @param size required memory size
|
||||
|
@ -2350,7 +2382,8 @@ wasm_runtime_shared_heap_malloc(wasm_module_inst_t module_inst, uint64_t size,
|
|||
void **p_native_addr);
|
||||
|
||||
/**
|
||||
* Free the memory allocated from shared heap
|
||||
* Free the memory allocated from shared heap, or the non-preallocated shared
|
||||
* heap from the shared heap chain
|
||||
*
|
||||
* @param module_inst the module instance
|
||||
* @param ptr the offset in wasm app
|
||||
|
|
|
@ -46,28 +46,6 @@ typedef float64 CellType_F64;
|
|||
#define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory)
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
#if WASM_ENABLE_MULTI_MEMORY != 0
|
||||
/* Only enable shared heap for the default memory */
|
||||
#define is_default_memory (memidx == 0)
|
||||
#else
|
||||
#define is_default_memory true
|
||||
#endif
|
||||
#define app_addr_in_shared_heap(app_addr, bytes) \
|
||||
(shared_heap && is_default_memory && (app_addr) >= shared_heap_start_off \
|
||||
&& (app_addr) <= shared_heap_end_off - bytes + 1)
|
||||
|
||||
#define shared_heap_addr_app_to_native(app_addr, native_addr) \
|
||||
native_addr = shared_heap_base_addr + ((app_addr)-shared_heap_start_off)
|
||||
|
||||
#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \
|
||||
if (app_addr_in_shared_heap(app_addr, bytes)) \
|
||||
shared_heap_addr_app_to_native(app_addr, native_addr); \
|
||||
else
|
||||
#else
|
||||
#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr)
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MEMORY64 == 0
|
||||
|
||||
#if (!defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|
@ -1670,22 +1648,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
if (memory)
|
||||
is_memory64 = memory->is_memory64;
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
WASMSharedHeap *shared_heap = module->e->shared_heap;
|
||||
uint8 *shared_heap_base_addr = shared_heap ? shared_heap->base_addr : NULL;
|
||||
#if WASM_ENABLE_MEMORY64 != 0
|
||||
uint64 shared_heap_start_off =
|
||||
shared_heap ? (is_memory64 ? shared_heap->start_off_mem64
|
||||
: shared_heap->start_off_mem32)
|
||||
: 0;
|
||||
uint64 shared_heap_end_off =
|
||||
shared_heap ? (is_memory64 ? UINT64_MAX : UINT32_MAX) : 0;
|
||||
#else
|
||||
uint64 shared_heap_start_off =
|
||||
shared_heap ? shared_heap->start_off_mem32 : 0;
|
||||
uint64 shared_heap_end_off = shared_heap ? UINT32_MAX : 0;
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
#if WASM_ENABLE_MULTI_MEMORY != 0
|
||||
uint32 memidx = 0;
|
||||
uint32 memidx_cached = (uint32)-1;
|
||||
|
|
|
@ -41,22 +41,6 @@ typedef float64 CellType_F64;
|
|||
#define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory)
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
#define app_addr_in_shared_heap(app_addr, bytes) \
|
||||
(shared_heap && (app_addr) >= shared_heap_start_off \
|
||||
&& (app_addr) <= shared_heap_end_off - bytes + 1)
|
||||
|
||||
#define shared_heap_addr_app_to_native(app_addr, native_addr) \
|
||||
native_addr = shared_heap_base_addr + ((app_addr)-shared_heap_start_off)
|
||||
|
||||
#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr) \
|
||||
if (app_addr_in_shared_heap(app_addr, bytes)) \
|
||||
shared_heap_addr_app_to_native(app_addr, native_addr); \
|
||||
else
|
||||
#else
|
||||
#define CHECK_SHARED_HEAP_OVERFLOW(app_addr, bytes, native_addr)
|
||||
#endif
|
||||
|
||||
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||
#define CHECK_MEMORY_OVERFLOW(bytes) \
|
||||
|
@ -1590,21 +1574,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
bool is_return_call = false;
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
WASMSharedHeap *shared_heap = module->e ? module->e->shared_heap : NULL;
|
||||
uint8 *shared_heap_base_addr = shared_heap ? shared_heap->base_addr : NULL;
|
||||
/*
|
||||
#if WASM_ENABLE_MEMORY64 != 0
|
||||
uint64 shared_heap_start_off =
|
||||
shared_heap ? (is_memory64 ? shared_heap->start_off_mem64
|
||||
: shared_heap->start_off_mem32)
|
||||
: 0;
|
||||
uint64 shared_heap_end_off =
|
||||
shared_heap ? (is_memory64 ? UINT64_MAX : UINT32_MAX) : 0;
|
||||
#else
|
||||
*/ /* TODO: uncomment the code when memory64 is enabled for fast-interp */
|
||||
uint64 shared_heap_start_off =
|
||||
shared_heap ? shared_heap->start_off_mem32 : 0;
|
||||
uint64 shared_heap_end_off = shared_heap ? UINT32_MAX : 0;
|
||||
/* TODO: currently flowing two variables are only dummy for shared heap
|
||||
* boundary check, need to be updated when multi-memory or memory64
|
||||
* proposals are to be implemented */
|
||||
bool is_memory64 = false;
|
||||
uint32 memidx = 0;
|
||||
(void)is_memory64;
|
||||
(void)memidx;
|
||||
/* #endif */
|
||||
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
|
||||
|
||||
|
|
|
@ -2818,6 +2818,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
|||
#else
|
||||
module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX;
|
||||
#endif
|
||||
module_inst->e->shared_heap = NULL;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_GC != 0
|
||||
|
|
|
@ -93,12 +93,21 @@ typedef union {
|
|||
} MemBound;
|
||||
|
||||
typedef struct WASMSharedHeap {
|
||||
struct WASMSharedHeap *next;
|
||||
void *heap_handle;
|
||||
uint8 *base_addr;
|
||||
/* The global shared heap list maintained in runtime, used for runtime
|
||||
* destroy */
|
||||
DefPointer(struct WASMSharedHeap *, next);
|
||||
/* The logical shared heap chain the shared heap in */
|
||||
DefPointer(struct WASMSharedHeap *, chain_next);
|
||||
/* Will be null if shared heap is created from pre allocated memory chunk
|
||||
* and don't need to dynamic malloc and free */
|
||||
DefPointer(void *, heap_handle);
|
||||
DefPointer(uint8 *, base_addr);
|
||||
uint64 size;
|
||||
uint64 start_off_mem64;
|
||||
uint64 start_off_mem32;
|
||||
/* The number of wasm apps it attached to, for a shared heap chain, only the
|
||||
* list head need to maintain the valid attached_count */
|
||||
uint8 attached_count;
|
||||
} WASMSharedHeap;
|
||||
|
||||
struct WASMMemoryInstance {
|
||||
|
@ -364,8 +373,6 @@ typedef struct WASMModuleInstanceExtra {
|
|||
#endif
|
||||
|
||||
#if WASM_ENABLE_SHARED_HEAP != 0
|
||||
WASMSharedHeap *shared_heap;
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
/*
|
||||
* Adjusted shared heap based addr to simple the calculation
|
||||
* in the aot code. The value is:
|
||||
|
@ -373,7 +380,8 @@ typedef struct WASMModuleInstanceExtra {
|
|||
*/
|
||||
uint8 *shared_heap_base_addr_adj;
|
||||
MemBound shared_heap_start_off;
|
||||
#endif
|
||||
MemBound shared_heap_end_off;
|
||||
WASMSharedHeap *shared_heap;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0 \
|
||||
|
|
|
@ -83,17 +83,21 @@ target_link_libraries(vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthre
|
|||
include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
|
||||
|
||||
add_executable (shared_heap_chain_test src/shared_heap_chain.c ${UNCOMMON_SHARED_SOURCE})
|
||||
add_executable (shared_heap_test src/main.c ${UNCOMMON_SHARED_SOURCE})
|
||||
|
||||
check_pie_supported()
|
||||
set_target_properties (shared_heap_test PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries (shared_heap_test vmlib -lm -ldl -lpthread)
|
||||
set (LIBS vmlib -lm -ldl -lpthread)
|
||||
else ()
|
||||
target_link_libraries (shared_heap_test vmlib -lm -ldl -lpthread -lrt)
|
||||
set (LIBS vmlib -lm -ldl -lpthread -lrt)
|
||||
endif ()
|
||||
|
||||
target_link_libraries (shared_heap_chain_test ${LIBS})
|
||||
target_link_libraries (shared_heap_test ${LIBS})
|
||||
|
||||
add_subdirectory(wasm-apps)
|
||||
|
||||
if (WAMR_BUILD_AOT EQUAL 1)
|
||||
|
@ -107,21 +111,31 @@ if (WAMR_BUILD_AOT EQUAL 1)
|
|||
)
|
||||
if (WAMR_COMPILER)
|
||||
message (CHECK_PASS "found")
|
||||
else()
|
||||
else ()
|
||||
message (CHECK_FAIL "not found")
|
||||
endif()
|
||||
endif ()
|
||||
if (NOT EXISTS ${WAMR_COMPILER})
|
||||
message (FATAL_ERROR "Please build wamrc under ${WAMR_ROOT_DIR}/wamr-compiler")
|
||||
else()
|
||||
else ()
|
||||
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(
|
||||
wasm_to_aot
|
||||
ALL
|
||||
DEPENDS wasm-apps/test1.wasm wasm-apps/test2.wasm ${WAMR_COMPILER}
|
||||
COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test1.aot wasm-apps/test1.wasm
|
||||
COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test2.aot wasm-apps/test2.wasm
|
||||
COMMAND ${WAMR_COMPILER} ${WAMR_COMPILER_FLAGS} -o wasm-apps/test1.aot wasm-apps/test1.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}
|
||||
)
|
||||
endif()
|
||||
|
|
50
samples/shared-heap/README.md
Normal file
50
samples/shared-heap/README.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Shared heap Sample introduction
|
||||
|
||||
This is a sample to show how to use the shared heap feature in WAMR. The shared heap feature allows multiple WASM instances to share the same memory space. This feature is useful when you want to run multiple WASM instances in the same process and share data between them. The sandbox nature of WASM is still maintained in the shared heap by WAMR. But the data management and correct data synchronization in shared heap is relied on the user's implementation.
|
||||
|
||||
> Note: The shared heap feature is experimental feature, it should be used with caution. It's optional and only available when building WAMR with the CMake cache variable `WAMR_BUILD_SHARED_HEAP` set to 1.
|
||||
|
||||
## Build and run the sample
|
||||
|
||||
To build the shared heap used in multi thread sample and the shared heap chain sample with following commands:
|
||||
|
||||
```bash
|
||||
cmake -S . -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
For the shared heap sample, it demonstrates how to create a shared heap and use it shares data between two WASM instances, which would satisfy most of the use cases. Use the following commands to run the sample:
|
||||
|
||||
```bash
|
||||
cd build
|
||||
./shared_heap_test
|
||||
```
|
||||
|
||||
For the shared heap chain sample. It chains a pre-allocated heap and a normal shared heap to one chain(linked list) as a whole and attaches/detaches all together, and pass the WASM address directly between two WASM instances. Use the following commands to run the sample:
|
||||
|
||||
```bash
|
||||
cd build
|
||||
./shared_heap_chain_test
|
||||
```
|
||||
|
||||
## How to use shared heap
|
||||
|
||||
The shared heap is an advanced feature in WAMR that gives the user flexibility to share data between multiple WASM instances(it will be the same address mapping for different WASM instance) or between WebAssembly and the host without incurring any copy overhead. The shared heap can be regarded as an extension of the WebAssembly linear memory. But it also heavily relies on the user's implementation to manage the shared data correctly. The following are some takeaway points to help the user use the shared heap correctly.
|
||||
|
||||
### Create and manage shared heap
|
||||
|
||||
You can create a shared heap by calling the `wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args)` API. And based on the `init_args`, you can create a shared heap in two ways:
|
||||
|
||||
1. WAMR managed shared heap: when only `init_args.size` is given and `init_args.pre_allocated_addr` stays as NULL, WAMR will allocate a shared heap(not from the linear memory) with the given size. The shared heap will be managed by WAMR, the wasm app or host(WAMR users) can dynamically manage memory from it by calling `wasm_runtime_shared_heap_malloc()` and `wasm_runtime_shared_heap_free()` on demand. Only the memory allocated from the shared heap is valid and can be shared, not the unallocated part of shared heap memory. And it will be automatically freed when runtime is destroyed(when `wasm_runtime_destroy()` is called).
|
||||
|
||||
2. Preallocated shared heap: the user can also use a pre-allocated memory(it can be allocated from the system heap, or is a static global buffer, the correctness of its accessibility and size needs to be ensured by the user) as a shared heap by giving `init_args.pre_allocated_addr` and `init_args.size`. This kind of shared heap serves as an area for data exchange, primarily between the host and WebAssembly. Any data within this area can be directly accessed by both sides (assuming the layout of the data structure is known). For instance, the host can store large structured variables in this space, allowing the WebAssembly application to operate on them without the need for copying. And the pre-allocated memory will relies on user to manage its life cycle.
|
||||
|
||||
After creation, the shared heap can be attached to a WASM instance(an additional segment appended to the end of the linear memory) by calling `wasm_runtime_attach_shared_heap(wasm_module_inst_t module_inst, wasm_shared_heap_t shared_heap)`. And it can be detached by calling `wasm_runtime_detach_shared_heap(wasm_module_inst_t module_inst)`. So that the data sharing can only happen between the WASM instances that have the same shared heap attached, complete by user's choice.
|
||||
|
||||
#### Shared heap chain
|
||||
|
||||
Sometimes you may want to use multiple shared heaps to attach together as a chain(linked list) and to share data more flexibly. You can call `wasm_runtime_chain_shared_heaps(wasm_shared_heap_t head, wasm_shared_heap_t body)` to chain two shared heaps together. The shared heap list remains one continuous shared heap in wasm app's point of view. To create a shared heap chain, the shared heaps can't be currently attached to any WASM instance.
|
||||
|
||||
> PS: At most one shared heap in shared heap list can be WAMR managed shared heap, the rest have to be the pre-allocated shared heap.
|
||||
|
||||

|
BIN
samples/shared-heap/images/shared_heap_chain.png
Normal file
BIN
samples/shared-heap/images/shared_heap_chain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
|
@ -55,7 +55,7 @@ thread1_callback(void *arg)
|
|||
i + 1);
|
||||
|
||||
printf("wasm app1 send buf: %s\n\n", buf);
|
||||
if (!bh_post_msg(queue, 1, buf, 1024 * i)) {
|
||||
if (!bh_post_msg(queue, 1, buf, 1024 * (i + 1))) {
|
||||
printf("Failed to post message to queue\n");
|
||||
wasm_runtime_shared_heap_free(module_inst, offset);
|
||||
break;
|
||||
|
@ -84,7 +84,7 @@ thread1_callback(void *arg)
|
|||
buf = wasm_runtime_addr_app_to_native(module_inst, argv[0]);
|
||||
|
||||
printf("wasm app1 send buf: %s\n\n", buf);
|
||||
if (!bh_post_msg(queue, 1, buf, 1024 * i)) {
|
||||
if (!bh_post_msg(queue, 1, buf, 1024 * (i + 1))) {
|
||||
printf("Failed to post message to queue\n");
|
||||
wasm_runtime_shared_heap_free(module_inst, argv[0]);
|
||||
break;
|
||||
|
@ -251,7 +251,7 @@ main(int argc, char **argv)
|
|||
heap_init_args.size = 65536;
|
||||
shared_heap = wasm_runtime_create_shared_heap(&heap_init_args);
|
||||
if (!shared_heap) {
|
||||
printf("Create shared heap failed. error: %s\n", error_buf);
|
||||
printf("Create shared heap failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
/* create thread 1 */
|
||||
struct thread_arg targ1 = { 0 };
|
||||
thread_arg targ1 = { 0 };
|
||||
korp_tid tid1;
|
||||
targ1.queue = queue;
|
||||
targ1.module_inst = module_inst1;
|
||||
|
@ -279,7 +279,7 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
/* create thread 2 */
|
||||
struct thread_arg targ2 = { 0 };
|
||||
thread_arg targ2 = { 0 };
|
||||
korp_tid tid2;
|
||||
targ2.queue = queue;
|
||||
targ2.module_inst = module_inst2;
|
||||
|
|
321
samples/shared-heap/src/shared_heap_chain.c
Normal file
321
samples/shared-heap/src/shared_heap_chain.c
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_export.h"
|
||||
#include "bh_platform.h"
|
||||
#include "bh_read_file.h"
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
static char preallocated_buf[BUF_SIZE];
|
||||
|
||||
static bool
|
||||
produce_data(wasm_module_inst_t module_inst, wasm_exec_env_t exec_env,
|
||||
bh_queue *queue, wasm_function_inst_t func, uint32 *argv,
|
||||
uint32 buf_size, bool free_on_fail)
|
||||
{
|
||||
uint8 *buf;
|
||||
|
||||
wasm_runtime_call_wasm(exec_env, func, 2, argv);
|
||||
|
||||
if (wasm_runtime_get_exception(module_inst)) {
|
||||
printf("Failed to call function: %s\n",
|
||||
wasm_runtime_get_exception(module_inst));
|
||||
return false;
|
||||
}
|
||||
if (argv[0] == 0) {
|
||||
printf("Failed to allocate memory from shared heap\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = wasm_runtime_addr_app_to_native(module_inst, argv[0]);
|
||||
printf("wasm app1 send buf: %s\n\n", buf);
|
||||
|
||||
/* Passes wasm address directly between wasm apps since memory in shared
|
||||
* heap chain is viewed as single address space in wasm's perspective */
|
||||
buf = (uint8 *)(uintptr_t)argv[0];
|
||||
if (!bh_post_msg(queue, 1, buf, buf_size)) {
|
||||
printf("Failed to post message to queue\n");
|
||||
if (free_on_fail)
|
||||
wasm_runtime_shared_heap_free(module_inst, argv[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *
|
||||
wasm_producer(wasm_module_inst_t module_inst, bh_queue *queue)
|
||||
{
|
||||
wasm_exec_env_t exec_env;
|
||||
wasm_function_inst_t my_shared_heap_malloc_func, my_shared_heap_free_func,
|
||||
produce_str_func;
|
||||
uint32 i, argv[2];
|
||||
|
||||
/* lookup wasm functions */
|
||||
if (!(my_shared_heap_malloc_func = wasm_runtime_lookup_function(
|
||||
module_inst, "my_shared_heap_malloc"))
|
||||
|| !(my_shared_heap_free_func = wasm_runtime_lookup_function(
|
||||
module_inst, "my_shared_heap_free"))
|
||||
|| !(produce_str_func =
|
||||
wasm_runtime_lookup_function(module_inst, "produce_str"))) {
|
||||
printf("Failed to lookup function.\n");
|
||||
}
|
||||
|
||||
/* create exec env */
|
||||
if (!(exec_env = wasm_runtime_create_exec_env(module_inst, 32768))) {
|
||||
printf("Failed to create exec env.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allocate memory by calling my_shared_heap_malloc function and send it
|
||||
to wasm app2 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
argv[0] = 1024 * (i + 1);
|
||||
argv[1] = i + 1;
|
||||
if (!produce_data(module_inst, exec_env, queue,
|
||||
my_shared_heap_malloc_func, argv, 1024 * (i + 1),
|
||||
true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* use pre-allocated shared heap memory by calling produce_str function and
|
||||
send it to wasm app2, the pre-allocated shared heap is the last one in
|
||||
chain, so its end address is calculated from UIN32_MAX */
|
||||
uint32 wasm_start_addr = UINT32_MAX - BUF_SIZE + 1;
|
||||
for (i = 8; i < 16; i++) {
|
||||
argv[0] = wasm_start_addr + 512 * (i - 8);
|
||||
argv[1] = i + 1;
|
||||
if (!produce_data(module_inst, exec_env, queue, produce_str_func, argv,
|
||||
512, false)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wasm_runtime_destroy_exec_env(exec_env);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wasm_consumer(wasm_module_inst_t module_inst, bh_queue *queue)
|
||||
{
|
||||
wasm_function_inst_t print_buf_func, consume_str_func;
|
||||
wasm_exec_env_t exec_env;
|
||||
uint32 argv[2], i;
|
||||
bh_message_t msg;
|
||||
char *buf;
|
||||
|
||||
/* lookup wasm function */
|
||||
if (!(print_buf_func =
|
||||
wasm_runtime_lookup_function(module_inst, "print_buf"))
|
||||
|| !(consume_str_func =
|
||||
wasm_runtime_lookup_function(module_inst, "consume_str"))) {
|
||||
printf("Failed to lookup function.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* create exec env */
|
||||
if (!(exec_env = wasm_runtime_create_exec_env(module_inst, 32768))) {
|
||||
printf("Failed to create exec env.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
msg = bh_get_msg(queue, BHT_WAIT_FOREVER);
|
||||
if (!msg)
|
||||
return;
|
||||
buf = bh_message_payload(msg);
|
||||
|
||||
/* call wasm function */
|
||||
argv[0] = (uint32)(uintptr_t)buf;
|
||||
if (i < 8)
|
||||
wasm_runtime_call_wasm(exec_env, print_buf_func, 1, argv);
|
||||
else
|
||||
wasm_runtime_call_wasm(exec_env, consume_str_func, 1, argv);
|
||||
|
||||
if (wasm_runtime_get_exception(module_inst)) {
|
||||
printf(
|
||||
"Failed to call 'print_buf' or 'consumer_str' function: %s\n",
|
||||
wasm_runtime_get_exception(module_inst));
|
||||
}
|
||||
|
||||
bh_free_msg(msg);
|
||||
}
|
||||
|
||||
wasm_runtime_destroy_exec_env(exec_env);
|
||||
}
|
||||
|
||||
static char global_heap_buf[512 * 1024];
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *wasm_file1 = NULL, *wasm_file2 = NULL;
|
||||
uint8 *wasm_file1_buf = NULL, *wasm_file2_buf = NULL;
|
||||
uint32 wasm_file1_size, wasm_file2_size;
|
||||
wasm_module_t wasm_module1 = NULL, wasm_module2 = NULL;
|
||||
wasm_module_inst_t module_inst1 = NULL;
|
||||
wasm_module_inst_t module_inst2 = NULL;
|
||||
wasm_shared_heap_t shared_heap = NULL, shared_heap2 = NULL,
|
||||
shared_heap_chain = NULL;
|
||||
bh_queue *queue = NULL;
|
||||
RuntimeInitArgs init_args;
|
||||
SharedHeapInitArgs heap_init_args;
|
||||
char error_buf[128] = { 0 };
|
||||
bool aot_mode = false;
|
||||
int ret = -1;
|
||||
|
||||
if (argc > 1 && !strcmp(argv[1], "--aot"))
|
||||
aot_mode = true;
|
||||
|
||||
if (!aot_mode)
|
||||
printf("Test shared heap in interpreter mode\n\n");
|
||||
else
|
||||
printf("Test shared heap in AOT mode\n\n");
|
||||
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
|
||||
|
||||
/* init wasm runtime */
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
printf("Init runtime environment failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create queue */
|
||||
if (!(queue = bh_queue_create())) {
|
||||
printf("Create queue failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* read wasm file */
|
||||
if (!aot_mode)
|
||||
wasm_file1 = "./wasm-apps/test1.wasm";
|
||||
else
|
||||
wasm_file1 = "./wasm-apps/test1_chain.aot";
|
||||
if (!(wasm_file1_buf =
|
||||
bh_read_file_to_buffer(wasm_file1, &wasm_file1_size))) {
|
||||
printf("Open wasm file %s failed.\n", wasm_file1);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load wasm file */
|
||||
wasm_module1 = wasm_runtime_load((uint8 *)wasm_file1_buf, wasm_file1_size,
|
||||
error_buf, sizeof(error_buf));
|
||||
if (!wasm_module1) {
|
||||
printf("Load wasm module failed. error: %s\n", error_buf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* instantiate module */
|
||||
module_inst1 = wasm_runtime_instantiate(wasm_module1, 65536, 0, error_buf,
|
||||
sizeof(error_buf));
|
||||
if (!module_inst1) {
|
||||
printf("Instantiate wasm module failed. error: %s\n", error_buf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* read wasm file */
|
||||
if (!aot_mode)
|
||||
wasm_file2 = "./wasm-apps/test2.wasm";
|
||||
else
|
||||
wasm_file2 = "./wasm-apps/test2_chain.aot";
|
||||
if (!(wasm_file2_buf =
|
||||
bh_read_file_to_buffer(wasm_file2, &wasm_file2_size))) {
|
||||
printf("Open wasm file %s failed.\n", wasm_file1);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load wasm file */
|
||||
wasm_module2 = wasm_runtime_load((uint8 *)wasm_file2_buf, wasm_file2_size,
|
||||
error_buf, sizeof(error_buf));
|
||||
if (!wasm_module2) {
|
||||
printf("Load wasm module failed. error: %s\n", error_buf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* instantiate module */
|
||||
module_inst2 = wasm_runtime_instantiate(wasm_module2, 65536, 0, error_buf,
|
||||
sizeof(error_buf));
|
||||
if (!module_inst2) {
|
||||
printf("Instantiate wasm module failed. error: %s\n", error_buf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* create shared heap */
|
||||
memset(&heap_init_args, 0, sizeof(heap_init_args));
|
||||
heap_init_args.size = 65536;
|
||||
shared_heap = wasm_runtime_create_shared_heap(&heap_init_args);
|
||||
if (!shared_heap) {
|
||||
printf("Create shared heap failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* create a preallocated shared heap */
|
||||
memset(&heap_init_args, 0, sizeof(heap_init_args));
|
||||
heap_init_args.pre_allocated_addr = preallocated_buf;
|
||||
heap_init_args.size = BUF_SIZE;
|
||||
shared_heap2 = wasm_runtime_create_shared_heap(&heap_init_args);
|
||||
if (!shared_heap2) {
|
||||
printf("Create preallocated shared heap failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
shared_heap_chain =
|
||||
wasm_runtime_chain_shared_heaps(shared_heap, shared_heap2);
|
||||
if (!shared_heap_chain) {
|
||||
printf("Create shared heap chain failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* attach module instance 1 to the shared heap */
|
||||
if (!wasm_runtime_attach_shared_heap(module_inst1, shared_heap_chain)) {
|
||||
printf("Attach shared heap failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* attach module instance 2 to the shared heap */
|
||||
if (!wasm_runtime_attach_shared_heap(module_inst2, shared_heap_chain)) {
|
||||
printf("Attach shared heap failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* wasm 1 produce shared data */
|
||||
wasm_producer(module_inst1, queue);
|
||||
|
||||
/* wasm 2 consume shared data */
|
||||
wasm_consumer(module_inst2, queue);
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
if (module_inst2)
|
||||
wasm_runtime_deinstantiate(module_inst2);
|
||||
|
||||
if (module_inst1)
|
||||
wasm_runtime_deinstantiate(module_inst1);
|
||||
|
||||
if (wasm_module2)
|
||||
wasm_runtime_unload(wasm_module2);
|
||||
|
||||
if (wasm_module1)
|
||||
wasm_runtime_unload(wasm_module1);
|
||||
|
||||
if (wasm_file2_buf)
|
||||
wasm_runtime_free(wasm_file2_buf);
|
||||
|
||||
if (wasm_file1_buf)
|
||||
wasm_runtime_free(wasm_file1_buf);
|
||||
|
||||
if (queue)
|
||||
bh_queue_destroy(queue);
|
||||
|
||||
wasm_runtime_destroy();
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -30,9 +30,7 @@ set (CMAKE_EXE_LINKER_FLAGS
|
|||
-Wl,--no-entry,--strip-all, \
|
||||
-Wl,--export=__heap_base,--export=__data_end \
|
||||
-Wl,--export=__wasm_call_ctors \
|
||||
-Wl,--export=my_shared_heap_malloc \
|
||||
-Wl,--export=my_shared_heap_free \
|
||||
-Wl,--export=print_buf \
|
||||
-Wl,--export-all \
|
||||
-Wl,--allow-undefined"
|
||||
)
|
||||
|
||||
|
|
|
@ -58,3 +58,14 @@ my_shared_heap_free(void *ptr)
|
|||
{
|
||||
shared_heap_free(ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
produce_str(char *addr, uint32_t index)
|
||||
{
|
||||
char c;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern void
|
||||
shared_heap_free(void *ptr);
|
||||
|
@ -16,3 +15,14 @@ print_buf(char *buf)
|
|||
printf("wasm app2's wasm func received buf: %s\n\n", buf);
|
||||
shared_heap_free(buf);
|
||||
}
|
||||
|
||||
void
|
||||
consume_str(char *buf)
|
||||
{
|
||||
/* Actually access it in wasm */
|
||||
char c = buf[0];
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,15 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
|||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
|
||||
if(WAMR_BUILD_TARGET STREQUAL "X86_32")
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
|
||||
# 1) Force -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()
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker
|
||||
|
@ -29,12 +36,21 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
|||
|
||||
# Fetch Google test
|
||||
include (FetchContent)
|
||||
FetchContent_Declare (
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24")
|
||||
FetchContent_Declare (
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable (googletest)
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP ON
|
||||
)
|
||||
else()
|
||||
FetchContent_Declare (
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||
)
|
||||
endif()
|
||||
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
SET(GOOGLETEST_INCLUDED 1)
|
||||
|
||||
|
|
|
@ -12,12 +12,20 @@ set(WAMR_BUILD_AOT 1)
|
|||
set(WAMR_BUILD_INTERP 1)
|
||||
set(WAMR_BUILD_FAST_INTERP 1)
|
||||
set(WAMR_BUILD_JIT 0)
|
||||
set(WAMR_BUILD_MEMORY64 1)
|
||||
if(WAMR_BUILD_TARGET STREQUAL "X86_32")
|
||||
set(WAMR_BUILD_MEMORY64 0)
|
||||
else()
|
||||
set(WAMR_BUILD_MEMORY64 1)
|
||||
endif()
|
||||
set(WAMR_BUILD_SHARED_HEAP 1)
|
||||
|
||||
# Compile wasm modules
|
||||
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
|
||||
include(../unit_common.cmake)
|
||||
|
||||
|
@ -56,4 +64,4 @@ add_executable(shared_heap_test ${unit_test_sources})
|
|||
|
||||
target_link_libraries(shared_heap_test ${LLVM_AVAILABLE_LIBS} gtest_main)
|
||||
|
||||
gtest_discover_tests(shared_heap_test)
|
||||
gtest_discover_tests(shared_heap_test)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,44 +29,81 @@ set(CMAKE_EXE_LINKER_FLAGS
|
|||
-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)
|
||||
target_link_libraries(test.wasm)
|
||||
|
||||
add_custom_command(TARGET test.wasm POST_BUILD
|
||||
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"
|
||||
)
|
||||
copy_wasm(test.wasm)
|
||||
compile_and_copy_aot_from(test.wasm)
|
||||
|
||||
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
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_BINARY_DIR}/test_addr_conv.wasm
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
COMMENT "Copy test_addr_conv.wasm to the same directory of google test"
|
||||
)
|
||||
# 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(TARGET test_addr_conv.wasm POST_BUILD
|
||||
COMMAND ${WAMRC_ROOT_DIR}/wamrc --opt-level=0 --enable-shared-heap --bounds-checks=1
|
||||
-o
|
||||
test_addr_conv.aot
|
||||
test_addr_conv.wasm
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_BINARY_DIR}/test_addr_conv.aot
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
COMMENT "Copy test_addr_conv.aot to the same directory of google test"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${BUILD_WASM}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${SOURCE_WASM}
|
||||
${BUILD_WASM}
|
||||
DEPENDS ${SOURCE_WASM}
|
||||
COMMENT "Copying bulk memory WASM to build directory"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${OUTPUT_AOT}
|
||||
COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_FLAGS}
|
||||
-o ${OUTPUT_AOT}
|
||||
${BUILD_WASM}
|
||||
COMMAND ${WAMRC_ROOT_DIR}/wamrc ${WAMR_COMPILER_CHAIN_FLAGS}
|
||||
-o ${OUTPUT_CHAIN_AOT}
|
||||
${BUILD_WASM}
|
||||
DEPENDS ${BUILD_WASM}
|
||||
COMMENT "Compiling bulk memory AOT from copied WASM"
|
||||
)
|
||||
|
||||
add_custom_target(compile_bulk_memory_aot ALL
|
||||
DEPENDS ${OUTPUT_AOT}
|
||||
)
|
||||
|
|
Binary file not shown.
|
@ -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))
|
||||
)
|
68
tests/unit/shared-heap/wasm-apps/memory64/CMakeLists.txt
Normal file
68
tests/unit/shared-heap/wasm-apps/memory64/CMakeLists.txt
Normal 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)
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#define NULL 0
|
||||
|
||||
extern void *
|
||||
shared_heap_malloc(int size);
|
||||
|
@ -32,3 +32,31 @@ test_malloc_fail()
|
|||
shared_heap_free(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
my_shared_heap_malloc(int size)
|
||||
{
|
||||
return shared_heap_malloc(size);
|
||||
}
|
||||
|
||||
void
|
||||
my_shared_heap_free(void *addr)
|
||||
{
|
||||
shared_heap_free(addr);
|
||||
}
|
||||
|
||||
char
|
||||
read_modify_write_8(char *addr, char value)
|
||||
{
|
||||
char original_value = *addr;
|
||||
*addr = value;
|
||||
return original_value;
|
||||
}
|
||||
|
||||
short
|
||||
read_modify_write_16(short *addr, short value)
|
||||
{
|
||||
short original_value = *addr;
|
||||
*addr = value;
|
||||
return original_value;
|
||||
}
|
||||
|
|
|
@ -30,3 +30,17 @@ test()
|
|||
shared_heap_free(ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
test_preallocated(void *app_addr)
|
||||
{
|
||||
int *ptr = (int *)app_addr;
|
||||
int *ptr2 = NULL;
|
||||
|
||||
ptr2 = test_addr_conv(ptr);
|
||||
if (ptr2 != ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -284,6 +284,7 @@ include (${IWASM_DIR}/interpreter/iwasm_interp.cmake)
|
|||
include (${IWASM_DIR}/aot/iwasm_aot.cmake)
|
||||
include (${IWASM_DIR}/compilation/iwasm_compl.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)
|
||||
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
|
||||
|
@ -366,6 +367,7 @@ add_library (vmlib
|
|||
${LIBC_WASI_SOURCE}
|
||||
${LIB_PTHREAD_SOURCE}
|
||||
${LIB_WASI_THREADS_SOURCE}
|
||||
${LIB_SHARED_HEAP_SOURCE}
|
||||
${IWASM_COMMON_SOURCE}
|
||||
${IWASM_INTERP_SOURCE}
|
||||
${IWASM_AOT_SOURCE}
|
||||
|
|
|
@ -213,7 +213,9 @@ print_help()
|
|||
printf(" --enable-linux-perf Enable linux perf support\n");
|
||||
#endif
|
||||
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(" --version Show version information\n");
|
||||
printf("Examples: wamrc -o test.aot test.wasm\n");
|
||||
|
@ -661,6 +663,9 @@ main(int argc, char *argv[])
|
|||
else if (!strcmp(argv[0], "--enable-shared-heap")) {
|
||||
option.enable_shared_heap = true;
|
||||
}
|
||||
else if (!strcmp(argv[0], "--enable-shared-chain")) {
|
||||
option.enable_shared_chain = true;
|
||||
}
|
||||
else if (!strcmp(argv[0], "--version")) {
|
||||
uint32 major, minor, patch;
|
||||
wasm_runtime_get_version(&major, &minor, &patch);
|
||||
|
@ -723,6 +728,13 @@ main(int argc, char *argv[])
|
|||
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) {
|
||||
wasm_file_name = argv[0];
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user