Merge pull request #3823 from bytecodealliance/dev/shared_heap

Implement the shared heap feature for interpreter, aot and llvm jit.
Add below runtime APIs:
```C
wasm_shared_heap_t
wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);

bool
wasm_runtime_attach_shared_heap(wasm_module_inst_t module_inst,
                                wasm_shared_heap_t shared_heap);

void
wasm_runtime_detach_shared_heap(wasm_module_inst_t module_inst);

uint64_t
wasm_runtime_shared_heap_malloc(wasm_module_inst_t module_inst, uint64_t size,
                                void **p_native_addr);

void
wasm_runtime_shared_heap_free(wasm_module_inst_t module_inst, uint64_t ptr);
```

And allow wasm app to call API shared_heap_malloc and shared_heap_free:
```C
void *shared_heap_malloc(uint32_t size);
void shared_heap_free(void *ptr);
```
This commit is contained in:
Wenyong Huang 2024-10-15 14:26:22 +08:00 committed by GitHub
commit b038f2721b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 2499 additions and 105 deletions

View File

@ -126,6 +126,16 @@ if [[ $? != 0 ]]; then
exit 1; exit 1;
fi fi
# build iwasm with multi-memory enabled
cd ${WAMR_DIR}/product-mini/platforms/linux
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_MULTI_MEMORY=1
make -j
if [[ $? != 0 ]]; then
echo "Failed to build iwasm with multi-memory enabled!"
exit 1;
fi
# build iwasm with hardware boundary check disabled # build iwasm with hardware boundary check disabled
cd ${WAMR_DIR}/product-mini/platforms/linux cd ${WAMR_DIR}/product-mini/platforms/linux
rm -rf build && mkdir build && cd build rm -rf build && mkdir build && cd build
@ -280,3 +290,23 @@ if [[ $? != 0 ]]; then
echo "Failed to build iwasm with linux perf support enabled!" echo "Failed to build iwasm with linux perf support enabled!"
exit 1; exit 1;
fi fi
# build iwasm with shared heap enabled
cd ${WAMR_DIR}/product-mini/platforms/linux
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_SHARED_HEAP=1
make -j
if [[ $? != 0 ]]; then
echo "Failed to build iwasm with shared heap enabled!"
exit 1;
fi
# build iwasm with dynamic aot debug enabled
cd ${WAMR_DIR}/product-mini/platforms/linux
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1
make -j
if [[ $? != 0 ]];
echo "Failed to build iwasm dynamic aot debug enabled!"
exit 1;
fi

View File

@ -578,6 +578,15 @@ jobs:
./run.sh test1 ./run.sh test1
./run.sh test2 ./run.sh test2
- name: Build Sample [shared-heap]
run: |
cd samples/shared-heap
mkdir build && cd build
cmake ..
cmake --build . --config Debug --parallel 4
./shared_heap_test
./shared_heap_test --aot
test: test:
needs: needs:
[ [

View File

@ -386,3 +386,12 @@ jobs:
./build.sh ./build.sh
./run.sh test1 ./run.sh test1
./run.sh test2 ./run.sh test2
- name: Build Sample [shared-heap]
run: |
cd samples/shared-heap
mkdir build && cd build
cmake ..
cmake --build . --config Debug --parallel 4
./shared_heap_test
./shared_heap_test --aot

View File

@ -593,6 +593,15 @@ jobs:
exit $? exit $?
working-directory: ./wamr-app-framework/samples/simple working-directory: ./wamr-app-framework/samples/simple
- name: Build Sample [shared-heap]
run: |
cd samples/shared-heap
mkdir build && cd build
cmake ..
cmake --build . --config Debug --parallel 4
./shared_heap_test
./shared_heap_test --aot
test: test:
needs: needs:
[ [

View File

@ -256,6 +256,11 @@ if (WAMR_BUILD_SHARED_MEMORY EQUAL 1)
else () else ()
add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0) add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0)
endif () endif ()
if (WAMR_BUILD_SHARED_HEAP EQUAL 1)
add_definitions (-DWASM_ENABLE_SHARED_HEAP=1)
message (" Shared heap enabled")
endif()
if (WAMR_BUILD_MEMORY64 EQUAL 1) if (WAMR_BUILD_MEMORY64 EQUAL 1)
# if native is 32-bit or cross-compiled to 32-bit # if native is 32-bit or cross-compiled to 32-bit
if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*") if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*")
@ -493,7 +498,7 @@ if (WAMR_BUILD_MODULE_INST_CONTEXT EQUAL 1)
message (" Module instance context enabled") message (" Module instance context enabled")
endif () endif ()
if (WAMR_BUILD_GC_HEAP_VERIFY EQUAL 1) if (WAMR_BUILD_GC_HEAP_VERIFY EQUAL 1)
add_definitions (-DWASM_ENABLE_GC_VERIFY=1) add_definitions (-DBH_ENABLE_GC_VERIFY=1)
message (" GC heap verification enabled") message (" GC heap verification enabled")
endif () endif ()
if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1) if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1)

View File

@ -119,6 +119,10 @@ if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1)
set (WAMR_BUILD_SHARED_MEMORY 1) set (WAMR_BUILD_SHARED_MEMORY 1)
endif () endif ()
if (WAMR_BUILD_SHARED_HEAP EQUAL 1)
include (${IWASM_DIR}/libraries/shared-heap/shared_heap.cmake)
endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_THREAD_MGR 1) set (WAMR_BUILD_THREAD_MGR 1)
include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake) include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
@ -193,6 +197,7 @@ set (source_all
${LIBC_EMCC_SOURCE} ${LIBC_EMCC_SOURCE}
${LIB_RATS_SOURCE} ${LIB_RATS_SOURCE}
${DEBUG_ENGINE_SOURCE} ${DEBUG_ENGINE_SOURCE}
${LIB_SHARED_HEAP_SOURCE}
) )
set (WAMR_RUNTIME_LIB_SOURCE ${source_all}) set (WAMR_RUNTIME_LIB_SOURCE ${source_all})

View File

@ -396,7 +396,9 @@
#define APP_HEAP_SIZE_DEFAULT (8 * 1024) #define APP_HEAP_SIZE_DEFAULT (8 * 1024)
#endif #endif
#define APP_HEAP_SIZE_MIN (256) #define APP_HEAP_SIZE_MIN (256)
#define APP_HEAP_SIZE_MAX (512 * 1024 * 1024) /* The ems memory allocator supports maximal heap size 1GB,
see ems_gc_internal.h */
#define APP_HEAP_SIZE_MAX (1024 * 1024 * 1024)
/* Default min/max gc heap size of each app */ /* Default min/max gc heap size of each app */
#ifndef GC_HEAP_SIZE_DEFAULT #ifndef GC_HEAP_SIZE_DEFAULT
@ -692,4 +694,8 @@
#endif #endif
#endif /* WASM_ENABLE_FUZZ_TEST != 0 */ #endif /* WASM_ENABLE_FUZZ_TEST != 0 */
#ifndef WASM_ENABLE_SHARED_HEAP
#define WASM_ENABLE_SHARED_HEAP 0
#endif
#endif /* end of _CONFIG_H_ */ #endif /* end of _CONFIG_H_ */

View File

@ -57,6 +57,9 @@ bh_static_assert(sizeof(AOTMemoryInstance) == 120);
bh_static_assert(offsetof(AOTTableInstance, elems) == 24); bh_static_assert(offsetof(AOTTableInstance, elems) == 24);
bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0); bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0);
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj)
== 8);
bh_static_assert(offsetof(AOTModuleInstanceExtra, shared_heap_start_off) == 16);
bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3); bh_static_assert(sizeof(CApiFuncImport) == sizeof(uintptr_t) * 3);
@ -1895,6 +1898,24 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
extra->stack_sizes = extra->stack_sizes =
aot_get_data_section_addr(module, AOT_STACK_SIZES_SECTION_NAME, NULL); aot_get_data_section_addr(module, AOT_STACK_SIZES_SECTION_NAME, NULL);
/*
* The AOT code checks whether the n bytes to access are in shared heap
* by checking whether the beginning address meets:
* addr >= start_off && addr <= end_off - n-bytes + 1
* where n is 1/2/4/8/16 and `end_off - n-bytes + 1` is constant, e.g.,
* UINT32_MAX, UINT32_MAX-1, UINT32_MAX-3 for n = 1, 2 or 4 in 32-bit
* target. To simplify the check, when shared heap is disabled, we set
* the start off to UINT64_MAX in 64-bit target and UINT32_MAX in 32-bit
* target, so in the checking, the above formula will be false, we don't
* need to check whether the shared heap is enabled or not in the AOT
* code.
*/
#if UINTPTR_MAX == UINT64_MAX
extra->shared_heap_start_off.u64 = UINT64_MAX;
#else
extra->shared_heap_start_off.u32[0] = UINT32_MAX;
#endif
#if WASM_ENABLE_PERF_PROFILING != 0 #if WASM_ENABLE_PERF_PROFILING != 0
total_size = sizeof(AOTFuncPerfProfInfo) total_size = sizeof(AOTFuncPerfProfInfo)
* ((uint64)module->import_func_count + module->func_count); * ((uint64)module->import_func_count + module->func_count);

View File

@ -111,6 +111,14 @@ typedef struct AOTFunctionInstance {
typedef struct AOTModuleInstanceExtra { typedef struct AOTModuleInstanceExtra {
DefPointer(const uint32 *, stack_sizes); DefPointer(const uint32 *, stack_sizes);
/*
* Adjusted shared heap based addr to simple the calculation
* in the aot code. The value is:
* shared_heap->base_addr - shared_heap->start_off
*/
DefPointer(uint8 *, shared_heap_base_addr_adj);
MemBound shared_heap_start_off;
WASMModuleInstanceExtraCommon common; WASMModuleInstanceExtraCommon common;
AOTFunctionInstance **functions; AOTFunctionInstance **functions;
uint32 function_count; uint32 function_count;
@ -119,6 +127,10 @@ typedef struct AOTModuleInstanceExtra {
bh_list *sub_module_inst_list; bh_list *sub_module_inst_list;
WASMModuleInstanceCommon **import_func_module_insts; WASMModuleInstanceCommon **import_func_module_insts;
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
WASMSharedHeap *shared_heap;
#endif
} AOTModuleInstanceExtra; } AOTModuleInstanceExtra;
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)

View File

@ -13,6 +13,10 @@
#include "../common/wasm_shared_memory.h" #include "../common/wasm_shared_memory.h"
#endif #endif
#if WASM_ENABLE_THREAD_MGR != 0
#include "../libraries/thread-mgr/thread_manager.h"
#endif
typedef enum Memory_Mode { typedef enum Memory_Mode {
MEMORY_MODE_UNKNOWN = 0, MEMORY_MODE_UNKNOWN = 0,
MEMORY_MODE_POOL, MEMORY_MODE_POOL,
@ -24,6 +28,11 @@ static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN;
static mem_allocator_t pool_allocator = NULL; static mem_allocator_t pool_allocator = NULL;
#if WASM_ENABLE_SHARED_HEAP != 0
static WASMSharedHeap *shared_heap_list = NULL;
static korp_mutex shared_heap_list_lock;
#endif
static enlarge_memory_error_callback_t enlarge_memory_error_cb; static enlarge_memory_error_callback_t enlarge_memory_error_cb;
static void *enlarge_memory_error_user_data; static void *enlarge_memory_error_user_data;
@ -132,16 +141,371 @@ is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
#endif #endif
} }
#if WASM_ENABLE_SHARED_HEAP != 0
static void *
wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size);
static void
wasm_munmap_linear_memory(void *mapped_mem, uint64 commit_size,
uint64 map_size);
static void *
runtime_malloc(uint64 size)
{
void *mem;
if (size >= UINT32_MAX || !(mem = wasm_runtime_malloc((uint32)size))) {
LOG_WARNING("Allocate memory failed");
return NULL;
}
memset(mem, 0, (uint32)size);
return mem;
}
WASMSharedHeap *
wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args)
{
uint64 heap_struct_size = sizeof(WASMSharedHeap), map_size;
uint32 size = init_args->size;
WASMSharedHeap *heap;
if (size == 0) {
goto fail1;
}
if (!(heap = runtime_malloc(heap_struct_size))) {
goto fail1;
}
if (!(heap->heap_handle =
runtime_malloc(mem_allocator_get_heap_struct_size()))) {
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;
if (size > APP_HEAP_SIZE_MAX || size < APP_HEAP_SIZE_MIN) {
LOG_WARNING("Invalid size of shared heap");
goto fail3;
}
#ifndef OS_ENABLE_HW_BOUND_CHECK
map_size = size;
#else
/* Totally 8G is mapped, the opcode load/store address range is 0 to 8G:
* ea = i + memarg.offset
* both i and memarg.offset are u32 in range 0 to 4G
* so the range of ea is 0 to 8G
*/
map_size = 8 * (uint64)BH_GB;
#endif
if (!(heap->base_addr = wasm_mmap_linear_memory(map_size, size))) {
goto fail3;
}
if (!mem_allocator_create_with_struct_and_pool(
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);
if (shared_heap_list == NULL) {
shared_heap_list = heap;
}
else {
heap->next = shared_heap_list;
shared_heap_list = heap;
}
os_mutex_unlock(&shared_heap_list_lock);
return heap;
fail4:
wasm_munmap_linear_memory(heap->base_addr, size, map_size);
fail3:
wasm_runtime_free(heap->heap_handle);
fail2:
wasm_runtime_free(heap);
fail1:
return NULL;
}
bool
wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
WASMSharedHeap *shared_heap)
{
WASMMemoryInstance *memory =
wasm_get_default_memory((WASMModuleInstance *)module_inst);
uint64 linear_mem_size;
if (!memory)
return false;
linear_mem_size = memory->memory_data_size;
/* check if linear memory and shared heap are overlapped */
if ((memory->is_memory64 && linear_mem_size > shared_heap->start_off_mem64)
|| (!memory->is_memory64
&& linear_mem_size > shared_heap->start_off_mem32)) {
LOG_WARNING("Linear memory address is overlapped with shared heap");
return false;
}
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMModuleInstanceExtra *e =
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
if (e->shared_heap) {
LOG_WARNING("A shared heap is already attached");
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
if (module_inst->module_type == Wasm_Module_AoT) {
AOTModuleInstanceExtra *e =
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
if (e->shared_heap) {
LOG_WARNING("A shared heap is already attached");
return false;
}
e->shared_heap = shared_heap;
#if UINTPTR_MAX == UINT64_MAX
if (memory->is_memory64)
e->shared_heap_start_off.u64 = shared_heap->start_off_mem64;
else
e->shared_heap_start_off.u64 = shared_heap->start_off_mem32;
e->shared_heap_base_addr_adj =
shared_heap->base_addr - e->shared_heap_start_off.u64;
#else
e->shared_heap_start_off.u32[0] = (uint32)shared_heap->start_off_mem32;
e->shared_heap_base_addr_adj =
shared_heap->base_addr - e->shared_heap_start_off.u32[0];
#endif
}
#endif /* end of WASM_ENABLE_AOT != 0 */
return true;
}
bool
wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
WASMSharedHeap *shared_heap)
{
#if WASM_ENABLE_THREAD_MGR != 0
return wasm_cluster_attach_shared_heap(module_inst, shared_heap);
#else
return wasm_runtime_attach_shared_heap_internal(module_inst, shared_heap);
#endif
}
void
wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst)
{
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMModuleInstanceExtra *e =
(WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e;
e->shared_heap = NULL;
#if WASM_ENABLE_JIT != 0
#if UINTPTR_MAX == UINT64_MAX
e->shared_heap_start_off.u64 = UINT64_MAX;
#else
e->shared_heap_start_off.u32[0] = UINT32_MAX;
#endif
e->shared_heap_base_addr_adj = NULL;
#endif
}
#endif /* end of WASM_ENABLE_INTERP != 0 */
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
AOTModuleInstanceExtra *e =
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
e->shared_heap = NULL;
#if UINTPTR_MAX == UINT64_MAX
e->shared_heap_start_off.u64 = UINT64_MAX;
#else
e->shared_heap_start_off.u32[0] = UINT32_MAX;
#endif
e->shared_heap_base_addr_adj = NULL;
}
#endif /* end of WASM_ENABLE_AOT != 0 */
}
void
wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst)
{
#if WASM_ENABLE_THREAD_MGR != 0
wasm_cluster_detach_shared_heap(module_inst);
#else
wasm_runtime_detach_shared_heap_internal(module_inst);
#endif
}
static WASMSharedHeap *
get_shared_heap(WASMModuleInstanceCommon *module_inst_comm)
{
#if WASM_ENABLE_INTERP != 0
if (module_inst_comm->module_type == Wasm_Module_Bytecode) {
return ((WASMModuleInstance *)module_inst_comm)->e->shared_heap;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst_comm->module_type == Wasm_Module_AoT) {
AOTModuleInstanceExtra *e =
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_comm)
->e;
return e->shared_heap;
}
#endif
return NULL;
}
WASMSharedHeap *
wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm)
{
return get_shared_heap(module_inst_comm);
}
static bool
is_app_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
bool is_memory64, uint64 app_offset, uint32 bytes)
{
WASMSharedHeap *heap = get_shared_heap(module_inst);
if (!heap) {
return false;
}
if (bytes == 0) {
bytes = 1;
}
if (!is_memory64) {
if (app_offset >= heap->start_off_mem32
&& app_offset <= UINT32_MAX - bytes + 1) {
return true;
}
}
else {
if (app_offset >= heap->start_off_mem64
&& app_offset <= UINT64_MAX - bytes + 1) {
return true;
}
}
return false;
}
static bool
is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
uint8 *addr, uint32 bytes)
{
WASMSharedHeap *heap = get_shared_heap(module_inst);
if (heap && addr >= heap->base_addr
&& addr + bytes <= heap->base_addr + heap->size
&& addr + bytes > addr) {
return true;
}
return false;
}
uint64
wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
uint64_t size, void **p_native_addr)
{
WASMMemoryInstance *memory =
wasm_get_default_memory((WASMModuleInstance *)module_inst);
WASMSharedHeap *shared_heap = get_shared_heap(module_inst);
void *native_addr = NULL;
if (!memory || !shared_heap)
return 0;
native_addr = mem_allocator_malloc(shared_heap->heap_handle, size);
if (!native_addr)
return 0;
if (p_native_addr) {
*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);
}
void
wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst, uint64 ptr)
{
WASMMemoryInstance *memory =
wasm_get_default_memory((WASMModuleInstance *)module_inst);
WASMSharedHeap *shared_heap = get_shared_heap(module_inst);
uint8 *addr = NULL;
if (!memory || !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");
return;
}
addr = shared_heap->base_addr + (ptr - shared_heap->start_off_mem64);
}
else {
if (ptr < shared_heap->start_off_mem32 || ptr > UINT32_MAX) {
LOG_WARNING("The address to free isn't in shared heap");
return;
}
addr = shared_heap->base_addr + (ptr - shared_heap->start_off_mem32);
}
mem_allocator_free(shared_heap->heap_handle, addr);
}
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
bool bool
wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
const MemAllocOption *alloc_option) const MemAllocOption *alloc_option)
{ {
bool ret = false;
#if WASM_ENABLE_SHARED_HEAP != 0
if (os_mutex_init(&shared_heap_list_lock)) {
return false;
}
#endif
if (mem_alloc_type == Alloc_With_Pool) { if (mem_alloc_type == Alloc_With_Pool) {
return wasm_memory_init_with_pool(alloc_option->pool.heap_buf, ret = wasm_memory_init_with_pool(alloc_option->pool.heap_buf,
alloc_option->pool.heap_size); alloc_option->pool.heap_size);
} }
else if (mem_alloc_type == Alloc_With_Allocator) { else if (mem_alloc_type == Alloc_With_Allocator) {
return wasm_memory_init_with_allocator( ret = wasm_memory_init_with_allocator(
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 #if WASM_MEM_ALLOC_WITH_USER_DATA != 0
alloc_option->allocator.user_data, alloc_option->allocator.user_data,
#endif #endif
@ -151,16 +515,58 @@ wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
} }
else if (mem_alloc_type == Alloc_With_System_Allocator) { else if (mem_alloc_type == Alloc_With_System_Allocator) {
memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR; memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR;
return true; ret = true;
} }
else { else {
return false; ret = false;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
if (!ret) {
os_mutex_destroy(&shared_heap_list_lock);
}
#endif
return ret;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
static void
destroy_shared_heaps()
{
WASMSharedHeap *heap;
WASMSharedHeap *cur;
uint64 map_size;
os_mutex_lock(&shared_heap_list_lock);
heap = shared_heap_list;
shared_heap_list = NULL;
os_mutex_unlock(&shared_heap_list_lock);
while (heap) {
cur = heap;
heap = heap->next;
mem_allocator_destroy(cur->heap_handle);
wasm_runtime_free(cur->heap_handle);
#ifndef OS_ENABLE_HW_BOUND_CHECK
map_size = cur->size;
#else
map_size = 8 * (uint64)BH_GB;
#endif
wasm_munmap_linear_memory(cur->base_addr, cur->size, map_size);
wasm_runtime_free(cur);
}
os_mutex_destroy(&shared_heap_list_lock);
}
#endif
void void
wasm_runtime_memory_destroy(void) wasm_runtime_memory_destroy(void)
{ {
#if WASM_ENABLE_SHARED_HEAP != 0
destroy_shared_heaps();
#endif
if (memory_mode == MEMORY_MODE_POOL) { if (memory_mode == MEMORY_MODE_POOL) {
#if BH_ENABLE_GC_VERIFY == 0 #if BH_ENABLE_GC_VERIFY == 0
(void)mem_allocator_destroy(pool_allocator); (void)mem_allocator_destroy(pool_allocator);
@ -335,6 +741,13 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm,
goto fail; goto fail;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
if (is_app_addr_in_shared_heap(module_inst_comm, memory_inst->is_memory64,
app_offset, size)) {
return true;
}
#endif
#if WASM_ENABLE_MEMORY64 != 0 #if WASM_ENABLE_MEMORY64 != 0
if (memory_inst->is_memory64) if (memory_inst->is_memory64)
max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE;
@ -364,6 +777,7 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
uint64 app_str_offset) uint64 app_str_offset)
{ {
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
WASMMemoryInstance *memory_inst;
uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE;
char *str, *str_end; char *str, *str_end;
@ -374,22 +788,42 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
return true; return true;
} }
if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL, memory_inst = wasm_get_default_memory(module_inst);
&app_end_offset)) if (!memory_inst) {
goto fail;
}
#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;
}
else
#endif
{
if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset,
NULL, &app_end_offset))
goto fail; goto fail;
#if WASM_ENABLE_MEMORY64 != 0 #if WASM_ENABLE_MEMORY64 != 0
if (module_inst->memories[0]->is_memory64) if (memory_inst->is_memory64)
max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE;
#endif #endif
/* boundary overflow check, max start offset can only be size - 1, while end /* boundary overflow check, max start offset can be size - 1, while end
* offset can be size */ offset can be size */
if (app_str_offset >= max_linear_memory_size if (app_str_offset >= max_linear_memory_size
|| app_end_offset > max_linear_memory_size) || app_end_offset > max_linear_memory_size)
goto fail; goto fail;
str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset); str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset);
str_end = str + (app_end_offset - app_str_offset); str_end = str + (app_end_offset - app_str_offset);
}
while (str < str_end && *str != '\0') while (str < str_end && *str != '\0')
str++; str++;
if (str == str_end) if (str == str_end)
@ -431,6 +865,12 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm,
goto fail; goto fail;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
if (is_native_addr_in_shared_heap(module_inst_comm, native_ptr, size)) {
return true;
}
#endif
SHARED_MEMORY_LOCK(memory_inst); SHARED_MEMORY_LOCK(memory_inst);
if (memory_inst->memory_data <= addr if (memory_inst->memory_data <= addr
@ -465,6 +905,23 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
return NULL; return NULL;
} }
#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;
}
#endif
SHARED_MEMORY_LOCK(memory_inst); SHARED_MEMORY_LOCK(memory_inst);
addr = memory_inst->memory_data + (uintptr_t)app_offset; addr = memory_inst->memory_data + (uintptr_t)app_offset;
@ -499,11 +956,32 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
bounds_checks = is_bounds_checks_enabled(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); memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) { if (!memory_inst) {
return 0; 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);
}
#endif
SHARED_MEMORY_LOCK(memory_inst); SHARED_MEMORY_LOCK(memory_inst);
if (bounds_checks) { if (bounds_checks) {
@ -601,6 +1079,10 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst); WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst);
uint8 *native_addr; uint8 *native_addr;
bool bounds_checks; bool bounds_checks;
#if WASM_ENABLE_SHARED_HEAP != 0
WASMSharedHeap *shared_heap;
bool is_in_shared_heap = false;
#endif
bh_assert(app_buf_addr <= UINTPTR_MAX && app_buf_size <= UINTPTR_MAX); bh_assert(app_buf_addr <= UINTPTR_MAX && app_buf_size <= UINTPTR_MAX);
@ -609,9 +1091,25 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
return false; return false;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
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; native_addr = memory_inst->memory_data + (uintptr_t)app_buf_addr;
}
bounds_checks = is_bounds_checks_enabled((wasm_module_inst_t)module_inst); bounds_checks =
is_bounds_checks_enabled((WASMModuleInstanceCommon *)module_inst);
if (!bounds_checks) { if (!bounds_checks) {
if (app_buf_addr == 0) { if (app_buf_addr == 0) {
@ -620,6 +1118,24 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
goto success; goto success;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
if (is_in_shared_heap) {
const char *str, *str_end;
/* The whole string must be in the linear memory */
str = (const char *)native_addr;
str_end = (const char *)shared_heap->base_addr + shared_heap->size;
while (str < str_end && *str != '\0')
str++;
if (str == str_end) {
wasm_set_exception(module_inst, "out of bounds memory access");
return false;
}
else
goto success;
}
#endif
/* No need to check the app_offset and buf_size if memory access /* No need to check the app_offset and buf_size if memory access
boundary check with hardware trap is enabled */ boundary check with hardware trap is enabled */
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
@ -749,7 +1265,7 @@ wasm_mremap_linear_memory(void *mapped_mem, uint64 old_size, uint64 new_size,
} }
static void * static void *
wasm_mmap_linear_memory(uint64_t map_size, uint64 commit_size) wasm_mmap_linear_memory(uint64 map_size, uint64 commit_size)
{ {
return wasm_mremap_linear_memory(NULL, 0, map_size, commit_size); return wasm_mremap_linear_memory(NULL, 0, map_size, commit_size);
} }
@ -758,6 +1274,9 @@ static bool
wasm_enlarge_memory_internal(WASMModuleInstanceCommon *module, wasm_enlarge_memory_internal(WASMModuleInstanceCommon *module,
WASMMemoryInstance *memory, uint32 inc_page_count) WASMMemoryInstance *memory, uint32 inc_page_count)
{ {
#if WASM_ENABLE_SHARED_HEAP != 0
WASMSharedHeap *shared_heap;
#endif
uint8 *memory_data_old, *memory_data_new, *heap_data_old; uint8 *memory_data_old, *memory_data_new, *heap_data_old;
uint32 num_bytes_per_page, heap_size; uint32 num_bytes_per_page, heap_size;
uint32 cur_page_count, max_page_count, total_page_count; uint32 cur_page_count, max_page_count, total_page_count;
@ -805,6 +1324,24 @@ wasm_enlarge_memory_internal(WASMModuleInstanceCommon *module,
goto return_func; goto return_func;
} }
#if WASM_ENABLE_SHARED_HEAP != 0
shared_heap = get_shared_heap(module);
if (shared_heap) {
if (memory->is_memory64
&& total_size_new > shared_heap->start_off_mem64) {
LOG_WARNING("Linear memory address is overlapped with shared heap");
ret = false;
goto return_func;
}
else if (!memory->is_memory64
&& total_size_new > shared_heap->start_off_mem32) {
LOG_WARNING("Linear memory address is overlapped with shared heap");
ret = false;
goto return_func;
}
}
#endif
bh_assert(total_size_new bh_assert(total_size_new
<= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64));

View File

@ -41,6 +41,35 @@ SET_LINEAR_MEMORY_SIZE(WASMMemoryInstance *memory, uint64 size)
#define SET_LINEAR_MEMORY_SIZE(memory, size) memory->memory_data_size = size #define SET_LINEAR_MEMORY_SIZE(memory, size) memory->memory_data_size = size
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
WASMSharedHeap *
wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);
bool
wasm_runtime_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
WASMSharedHeap *shared_heap);
bool
wasm_runtime_attach_shared_heap_internal(WASMModuleInstanceCommon *module_inst,
WASMSharedHeap *shared_heap);
void
wasm_runtime_detach_shared_heap(WASMModuleInstanceCommon *module_inst);
void
wasm_runtime_detach_shared_heap_internal(WASMModuleInstanceCommon *module_inst);
WASMSharedHeap *
wasm_runtime_get_shared_heap(WASMModuleInstanceCommon *module_inst_comm);
uint64
wasm_runtime_shared_heap_malloc(WASMModuleInstanceCommon *module_inst,
uint64 size, void **p_native_addr);
void
wasm_runtime_shared_heap_free(WASMModuleInstanceCommon *module_inst,
uint64 ptr);
#endif
bool bool
wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
const MemAllocOption *alloc_option); const MemAllocOption *alloc_option);

View File

@ -33,6 +33,11 @@ uint32
get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis); get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis);
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
uint32
get_lib_shared_heap_export_apis(NativeSymbol **p_shared_heap_apis);
#endif
uint32 uint32
get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis); get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis);
@ -512,6 +517,14 @@ wasm_native_init()
goto fail; goto fail;
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
n_native_symbols = get_lib_shared_heap_export_apis(&native_symbols);
if (n_native_symbols > 0
&& !wasm_native_register_natives("env", native_symbols,
n_native_symbols))
goto fail;
#endif
#if WASM_ENABLE_BASE_LIB != 0 #if WASM_ENABLE_BASE_LIB != 0
n_native_symbols = get_base_lib_export_apis(&native_symbols); n_native_symbols = get_base_lib_export_apis(&native_symbols);
if (n_native_symbols > 0 if (n_native_symbols > 0

View File

@ -185,6 +185,9 @@ static bool
is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst) is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst)
{ {
WASMMemoryInstance *memory_inst; WASMMemoryInstance *memory_inst;
#if WASM_ENABLE_SHARED_HEAP != 0
WASMSharedHeap *shared_heap;
#endif
uint8 *mapped_mem_start_addr = NULL; uint8 *mapped_mem_start_addr = NULL;
uint8 *mapped_mem_end_addr = NULL; uint8 *mapped_mem_end_addr = NULL;
uint32 i; uint32 i;
@ -202,6 +205,21 @@ is_sig_addr_in_guard_pages(void *sig_addr, WASMModuleInstance *module_inst)
} }
} }
#if WASM_ENABLE_SHARED_HEAP != 0
shared_heap =
wasm_runtime_get_shared_heap((WASMModuleInstanceCommon *)module_inst);
if (shared_heap) {
mapped_mem_start_addr = shared_heap->base_addr;
mapped_mem_end_addr = shared_heap->base_addr + 8 * (uint64)BH_GB;
if (mapped_mem_start_addr <= (uint8 *)sig_addr
&& (uint8 *)sig_addr < mapped_mem_end_addr) {
/* The address which causes segmentation fault is inside
the shared heap's guard regions */
return true;
}
}
#endif
return false; return false;
} }
@ -4513,9 +4531,14 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
uint32 *argv, uint32 argc, uint32 *argv_ret) uint32 *argv, uint32 argc, uint32 *argv_ret)
{ {
WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env);
#if WASM_ENABLE_MEMORY64 != 0
WASMMemoryInstance *memory =
wasm_get_default_memory((WASMModuleInstance *)module);
bool is_memory64 = memory ? memory->is_memory64 : false;
#endif
typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *); typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *);
NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr; NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr;
uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size, arg_i64; uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size;
uint32 *argv_src = argv, i, argc1, ptr_len; uint32 *argv_src = argv, i, argc1, ptr_len;
uint32 arg_i32; uint32 arg_i32;
bool ret = false; bool ret = false;
@ -4540,11 +4563,11 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
#endif #endif
{ {
*(uint32 *)argv_dst = arg_i32 = *argv_src++; *(uint32 *)argv_dst = arg_i32 = *argv_src++;
/* TODO: memory64 if future there is a way for supporting if (signature
* wasm64 and wasm32 in libc at the same time, remove the #if WASM_ENABLE_MEMORY64 != 0
* macro control */ && !is_memory64
#if WASM_ENABLE_MEMORY64 == 0 #endif
if (signature) { ) {
if (signature[i + 1] == '*') { if (signature[i + 1] == '*') {
/* param is a pointer */ /* param is a pointer */
if (signature[i + 2] == '~') if (signature[i + 2] == '~')
@ -4573,17 +4596,18 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
module, (uint64)arg_i32); module, (uint64)arg_i32);
} }
} }
#endif
break; break;
} }
case VALUE_TYPE_I64: case VALUE_TYPE_I64:
#if WASM_ENABLE_MEMORY64 != 0 #if WASM_ENABLE_MEMORY64 != 0
{ {
uint64 arg_i64;
PUT_I64_TO_ADDR((uint32 *)argv_dst, PUT_I64_TO_ADDR((uint32 *)argv_dst,
GET_I64_FROM_ADDR(argv_src)); GET_I64_FROM_ADDR(argv_src));
argv_src += 2; argv_src += 2;
arg_i64 = *argv_dst; arg_i64 = *argv_dst;
if (signature) { if (signature && is_memory64) {
/* TODO: memory64 pointer with length need a new symbol /* TODO: memory64 pointer with length need a new symbol
* to represent type i64, with '~' still represent i32 * to represent type i64, with '~' still represent i32
* length */ * length */
@ -4744,9 +4768,6 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
fail: fail:
if (argv1 != argv_buf) if (argv1 != argv_buf)
wasm_runtime_free(argv1); wasm_runtime_free(argv1);
#if WASM_ENABLE_MEMORY64 == 0
(void)arg_i64;
#endif
return ret; return ret;
} }
@ -5670,6 +5691,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
uint32 *argv_ret) uint32 *argv_ret)
{ {
WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env);
#if WASM_ENABLE_MEMORY64 != 0
WASMMemoryInstance *memory =
wasm_get_default_memory((WASMModuleInstance *)module);
bool is_memory64 = memory ? memory->is_memory64 : false;
#endif
uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size, uint64 argv_buf[32] = { 0 }, *argv1 = argv_buf, *ints, *stacks, size,
arg_i64; arg_i64;
uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0;
@ -5735,11 +5761,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
{ {
arg_i32 = *argv_src++; arg_i32 = *argv_src++;
arg_i64 = arg_i32; arg_i64 = arg_i32;
/* TODO: memory64 if future there is a way for supporting if (signature
* wasm64 and wasm32 in libc at the same time, remove the #if WASM_ENABLE_MEMORY64 != 0
* macro control */ && !is_memory64
#if WASM_ENABLE_MEMORY64 == 0 #endif
if (signature) { ) {
if (signature[i + 1] == '*') { if (signature[i + 1] == '*') {
/* param is a pointer */ /* param is a pointer */
if (signature[i + 2] == '~') if (signature[i + 2] == '~')
@ -5766,7 +5792,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
module, (uint64)arg_i32); module, (uint64)arg_i32);
} }
} }
#endif
if (n_ints < MAX_REG_INTS) if (n_ints < MAX_REG_INTS)
ints[n_ints++] = arg_i64; ints[n_ints++] = arg_i64;
else else
@ -5778,7 +5803,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
{ {
arg_i64 = GET_I64_FROM_ADDR(argv_src); arg_i64 = GET_I64_FROM_ADDR(argv_src);
argv_src += 2; argv_src += 2;
if (signature) { if (signature && is_memory64) {
/* TODO: memory64 pointer with length need a new symbol /* TODO: memory64 pointer with length need a new symbol
* to represent type i64, with '~' still represent i32 * to represent type i64, with '~' still represent i32
* length */ * length */

View File

@ -8,6 +8,9 @@
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
#include "../libraries/thread-mgr/thread_manager.h" #include "../libraries/thread-mgr/thread_manager.h"
#endif #endif
#if WASM_ENABLE_AOT != 0
#include "../aot/aot_runtime.h"
#endif
/* /*
* Note: this lock can be per memory. * Note: this lock can be per memory.
@ -243,6 +246,31 @@ map_try_release_wait_info(HashMap *wait_hash_map, AtomicWaitInfo *wait_info,
destroy_wait_info(wait_info); destroy_wait_info(wait_info);
} }
#if WASM_ENABLE_SHARED_HEAP != 0
static bool
is_native_addr_in_shared_heap(WASMModuleInstanceCommon *module_inst,
uint8 *addr, uint32 bytes)
{
WASMSharedHeap *shared_heap = NULL;
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
shared_heap = ((WASMModuleInstance *)module_inst)->e->shared_heap;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
AOTModuleInstanceExtra *e =
(AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
shared_heap = e->shared_heap;
}
#endif
return shared_heap && addr >= shared_heap->base_addr
&& addr + bytes <= shared_heap->base_addr + shared_heap->size;
}
#endif
uint32 uint32
wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
uint64 expect, int64 timeout, bool wait64) uint64 expect, int64 timeout, bool wait64)
@ -271,9 +299,17 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
} }
shared_memory_lock(module_inst->memories[0]); shared_memory_lock(module_inst->memories[0]);
if ((uint8 *)address < module_inst->memories[0]->memory_data if (
#if WASM_ENABLE_SHARED_HEAP != 0
/* not in shared heap */
!is_native_addr_in_shared_heap((WASMModuleInstanceCommon *)module_inst,
address, wait64 ? 8 : 4)
&&
#endif
/* and not in linear memory */
((uint8 *)address < module_inst->memories[0]->memory_data
|| (uint8 *)address + (wait64 ? 8 : 4) || (uint8 *)address + (wait64 ? 8 : 4)
> module_inst->memories[0]->memory_data_end) { > module_inst->memories[0]->memory_data_end)) {
shared_memory_unlock(module_inst->memories[0]); shared_memory_unlock(module_inst->memories[0]);
wasm_runtime_set_exception(module, "out of bounds memory access"); wasm_runtime_set_exception(module, "out of bounds memory access");
return -1; return -1;
@ -397,6 +433,11 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
shared_memory_lock(module_inst->memories[0]); shared_memory_lock(module_inst->memories[0]);
out_of_bounds = out_of_bounds =
#if WASM_ENABLE_SHARED_HEAP != 0
/* not in shared heap */
!is_native_addr_in_shared_heap(module, address, 4) &&
#endif
/* and not in linear memory */
((uint8 *)address < module_inst->memories[0]->memory_data ((uint8 *)address < module_inst->memories[0]->memory_data
|| (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end); || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end);
shared_memory_unlock(module_inst->memories[0]); shared_memory_unlock(module_inst->memories[0]);

View File

@ -118,10 +118,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
{ {
LLVMValueRef offset_const = LLVMValueRef offset_const =
MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset)); MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset));
LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp; LLVMValueRef addr, maddr, maddr_phi = NULL, offset1, cmp1, cmp2, cmp;
LLVMValueRef mem_base_addr, mem_check_bound; LLVMValueRef mem_base_addr, mem_check_bound;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef check_succ; LLVMBasicBlockRef check_succ, block_maddr_phi = NULL;
AOTValue *aot_value_top; AOTValue *aot_value_top;
uint32 local_idx_of_aot_value = 0; uint32 local_idx_of_aot_value = 0;
uint64 const_value; uint64 const_value;
@ -131,6 +131,11 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
bool is_shared_memory = bool is_shared_memory =
comp_ctx->comp_data->memories[0].flags & SHARED_MEMORY_FLAG; comp_ctx->comp_data->memories[0].flags & SHARED_MEMORY_FLAG;
#endif #endif
#if WASM_ENABLE_MEMORY64 == 0
bool is_memory64 = false;
#else
bool is_memory64 = IS_MEMORY64;
#endif
is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false; is_target_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
@ -268,8 +273,137 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
} }
/* offset1 = offset + addr; */ /* offset1 = offset + addr; */
/* TODO: check whether integer overflow occurs when memory is 64-bit
and boundary check is enabled */
BUILD_OP(Add, offset_const, addr, offset1, "offset1"); BUILD_OP(Add, offset_const, addr, offset1, "offset1");
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem;
LLVMValueRef is_in_shared_heap, shared_heap_check_bound = NULL;
/* Add basic blocks */
ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap");
ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem");
ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr);
LLVMMoveBasicBlockAfter(app_addr_in_linear_mem,
app_addr_in_shared_heap);
LLVMMoveBasicBlockAfter(block_maddr_phi, app_addr_in_linear_mem);
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
if (!(maddr_phi =
LLVMBuildPhi(comp_ctx->builder,
enable_segue ? INT8_PTR_TYPE_GS : INT8_PTR_TYPE,
"maddr_phi"))) {
aot_set_last_error("llvm build phi failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
if (!is_target_64bit) {
/* Check whether interger overflow occurs in addr + offset */
LLVMBasicBlockRef check_integer_overflow_end;
ADD_BASIC_BLOCK(check_integer_overflow_end,
"check_integer_overflow_end");
LLVMMoveBasicBlockAfter(check_integer_overflow_end, block_curr);
BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
if (!aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true,
cmp1, check_integer_overflow_end)) {
goto fail;
}
SET_BUILD_POS(check_integer_overflow_end);
}
shared_heap_check_bound =
is_memory64 ? I64_CONST(UINT64_MAX - bytes + 1)
: (comp_ctx->pointer_size == sizeof(uint64)
? I64_CONST(UINT32_MAX - bytes + 1)
: I32_CONST(UINT32_MAX - bytes + 1));
CHECK_LLVM_CONST(shared_heap_check_bound);
/* Check whether the bytes to access are in shared heap */
if (!comp_ctx->enable_bound_check) {
/* Use IntUGT but not IntUGE to compare, since (1) in the ems
memory allocator, the hmu node includes hmu header and hmu
memory, only the latter is returned to the caller as the
allocated memory, the hmu header isn't returned so the
first byte of the shared heap won't be accesed, (2) using
IntUGT gets better performance than IntUGE in some cases */
BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off,
is_in_shared_heap, "is_in_shared_heap");
/* We don't check the shared heap's upper boundary if boundary
check isn't enabled, the runtime may also use the guard pages
of shared heap to check the boundary if hardware boundary
check feature is enabled. */
}
else {
/* Use IntUGT but not IntUGE to compare, same as above */
BUILD_ICMP(LLVMIntUGT, offset1, func_ctx->shared_heap_start_off,
cmp1, "cmp1");
/* Check the shared heap's upper boundary if boundary check is
enabled */
BUILD_ICMP(LLVMIntULE, offset1, shared_heap_check_bound, cmp2,
"cmp2");
BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap");
}
if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap,
app_addr_in_shared_heap, app_addr_in_linear_mem)) {
aot_set_last_error("llvm build cond br failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap);
/* Get native address inside shared heap */
if (!(maddr =
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->shared_heap_base_addr_adj,
&offset1, 1, "maddr_shared_heap"))) {
aot_set_last_error("llvm build inbounds gep failed");
goto fail;
}
if (enable_segue) {
LLVMValueRef mem_base_addr_u64, maddr_u64, offset_to_mem_base;
if (!(maddr_u64 = LLVMBuildPtrToInt(comp_ctx->builder, maddr,
I64_TYPE, "maddr_u64"))
|| !(mem_base_addr_u64 =
LLVMBuildPtrToInt(comp_ctx->builder, mem_base_addr,
I64_TYPE, "mem_base_addr_u64"))) {
aot_set_last_error("llvm build ptr to int failed");
goto fail;
}
if (!(offset_to_mem_base =
LLVMBuildSub(comp_ctx->builder, maddr_u64,
mem_base_addr_u64, "offset_to_mem_base"))) {
aot_set_last_error("llvm build sub failed");
goto fail;
}
if (!(maddr = LLVMBuildIntToPtr(
comp_ctx->builder, offset_to_mem_base, INT8_PTR_TYPE_GS,
"maddr_shared_heap_segue"))) {
aot_set_last_error("llvm build int to ptr failed.");
goto fail;
}
}
LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
aot_set_last_error("llvm build br failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem);
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
}
if (comp_ctx->enable_bound_check if (comp_ctx->enable_bound_check
&& !(is_local_of_aot_value && !(is_local_of_aot_value
&& aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value, && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value,
@ -304,12 +438,18 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
if (is_target_64bit) { if (is_target_64bit) {
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
} }
else {
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
/* Check integer overflow has been checked above */
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp");
}
else { else {
/* Check integer overflow */ /* Check integer overflow */
BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1");
BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2");
BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); BUILD_OP(Or, cmp1, cmp2, cmp, "cmp");
} }
}
/* Add basic blocks */ /* Add basic blocks */
ADD_BASIC_BLOCK(check_succ, "check_succ"); ADD_BASIC_BLOCK(check_succ, "check_succ");
@ -354,6 +494,18 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail; goto fail;
} }
} }
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
aot_set_last_error("llvm build br failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
return maddr_phi;
}
else
return maddr; return maddr;
fail: fail:
return NULL; return NULL;
@ -985,10 +1137,15 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef offset, LLVMValueRef bytes) LLVMValueRef offset, LLVMValueRef bytes)
{ {
LLVMValueRef maddr, max_addr, cmp; LLVMValueRef maddr, max_addr, cmp;
LLVMValueRef mem_base_addr; LLVMValueRef mem_base_addr, maddr_phi = NULL;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef check_succ; LLVMBasicBlockRef check_succ, block_maddr_phi = NULL;
LLVMValueRef mem_size; LLVMValueRef mem_size;
#if WASM_ENABLE_MEMORY64 == 0
bool is_memory64 = false;
#else
bool is_memory64 = IS_MEMORY64;
#endif
/* Get memory base address and memory data size */ /* Get memory base address and memory data size */
#if WASM_ENABLE_SHARED_MEMORY != 0 #if WASM_ENABLE_SHARED_MEMORY != 0
@ -1053,9 +1210,96 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
offset = offset =
LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset"); LLVMBuildZExt(comp_ctx->builder, offset, I64_TYPE, "extend_offset");
bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len"); bytes = LLVMBuildZExt(comp_ctx->builder, bytes, I64_TYPE, "extend_len");
if (!offset || !bytes) {
aot_set_last_error("llvm build zext failed.");
goto fail;
}
/* TODO: check whether integer overflow occurs when memory is 64-bit
and boundary check is enabled */
BUILD_OP(Add, offset, bytes, max_addr, "max_addr"); BUILD_OP(Add, offset, bytes, max_addr, "max_addr");
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
LLVMBasicBlockRef app_addr_in_shared_heap, app_addr_in_linear_mem;
LLVMValueRef shared_heap_start_off, shared_heap_check_bound;
LLVMValueRef max_offset, cmp1, cmp2, is_in_shared_heap;
/* Add basic blocks */
ADD_BASIC_BLOCK(app_addr_in_shared_heap, "app_addr_in_shared_heap");
ADD_BASIC_BLOCK(app_addr_in_linear_mem, "app_addr_in_linear_mem");
ADD_BASIC_BLOCK(block_maddr_phi, "maddr_phi");
LLVMMoveBasicBlockAfter(app_addr_in_shared_heap, block_curr);
LLVMMoveBasicBlockAfter(app_addr_in_linear_mem,
app_addr_in_shared_heap);
LLVMMoveBasicBlockAfter(block_maddr_phi, check_succ);
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
if (!(maddr_phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE,
"maddr_phi"))) {
aot_set_last_error("llvm build phi failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr);
shared_heap_start_off = func_ctx->shared_heap_start_off;
if (comp_ctx->pointer_size == sizeof(uint32)) {
if (!(shared_heap_start_off =
LLVMBuildZExt(comp_ctx->builder, shared_heap_start_off,
I64_TYPE, "shared_heap_start_off_u64"))) {
aot_set_last_error("llvm build zext failed");
goto fail;
}
}
shared_heap_check_bound =
is_memory64 ? I64_CONST(UINT64_MAX) : I64_CONST(UINT32_MAX);
CHECK_LLVM_CONST(shared_heap_check_bound);
/* Check whether the bytes to access are in shared heap */
if (!comp_ctx->enable_bound_check) {
/* Use IntUGT but not IntUGE to compare, same as the check
in aot_check_memory_overflow */
BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off,
is_in_shared_heap, "is_in_shared_heap");
}
else {
BUILD_ICMP(LLVMIntUGT, offset, func_ctx->shared_heap_start_off,
cmp1, "cmp1");
BUILD_OP(Add, max_addr, I64_NEG_ONE, max_offset, "max_offset");
BUILD_ICMP(LLVMIntULE, max_offset, shared_heap_check_bound, cmp2,
"cmp2");
BUILD_OP(And, cmp1, cmp2, is_in_shared_heap, "is_in_shared_heap");
}
if (!LLVMBuildCondBr(comp_ctx->builder, is_in_shared_heap,
app_addr_in_shared_heap, app_addr_in_linear_mem)) {
aot_set_last_error("llvm build cond br failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_shared_heap);
/* Get native address inside shared heap */
if (!(maddr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->shared_heap_base_addr_adj,
&offset, 1, "maddr_shared_heap"))) {
aot_set_last_error("llvm build inbounds gep failed");
goto fail;
}
LLVMAddIncoming(maddr_phi, &maddr, &app_addr_in_shared_heap, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
aot_set_last_error("llvm build br failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, app_addr_in_linear_mem);
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
}
BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr"); BUILD_ICMP(LLVMIntUGT, max_addr, mem_size, cmp, "cmp_max_mem_addr");
if (!aot_emit_exception(comp_ctx, func_ctx, if (!aot_emit_exception(comp_ctx, func_ctx,
EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp,
check_succ)) { check_succ)) {
@ -1068,11 +1312,23 @@ check_bulk_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
aot_set_last_error("llvm build add failed."); aot_set_last_error("llvm build add failed.");
goto fail; goto fail;
} }
if (comp_ctx->enable_shared_heap /* TODO: && mem_idx == 0 */) {
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMAddIncoming(maddr_phi, &maddr, &block_curr, 1);
if (!LLVMBuildBr(comp_ctx->builder, block_maddr_phi)) {
aot_set_last_error("llvm build br failed");
goto fail;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_maddr_phi);
return maddr_phi;
}
else
return maddr; return maddr;
fail: fail:
return NULL; return NULL;
} }
#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 or WASM_ENABLE_STRINGREF != 0 */ #endif /* end of WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_STRINGREF != 0 */
#if WASM_ENABLE_BULK_MEMORY != 0 #if WASM_ENABLE_BULK_MEMORY != 0
bool bool

View File

@ -1518,6 +1518,75 @@ create_memory_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true; return true;
} }
static bool
create_shared_heap_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef offset, base_addr_p, start_off_p, cmp;
uint32 offset_u32;
/* Load aot_inst->e->shared_heap_base_addr_adj */
offset_u32 = get_module_inst_extra_offset(comp_ctx);
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
if (comp_ctx->is_jit_mode)
offset_u32 +=
offsetof(WASMModuleInstanceExtra, shared_heap_base_addr_adj);
else
#endif
offset_u32 +=
offsetof(AOTModuleInstanceExtra, shared_heap_base_addr_adj);
offset = I32_CONST(offset_u32);
CHECK_LLVM_CONST(offset);
if (!(base_addr_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"shared_heap_base_addr_adj_p"))) {
aot_set_last_error("llvm build inbounds gep failed");
return false;
}
if (!(func_ctx->shared_heap_base_addr_adj =
LLVMBuildLoad2(comp_ctx->builder, INT8_PTR_TYPE, base_addr_p,
"shared_heap_base_addr_adj"))) {
aot_set_last_error("llvm build load failed");
return false;
}
/* Load aot_inst->e->shared_heap_start_off */
offset_u32 = get_module_inst_extra_offset(comp_ctx);
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
if (comp_ctx->is_jit_mode)
offset_u32 += offsetof(WASMModuleInstanceExtra, shared_heap_start_off);
else
#endif
offset_u32 += offsetof(AOTModuleInstanceExtra, shared_heap_start_off);
offset = I32_CONST(offset_u32);
CHECK_LLVM_CONST(offset);
if (!(start_off_p = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
func_ctx->aot_inst, &offset, 1,
"shared_heap_start_off_p"))) {
aot_set_last_error("llvm build inbounds gep failed");
return false;
}
if (!(func_ctx->shared_heap_start_off = LLVMBuildLoad2(
comp_ctx->builder,
comp_ctx->pointer_size == sizeof(uint64) ? I64_TYPE : I32_TYPE,
start_off_p, "shared_heap_start_off"))) {
aot_set_last_error("llvm build load failed");
return false;
}
if (!(cmp = LLVMBuildIsNotNull(comp_ctx->builder,
func_ctx->shared_heap_base_addr_adj,
"has_shared_heap"))) {
aot_set_last_error("llvm build is not null failed");
return false;
}
return true;
fail:
return false;
}
static bool static bool
create_cur_exception(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) create_cur_exception(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{ {
@ -1808,6 +1877,12 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
goto fail; goto fail;
} }
/* Load shared heap, shared heap start off mem32 or mem64 */
if (comp_ctx->enable_shared_heap
&& !create_shared_heap_info(comp_ctx, func_ctx)) {
goto fail;
}
return func_ctx; return func_ctx;
fail: fail:
@ -2619,6 +2694,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
if (option->enable_gc) if (option->enable_gc)
comp_ctx->enable_gc = true; comp_ctx->enable_gc = true;
if (option->enable_shared_heap)
comp_ctx->enable_shared_heap = true;
comp_ctx->opt_level = option->opt_level; comp_ctx->opt_level = option->opt_level;
comp_ctx->size_level = option->size_level; comp_ctx->size_level = option->size_level;

View File

@ -242,6 +242,9 @@ typedef struct AOTFuncContext {
bool mem_space_unchanged; bool mem_space_unchanged;
AOTCheckedAddrList checked_addr_list; AOTCheckedAddrList checked_addr_list;
LLVMValueRef shared_heap_base_addr_adj;
LLVMValueRef shared_heap_start_off;
LLVMBasicBlockRef got_exception_block; LLVMBasicBlockRef got_exception_block;
LLVMBasicBlockRef func_return_block; LLVMBasicBlockRef func_return_block;
LLVMValueRef exception_id_phi; LLVMValueRef exception_id_phi;
@ -467,6 +470,8 @@ typedef struct AOTCompContext {
/* Enable GC */ /* Enable GC */
bool enable_gc; bool enable_gc;
bool enable_shared_heap;
uint32 opt_level; uint32 opt_level;
uint32 size_level; uint32 size_level;

View File

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

View File

@ -139,6 +139,9 @@ typedef struct wasm_section_t {
struct WASMExecEnv; struct WASMExecEnv;
typedef struct WASMExecEnv *wasm_exec_env_t; typedef struct WASMExecEnv *wasm_exec_env_t;
struct WASMSharedHeap;
typedef struct WASMSharedHeap *wasm_shared_heap_t;
/* Package Type */ /* Package Type */
typedef enum { typedef enum {
Wasm_Module_Bytecode = 0, Wasm_Module_Bytecode = 0,
@ -329,6 +332,10 @@ typedef enum {
WASM_LOG_LEVEL_VERBOSE = 4 WASM_LOG_LEVEL_VERBOSE = 4
} log_level_t; } log_level_t;
typedef struct SharedHeapInitArgs {
uint32_t size;
} SharedHeapInitArgs;
/** /**
* Initialize the WASM runtime environment, and also initialize * Initialize the WASM runtime environment, and also initialize
* the memory allocator with system allocator, which calls os_malloc * the memory allocator with system allocator, which calls os_malloc
@ -2219,6 +2226,60 @@ wasm_runtime_detect_native_stack_overflow_size(wasm_exec_env_t exec_env,
WASM_RUNTIME_API_EXTERN bool WASM_RUNTIME_API_EXTERN bool
wasm_runtime_is_underlying_binary_freeable(const wasm_module_t module); wasm_runtime_is_underlying_binary_freeable(const wasm_module_t module);
/**
* Create a shared heap
*
* @param init_args the initialization arguments
* @return the shared heap created
*/
WASM_RUNTIME_API_EXTERN wasm_shared_heap_t
wasm_runtime_create_shared_heap(SharedHeapInitArgs *init_args);
/**
* Attach a shared heap to a module instance
*
* @param module_inst the module instance
* @param shared_heap the shared heap
* @return true if success, false if failed
*/
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_attach_shared_heap(wasm_module_inst_t module_inst,
wasm_shared_heap_t shared_heap);
/**
* Detach a shared heap from a module instance
*
* @param module_inst the module instance
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_detach_shared_heap(wasm_module_inst_t module_inst);
/**
* Allocate memory from a shared heap
*
* @param module_inst the module instance
* @param size required memory size
* @param p_native_addr native address of allocated memory
*
* @return return the allocated memory address, which re-uses part of the wasm
* address space and is in the range of [UINT32 - shared_heap_size + 1, UINT32]
* (when the wasm memory is 32-bit) or [UINT64 - shared_heap_size + 1, UINT64]
* (when the wasm memory is 64-bit). Note that it is not an absolute address.
* Return non-zero if success, zero if failed.
*/
WASM_RUNTIME_API_EXTERN uint64_t
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
*
* @param module_inst the module instance
* @param ptr the offset in wasm app
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_shared_heap_free(wasm_module_inst_t module_inst, uint64_t ptr);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -46,6 +46,28 @@ typedef float64 CellType_F64;
#define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory)
#endif #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 WASM_ENABLE_MEMORY64 == 0
#if (!defined(OS_ENABLE_HW_BOUND_CHECK) \ #if (!defined(OS_ENABLE_HW_BOUND_CHECK) \
@ -53,6 +75,7 @@ typedef float64 CellType_F64;
#define CHECK_MEMORY_OVERFLOW(bytes) \ #define CHECK_MEMORY_OVERFLOW(bytes) \
do { \ do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \ uint64 offset1 = (uint64)offset + (uint64)addr; \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
/* If offset1 is in valid range, maddr must also \ /* If offset1 is in valid range, maddr must also \
be in valid range, no need to check it again. */ \ be in valid range, no need to check it again. */ \
@ -64,6 +87,7 @@ typedef float64 CellType_F64;
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \ do { \
uint64 offset1 = (uint32)(start); \ uint64 offset1 = (uint32)(start); \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
/* App heap space is not valid space for \ /* App heap space is not valid space for \
bulk memory operation */ \ bulk memory operation */ \
@ -71,18 +95,24 @@ typedef float64 CellType_F64;
else \ else \
goto out_of_bounds; \ goto out_of_bounds; \
} while (0) } while (0)
#else /* else of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ #else /* else of !defined(OS_ENABLE_HW_BOUND_CHECK) || \
WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
#define CHECK_MEMORY_OVERFLOW(bytes) \ #define CHECK_MEMORY_OVERFLOW(bytes) \
do { \ do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \ uint64 offset1 = (uint64)offset + (uint64)addr; \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
maddr = memory->memory_data + offset1; \ maddr = memory->memory_data + offset1; \
} while (0) } while (0)
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \ do { \
maddr = memory->memory_data + (uint32)(start); \ uint64 offset1 = (uint32)(start); \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
maddr = memory->memory_data + offset1; \
} while (0) } while (0)
#endif /* end of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ #endif /* end of !defined(OS_ENABLE_HW_BOUND_CHECK) || \
WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
@ -91,6 +121,7 @@ typedef float64 CellType_F64;
#define CHECK_MEMORY_OVERFLOW(bytes) \ #define CHECK_MEMORY_OVERFLOW(bytes) \
do { \ do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \ uint64 offset1 = (uint64)offset + (uint64)addr; \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
/* If memory64 is enabled, offset1, offset1 + bytes can overflow */ \ /* If memory64 is enabled, offset1, offset1 + bytes can overflow */ \
if (disable_bounds_checks \ if (disable_bounds_checks \
|| (offset1 >= offset && offset1 + bytes >= offset1 \ || (offset1 >= offset && offset1 + bytes >= offset1 \
@ -99,9 +130,11 @@ typedef float64 CellType_F64;
else \ else \
goto out_of_bounds; \ goto out_of_bounds; \
} while (0) } while (0)
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \ do { \
uint64 offset1 = (uint64)(start); \ uint64 offset1 = (uint64)(start); \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
/* If memory64 is enabled, offset1 + bytes can overflow */ \ /* If memory64 is enabled, offset1 + bytes can overflow */ \
if (disable_bounds_checks \ if (disable_bounds_checks \
|| (offset1 + bytes >= offset1 \ || (offset1 + bytes >= offset1 \
@ -1611,6 +1644,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
if (memory) if (memory)
is_memory64 = memory->is_memory64; is_memory64 = memory->is_memory64;
#endif #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 #if WASM_ENABLE_MULTI_MEMORY != 0
uint32 memidx = 0; uint32 memidx = 0;
uint32 memidx_cached = (uint32)-1; uint32 memidx_cached = (uint32)-1;
@ -3472,8 +3521,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
str_obj = (WASMString)wasm_stringref_obj_get_value( str_obj = (WASMString)wasm_stringref_obj_get_value(
stringref_obj); stringref_obj);
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)addr, 1))
shared_heap_addr_app_to_native((uint64)addr, maddr);
else
#endif
{
memory_inst = module->memories[mem_idx]; memory_inst = module->memories[mem_idx];
maddr = memory_inst->memory_data + addr; maddr = memory_inst->memory_data + addr;
}
if (opcode == WASM_OP_STRING_ENCODE_WTF16) { if (opcode == WASM_OP_STRING_ENCODE_WTF16) {
flag = WTF16; flag = WTF16;
@ -3640,8 +3696,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
addr = POP_I32(); addr = POP_I32();
stringview_wtf8_obj = POP_REF(); stringview_wtf8_obj = POP_REF();
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)addr, 1))
shared_heap_addr_app_to_native((uint64)addr, maddr);
else
#endif
{
memory_inst = module->memories[mem_idx]; memory_inst = module->memories[mem_idx];
maddr = memory_inst->memory_data + addr; maddr = memory_inst->memory_data + addr;
}
bytes_written = wasm_string_encode( bytes_written = wasm_string_encode(
(WASMString)wasm_stringview_wtf8_obj_get_value( (WASMString)wasm_stringview_wtf8_obj_get_value(
@ -5674,9 +5737,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
#else #else
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)(uint32)addr,
bytes))
shared_heap_addr_app_to_native((uint64)(uint32)addr,
maddr);
else
#endif
{
if ((uint64)(uint32)addr + bytes > linear_mem_size) if ((uint64)(uint32)addr + bytes > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
maddr = memory->memory_data + (uint32)addr; maddr = memory->memory_data + (uint32)addr;
}
#endif #endif
if (bh_bitmap_get_bit(module->e->common.data_dropped, if (bh_bitmap_get_bit(module->e->common.data_dropped,
@ -5726,15 +5798,30 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
linear_mem_size = get_linear_mem_size(); linear_mem_size = get_linear_mem_size();
#endif #endif
dlen = linear_mem_size - dst;
/* dst boundary check */ /* dst boundary check */
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else #if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)dst, len))
dlen = shared_heap_end_off - dst + 1;
#endif
#else /* else of OS_ENABLE_HW_BOUND_CHECK */
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)dst, len)) {
shared_heap_addr_app_to_native((uint64)dst, mdst);
dlen = shared_heap_end_off - dst + 1;
}
else
#endif
{
if ((uint64)dst + len > linear_mem_size) if ((uint64)dst + len > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
mdst = memory->memory_data + dst; mdst = memory->memory_data + dst;
#endif }
dlen = linear_mem_size - dst; #endif /* end of OS_ENABLE_HW_BOUND_CHECK */
#if WASM_ENABLE_MULTI_MEMORY != 0 #if WASM_ENABLE_MULTI_MEMORY != 0
/* src memidx */ /* src memidx */
@ -5750,9 +5837,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
#else #else
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)src, len))
shared_heap_addr_app_to_native((uint64)src, msrc);
else
#endif
{
if ((uint64)src + len > linear_mem_size) if ((uint64)src + len > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
msrc = memory->memory_data + src; msrc = memory->memory_data + src;
}
#endif #endif
#if WASM_ENABLE_MEMORY64 == 0 #if WASM_ENABLE_MEMORY64 == 0
@ -5789,9 +5883,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else #else
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)(uint32)dst, len))
shared_heap_addr_app_to_native((uint64)(uint32)dst,
mdst);
else
#endif
{
if ((uint64)(uint32)dst + len > linear_mem_size) if ((uint64)(uint32)dst + len > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst; mdst = memory->memory_data + (uint32)dst;
}
#endif #endif
memset(mdst, fill_val, len); memset(mdst, fill_val, len);

View File

@ -37,11 +37,28 @@ typedef float64 CellType_F64;
#define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory)
#endif #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) \ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#define CHECK_MEMORY_OVERFLOW(bytes) \ #define CHECK_MEMORY_OVERFLOW(bytes) \
do { \ do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \ uint64 offset1 = (uint64)offset + (uint64)addr; \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
/* If offset1 is in valid range, maddr must also \ /* If offset1 is in valid range, maddr must also \
be in valid range, no need to check it again. */ \ be in valid range, no need to check it again. */ \
@ -53,6 +70,7 @@ typedef float64 CellType_F64;
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \ do { \
uint64 offset1 = (uint32)(start); \ uint64 offset1 = (uint32)(start); \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \ if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
/* App heap space is not valid space for \ /* App heap space is not valid space for \
bulk memory operation */ \ bulk memory operation */ \
@ -64,12 +82,15 @@ typedef float64 CellType_F64;
#define CHECK_MEMORY_OVERFLOW(bytes) \ #define CHECK_MEMORY_OVERFLOW(bytes) \
do { \ do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \ uint64 offset1 = (uint64)offset + (uint64)addr; \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
maddr = memory->memory_data + offset1; \ maddr = memory->memory_data + offset1; \
} while (0) } while (0)
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \ do { \
maddr = memory->memory_data + (uint32)(start); \ uint64 offset1 = (uint32)(start); \
CHECK_SHARED_HEAP_OVERFLOW(offset1, bytes, maddr) \
maddr = memory->memory_data + offset1; \
} while (0) } while (0)
#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \ #endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
@ -1516,6 +1537,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
bool is_return_call = false; bool is_return_call = false;
#endif #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;
/* #endif */
#endif /* end of WASM_ENABLE_SHARED_HEAP != 0 */
#if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_ENABLE_LABELS_AS_VALUES != 0
#define HANDLE_OPCODE(op) &&HANDLE_##op #define HANDLE_OPCODE(op) &&HANDLE_##op
@ -2831,8 +2870,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
str_obj = (WASMString)wasm_stringref_obj_get_value( str_obj = (WASMString)wasm_stringref_obj_get_value(
stringref_obj); stringref_obj);
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)addr, 1))
shared_heap_addr_app_to_native((uint64)addr, maddr);
else
#endif
{
memory_inst = module->memories[mem_idx]; memory_inst = module->memories[mem_idx];
maddr = memory_inst->memory_data + addr; maddr = memory_inst->memory_data + addr;
}
if (opcode == WASM_OP_STRING_ENCODE_WTF16) { if (opcode == WASM_OP_STRING_ENCODE_WTF16) {
flag = WTF16; flag = WTF16;
@ -2999,8 +3045,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
addr = POP_I32(); addr = POP_I32();
stringview_wtf8_obj = POP_REF(); stringview_wtf8_obj = POP_REF();
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)addr, 1))
shared_heap_addr_app_to_native((uint64)addr, maddr);
else
#endif
{
memory_inst = module->memories[mem_idx]; memory_inst = module->memories[mem_idx];
maddr = memory_inst->memory_data + addr; maddr = memory_inst->memory_data + addr;
}
bytes_written = wasm_string_encode( bytes_written = wasm_string_encode(
(WASMString)wasm_stringview_wtf8_obj_get_value( (WASMString)wasm_stringview_wtf8_obj_get_value(
@ -4985,9 +5038,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
#else #else
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)(uint32)addr,
bytes))
shared_heap_addr_app_to_native((uint64)(uint32)addr,
maddr);
else
#endif
{
if ((uint64)(uint32)addr + bytes > linear_mem_size) if ((uint64)(uint32)addr + bytes > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
maddr = memory->memory_data + (uint32)addr; maddr = memory->memory_data + (uint32)addr;
}
#endif #endif
if (bh_bitmap_get_bit(module->e->common.data_dropped, if (bh_bitmap_get_bit(module->e->common.data_dropped,
segment)) { segment)) {
@ -5020,6 +5082,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
{ {
uint32 dst, src, len; uint32 dst, src, len;
uint8 *mdst, *msrc; uint8 *mdst, *msrc;
uint64 dlen;
len = POP_I32(); len = POP_I32();
src = POP_I32(); src = POP_I32();
@ -5029,22 +5092,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
linear_mem_size = get_linear_mem_size(); linear_mem_size = get_linear_mem_size();
#endif #endif
dlen = linear_mem_size - dst;
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else #if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)dst, len))
dlen = shared_heap_end_off - dst + 1;
#endif
#else /* else of OS_ENABLE_HW_BOUND_CHECK */
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)src, len))
shared_heap_addr_app_to_native((uint64)src, msrc);
else
#endif
{
if ((uint64)(uint32)src + len > linear_mem_size) if ((uint64)(uint32)src + len > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
msrc = memory->memory_data + (uint32)src; msrc = memory->memory_data + (uint32)src;
}
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)dst, len)) {
shared_heap_addr_app_to_native((uint64)dst, mdst);
dlen = shared_heap_end_off - dst + 1;
}
else
#endif
{
if ((uint64)(uint32)dst + len > linear_mem_size) if ((uint64)(uint32)dst + len > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst; mdst = memory->memory_data + (uint32)dst;
#endif }
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
/* allowing the destination and source to overlap */ /* allowing the destination and source to overlap */
bh_memmove_s(mdst, (uint32)(linear_mem_size - dst), bh_memmove_s(mdst, (uint32)dlen, msrc, len);
msrc, len);
break; break;
} }
case WASM_OP_MEMORY_FILL: case WASM_OP_MEMORY_FILL:
@ -5063,9 +5147,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#ifndef OS_ENABLE_HW_BOUND_CHECK #ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else #else
#if WASM_ENABLE_SHARED_HEAP != 0
if (app_addr_in_shared_heap((uint64)(uint32)dst, len))
shared_heap_addr_app_to_native((uint64)(uint32)dst,
mdst);
else
#endif
{
if ((uint64)(uint32)dst + len > linear_mem_size) if ((uint64)(uint32)dst + len > linear_mem_size)
goto out_of_bounds; goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst; mdst = memory->memory_data + (uint32)dst;
}
#endif #endif
memset(mdst, fill_val, len); memset(mdst, fill_val, len);

View File

@ -5379,6 +5379,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
option.enable_memory_profiling = true; option.enable_memory_profiling = true;
option.enable_stack_estimation = true; option.enable_stack_estimation = true;
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
option.enable_shared_heap = true;
#endif
module->comp_ctx = aot_create_comp_context(module->comp_data, &option); module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
if (!module->comp_ctx) { if (!module->comp_ctx) {

View File

@ -2216,6 +2216,9 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf,
option.enable_memory_profiling = true; option.enable_memory_profiling = true;
option.enable_stack_estimation = true; option.enable_stack_estimation = true;
#endif #endif
#if WASM_ENABLE_SHARED_HEAP != 0
option.enable_shared_heap = true;
#endif
module->comp_ctx = aot_create_comp_context(module->comp_data, &option); module->comp_ctx = aot_create_comp_context(module->comp_data, &option);
if (!module->comp_ctx) { if (!module->comp_ctx) {

View File

@ -2798,6 +2798,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
} }
} }
#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_SHARED_HEAP != 0
#if UINTPTR_MAX == UINT64_MAX
module_inst->e->shared_heap_start_off.u64 = UINT64_MAX;
#else
module_inst->e->shared_heap_start_off.u32[0] = UINT32_MAX;
#endif
#endif
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
/* Initialize the table data with init expr */ /* Initialize the table data with init expr */
for (i = 0; i < module->table_count; i++) { for (i = 0; i < module->table_count; i++) {

View File

@ -92,6 +92,15 @@ typedef union {
uint32 u32[2]; uint32 u32[2];
} MemBound; } MemBound;
typedef struct WASMSharedHeap {
struct WASMSharedHeap *next;
void *heap_handle;
uint8 *base_addr;
uint64 size;
uint64 start_off_mem64;
uint64 start_off_mem32;
} WASMSharedHeap;
struct WASMMemoryInstance { struct WASMMemoryInstance {
/* Module type */ /* Module type */
uint32 module_type; uint32 module_type;
@ -354,6 +363,19 @@ typedef struct WASMModuleInstanceExtra {
uint32 max_aux_stack_used; uint32 max_aux_stack_used;
#endif #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:
* shared_heap->base_addr - shared_heap->start_off
*/
uint8 *shared_heap_base_addr_adj;
MemBound shared_heap_start_off;
#endif
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0 \ #if WASM_ENABLE_DEBUG_INTERP != 0 \
|| (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \
&& WASM_ENABLE_LAZY_JIT != 0) && WASM_ENABLE_LAZY_JIT != 0)

View File

@ -0,0 +1,8 @@
# Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (LIB_SHARED_HEAP ${CMAKE_CURRENT_LIST_DIR})
add_definitions (-DWASM_ENABLE_SHARED_HEAP=1)
include_directories(${LIB_SHARED_HEAP_DIR})
file (GLOB source_all ${LIB_SHARED_HEAP}/*.c)
set (LIB_SHARED_HEAP_SOURCE ${source_all})

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_common.h"
#include "bh_log.h"
#include "wasm_export.h"
#include "../interpreter/wasm.h"
#include "../common/wasm_runtime_common.h"
/* clang-format off */
#define validate_native_addr(addr, size) \
wasm_runtime_validate_native_addr(module_inst, addr, size)
#define module_shared_malloc(size, p_native_addr) \
wasm_runtime_shared_heap_malloc(module_inst, size, p_native_addr)
#define module_shared_free(offset) \
wasm_runtime_shared_heap_free(module_inst, offset)
/* clang-format on */
static uint32
shared_heap_malloc_wrapper(wasm_exec_env_t exec_env, uint32 size)
{
wasm_module_inst_t module_inst = get_module_inst(exec_env);
return (uint32)module_shared_malloc((uint64)size, NULL);
}
static void
shared_heap_free_wrapper(wasm_exec_env_t exec_env, void *ptr)
{
wasm_module_inst_t module_inst = get_module_inst(exec_env);
if (!validate_native_addr(ptr, (uint64)sizeof(uintptr_t))) {
LOG_WARNING("Invalid app address");
return;
}
module_shared_free(addr_native_to_app(ptr));
}
/* clang-format off */
#define REG_NATIVE_FUNC(func_name, signature) \
{ #func_name, func_name##_wrapper, signature, NULL }
/* clang-format on */
static NativeSymbol native_symbols_shared_heap[] = {
REG_NATIVE_FUNC(shared_heap_malloc, "(i)i"),
REG_NATIVE_FUNC(shared_heap_free, "(*)"),
};
uint32
get_lib_shared_heap_export_apis(NativeSymbol **p_shared_heap_apis)
{
*p_shared_heap_apis = native_symbols_shared_heap;
return sizeof(native_symbols_shared_heap) / sizeof(NativeSymbol);
}

View File

@ -1402,6 +1402,82 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst,
} }
} }
#if WASM_ENABLE_SHARED_HEAP != 0
static void
attach_shared_heap_visitor(void *node, void *heap)
{
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env);
wasm_runtime_attach_shared_heap_internal(module_inst, heap);
}
static void
detach_shared_heap_visitor(void *node, void *heap)
{
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env);
(void)heap;
wasm_runtime_detach_shared_heap_internal(module_inst);
}
bool
wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
WASMSharedHeap *heap)
{
WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst);
if (exec_env == NULL) {
/* Maybe threads have not been started yet. */
return wasm_runtime_attach_shared_heap_internal(module_inst, heap);
}
else {
WASMCluster *cluster;
cluster = wasm_exec_env_get_cluster(exec_env);
bh_assert(cluster);
os_mutex_lock(&cluster->lock);
/* Try attaching shared heap to this module instance first
to ensure that we can attach it to all other instances. */
if (!wasm_runtime_attach_shared_heap_internal(module_inst, heap)) {
os_mutex_unlock(&cluster->lock);
return false;
}
/* Detach the shared heap so it can be attached again. */
wasm_runtime_detach_shared_heap_internal(module_inst);
traverse_list(&cluster->exec_env_list, attach_shared_heap_visitor,
heap);
os_mutex_unlock(&cluster->lock);
}
return true;
}
void
wasm_cluster_detach_shared_heap(WASMModuleInstanceCommon *module_inst)
{
WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst);
if (exec_env == NULL) {
/* Maybe threads have not been started yet. */
wasm_runtime_detach_shared_heap_internal(module_inst);
}
else {
WASMCluster *cluster;
cluster = wasm_exec_env_get_cluster(exec_env);
bh_assert(cluster);
os_mutex_lock(&cluster->lock);
traverse_list(&cluster->exec_env_list, detach_shared_heap_visitor,
NULL);
os_mutex_unlock(&cluster->lock);
}
}
#endif
#if WASM_ENABLE_MODULE_INST_CONTEXT != 0 #if WASM_ENABLE_MODULE_INST_CONTEXT != 0
struct inst_set_context_data { struct inst_set_context_data {
void *key; void *key;

View File

@ -11,6 +11,9 @@
#include "wasm_export.h" #include "wasm_export.h"
#include "../interpreter/wasm.h" #include "../interpreter/wasm.h"
#include "../common/wasm_runtime_common.h" #include "../common/wasm_runtime_common.h"
#if WASM_ENABLE_SHARED_HEAP != 0
#include "../common/wasm_memory.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -167,6 +170,15 @@ wasm_cluster_set_context(WASMModuleInstanceCommon *module_inst, void *key,
bool bool
wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env); wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env);
#if WASM_ENABLE_SHARED_HEAP != 0
bool
wasm_cluster_attach_shared_heap(WASMModuleInstanceCommon *module_inst,
WASMSharedHeap *heap);
void
wasm_cluster_detach_shared_heap(WASMModuleInstanceCommon *module_inst);
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_DEBUG_INTERP != 0
#define WAMR_SIG_TRAP (5) #define WAMR_SIG_TRAP (5)
#define WAMR_SIG_STOP (19) #define WAMR_SIG_STOP (19)

View File

@ -300,6 +300,22 @@ Currently we only profile the memory consumption of module, module_instance and
wasm_runtime_get_context wasm_runtime_get_context
``` ```
#### **Shared heap among wasm apps and host native**
- **WAMR_BUILD_SHARED_HEAP**=1/0, default to disable if not set
> Note: If it is enabled, allow to create one or more shared heaps, and attach one to a module instance, the belows APIs ared provided:
```C
wasm_runtime_create_shared_heap
wasm_runtime_attach_shared_heap
wasm_runtime_detach_shared_heap
wasm_runtime_shared_heap_malloc
wasm_runtime_shared_heap_free
```
And the wasm app can calls below APIs to allocate/free memory from/to the shared heap if it is attached to the app's module instance:
```C
void *shared_heap_malloc();
void shared_heap_free(void *ptr);
```
**Combination of configurations:** **Combination of configurations:**
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:

View File

@ -0,0 +1,127 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 3.14)
include(CheckPIESupported)
if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows")
project (shared_heap_test)
else()
project (shared_heap_test C ASM)
endif()
################ runtime settings ################
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
if (APPLE)
add_definitions(-DBH_PLATFORM_DARWIN)
endif ()
# Reset default linker flags
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
# WAMR features switch
# Set WAMR_BUILD_TARGET, currently values supported:
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
if (NOT DEFINED WAMR_BUILD_TARGET)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
set (WAMR_BUILD_TARGET "AARCH64")
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
set (WAMR_BUILD_TARGET "RISCV64")
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
# Build as X86_64 by default in 64-bit platform
set (WAMR_BUILD_TARGET "X86_64")
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
# Build as X86_32 by default in 32-bit platform
set (WAMR_BUILD_TARGET "X86_32")
else ()
message(SEND_ERROR "Unsupported build target platform!")
endif ()
endif ()
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Debug)
endif ()
set (WAMR_BUILD_INTERP 1)
set (WAMR_BUILD_FAST_INTERP 1)
set (WAMR_BUILD_AOT 1)
set (WAMR_BUILD_JIT 0)
set (WAMR_BUILD_LIBC_BUILTIN 1)
set (WAMR_BUILD_LIBC_WASI 0)
set (WAMR_BUILD_SHARED_HEAP 1)
set (WAMR_BUILD_GC_HEAP_VERIFY 1)
if (NOT MSVC)
# linker flags
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
endif ()
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
endif ()
endif ()
endif ()
# build out vmlib
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE})
if (MSVC)
target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=)
endif()
target_link_libraries(vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread)
################ application related ################
include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
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)
else ()
target_link_libraries (shared_heap_test vmlib -lm -ldl -lpthread -lrt)
endif ()
add_subdirectory(wasm-apps)
if (WAMR_BUILD_AOT EQUAL 1)
set (WAMR_COMPILER_DIR ${CMAKE_CURRENT_LIST_DIR}/../../wamr-compiler/build)
message (CHECK_START "Detecting WAMR_COMPILER at ${WAMR_COMPILER_DIR}")
find_file (WAMR_COMPILER
wamrc
PATHS "${CMAKE_CURRENT_LIST_DIR}/../../wamr-compiler/build"
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
if (WAMR_COMPILER)
message (CHECK_PASS "found")
else()
message (CHECK_FAIL "not found")
endif()
if (NOT EXISTS ${WAMR_COMPILER})
message (FATAL_ERROR "Please build wamrc under ${WAMR_ROOT_DIR}/wamr-compiler")
else()
message (STATUS "WAMR_COMPILER is ${WAMR_COMPILER}")
endif()
add_custom_target(
wasm_to_aot
ALL
DEPENDS wasm-apps/test1.wasm wasm-apps/test2.wasm ${WAMR_COMPILER}
COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test1.aot wasm-apps/test1.wasm
COMMAND ${WAMR_COMPILER} --enable-shared-heap -o wasm-apps/test2.aot wasm-apps/test2.wasm
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()

View File

@ -0,0 +1,328 @@
/*
* 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"
typedef struct thread_arg {
bh_queue *queue;
wasm_module_inst_t module_inst;
} thread_arg;
static void *
thread1_callback(void *arg)
{
thread_arg *targ = arg;
wasm_module_inst_t module_inst = targ->module_inst;
bh_queue *queue = targ->queue;
wasm_exec_env_t exec_env;
wasm_function_inst_t my_shared_heap_malloc_func;
wasm_function_inst_t my_shared_heap_free_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"))) {
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 with wasm_runtime_shared_heap_malloc and send it
to wasm app2 */
for (i = 0; i < 5; i++) {
uint8 *buf;
uint64 offset;
offset = wasm_runtime_shared_heap_malloc(module_inst, 1024 * (i + 1),
(void **)&buf);
if (offset == 0) {
printf("Failed to allocate memory from shared heap\n");
break;
}
snprintf(buf, 1024, "Hello, this is buf %u allocated from shared heap",
i + 1);
printf("wasm app1 send buf: %s\n\n", buf);
if (!bh_post_msg(queue, 1, buf, 1024 * i)) {
printf("Failed to post message to queue\n");
wasm_runtime_shared_heap_free(module_inst, offset);
break;
}
}
/* allocate memory by calling my_shared_heap_malloc function and send it
to wasm app2 */
for (i = 5; i < 10; i++) {
uint8 *buf;
argv[0] = 1024 * (i + 1);
argv[1] = i + 1;
wasm_runtime_call_wasm(exec_env, my_shared_heap_malloc_func, 2, argv);
if (wasm_runtime_get_exception(module_inst)) {
printf("Failed to call 'my_shared_heap_malloc' function: %s\n",
wasm_runtime_get_exception(module_inst));
break;
}
if (argv[0] == 0) {
printf("Failed to allocate memory from shared heap\n");
break;
}
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)) {
printf("Failed to post message to queue\n");
wasm_runtime_shared_heap_free(module_inst, argv[0]);
break;
}
}
wasm_runtime_destroy_exec_env(exec_env);
return NULL;
}
static void
queue_callback(void *message, void *arg)
{
bh_message_t msg = (bh_message_t)message;
wasm_exec_env_t exec_env = arg;
wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
wasm_function_inst_t print_buf_func;
uint32 argv[2];
/* lookup wasm function */
if (!(print_buf_func =
wasm_runtime_lookup_function(module_inst, "print_buf"))) {
printf("Failed to lookup function.\n");
return;
}
char *buf = bh_message_payload(msg);
printf("wasm app's native queue received buf: %s\n\n", buf);
/* call wasm function */
argv[0] = wasm_runtime_addr_native_to_app(module_inst, buf);
wasm_runtime_call_wasm(exec_env, print_buf_func, 1, argv);
if (wasm_runtime_get_exception(module_inst)) {
printf("Failed to call 'print_buf' function: %s\n",
wasm_runtime_get_exception(module_inst));
}
}
static void *
thread2_callback(void *arg)
{
thread_arg *targ = arg;
bh_queue *queue = targ->queue;
wasm_module_inst_t module_inst = targ->module_inst;
wasm_exec_env_t exec_env;
/* create exec env */
if (!(exec_env = wasm_runtime_create_exec_env(module_inst, 32768))) {
printf("Failed to create exec env.\n");
return NULL;
}
/* enter queue's message loop until bh_queue_exit_loop_run
is called */
bh_queue_enter_loop_run(queue, queue_callback, exec_env);
wasm_runtime_destroy_exec_env(exec_env);
return NULL;
}
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;
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.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.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. error: %s\n", error_buf);
goto fail;
}
/* attach module instance 1 to the shared heap */
if (!wasm_runtime_attach_shared_heap(module_inst1, shared_heap)) {
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)) {
printf("Attach shared heap failed.\n");
goto fail;
}
/* create thread 1 */
struct thread_arg targ1 = { 0 };
korp_tid tid1;
targ1.queue = queue;
targ1.module_inst = module_inst1;
if (os_thread_create(&tid1, thread1_callback, &targ1,
APP_THREAD_STACK_SIZE_DEFAULT)) {
printf("Failed to create thread 1\n");
goto fail;
}
/* create thread 2 */
struct thread_arg targ2 = { 0 };
korp_tid tid2;
targ2.queue = queue;
targ2.module_inst = module_inst2;
if (os_thread_create(&tid2, thread2_callback, &targ2,
APP_THREAD_STACK_SIZE_DEFAULT)) {
printf("Failed to create thread 2\n");
os_thread_join(tid1, NULL);
goto fail;
}
/* wait until all messages are post to wasm app2 and wasm app2
handles all of them, then exit the queue message loop */
usleep(10000);
bh_queue_exit_loop_run(queue);
os_thread_join(tid1, NULL);
os_thread_join(tid2, NULL);
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;
}

View File

@ -0,0 +1,43 @@
# 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)
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
if (APPLE)
set (HAVE_FLAG_SEARCH_PATHS_FIRST 0)
set (CMAKE_C_LINK_FLAGS "")
set (CMAKE_CXX_LINK_FLAGS "")
endif ()
set (CMAKE_SYSTEM_PROCESSOR wasm32)
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 -Qunused-arguments -z stack-size=32768")
set (CMAKE_C_COMPILER_TARGET "wasm32")
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
"-O0 -Wl,--initial-memory=65536, \
-Wl,--no-entry,--strip-all, \
-Wl,--export=__heap_base,--export=__data_end \
-Wl,--export=__wasm_call_ctors \
-Wl,--export=my_shared_heap_malloc \
-Wl,--export=my_shared_heap_free \
-Wl,--export=print_buf \
-Wl,--allow-undefined"
)
add_executable(test1.wasm test1.c)
target_link_libraries(test1.wasm)
add_executable(test2.wasm test2.c)
target_link_libraries(test2.wasm)

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
extern void *
shared_heap_malloc(uint32_t size);
extern void
shared_heap_free(void *ptr);
void *
my_shared_heap_malloc(uint32_t size, uint32_t index)
{
char *buf1 = NULL, *buf2 = NULL, *buf;
buf1 = shared_heap_malloc(128);
if (!buf1)
return NULL;
buf1[0] = 'H';
buf1[1] = 'e';
buf1[2] = 'l';
buf1[3] = 'l';
buf1[4] = 'o';
buf1[5] = ',';
buf1[6] = ' ';
buf2 = shared_heap_malloc(128);
if (!buf2) {
shared_heap_free(buf1);
return NULL;
}
snprintf(buf2, 128, "this is buf %u allocated from shared heap", index);
buf = shared_heap_malloc(size);
if (!buf) {
shared_heap_free(buf1);
shared_heap_free(buf2);
return NULL;
}
memset(buf, 0, size);
memcpy(buf, buf1, strlen(buf1));
memcpy(buf + strlen(buf1), buf2, strlen(buf2));
shared_heap_free(buf1);
shared_heap_free(buf2);
return buf;
}
void
my_shared_heap_free(void *ptr)
{
shared_heap_free(ptr);
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <stdio.h>
extern void
shared_heap_free(void *ptr);
void
print_buf(char *buf)
{
printf("wasm app2's wasm func received buf: %s\n\n", buf);
shared_heap_free(buf);
}

View File

@ -50,3 +50,4 @@ add_subdirectory(linux-perf)
add_subdirectory(gc) add_subdirectory(gc)
add_subdirectory(memory64) add_subdirectory(memory64)
add_subdirectory(tid-allocator) add_subdirectory(tid-allocator)
add_subdirectory(shared-heap)

View File

@ -0,0 +1,59 @@
# Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required(VERSION 3.14)
project(test-shared-heap)
add_definitions(-DRUN_ON_LINUX)
set(WAMR_BUILD_APP_FRAMEWORK 0)
set(WAMR_BUILD_AOT 0)
set(WAMR_BUILD_INTERP 1)
set(WAMR_BUILD_FAST_INTERP 1)
set(WAMR_BUILD_JIT 0)
set(WAMR_BUILD_MEMORY64 1)
set(WAMR_BUILD_SHARED_HEAP 1)
# Compile wasm modules
add_subdirectory(wasm-apps)
# if only load this CMake other than load it as subdirectory
include(../unit_common.cmake)
set(LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm")
if (NOT EXISTS "${LLVM_SRC_ROOT}/build")
message(FATAL_ERROR "Cannot find LLVM dir: ${LLVM_SRC_ROOT}/build")
endif ()
set(CMAKE_PREFIX_PATH "${LLVM_SRC_ROOT}/build;${CMAKE_PREFIX_PATH}")
find_package(LLVM REQUIRED CONFIG)
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include(${IWASM_DIR}/compilation/iwasm_compl.cmake)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
file(GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
set(UNIT_SOURCE ${source_all})
aux_source_directory(. SRC_LIST)
set(unit_test_sources
${UNIT_SOURCE}
${WAMR_RUNTIME_LIB_SOURCE}
${UNCOMMON_SHARED_SOURCE}
${SRC_LIST}
)
# Now simply link against gtest or gtest_main as needed. Eg
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)

View File

@ -0,0 +1,142 @@
/*
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "test_helper.h"
#include "gtest/gtest.h"
#include "bh_read_file.h"
#include "wasm_runtime_common.h"
class shared_heap_test : public testing::Test
{
protected:
virtual void SetUp() {}
static void SetUpTestCase() {}
virtual void TearDown() {}
WAMRRuntimeRAII<512 * 1024> runtime;
};
struct ret_env {
wasm_exec_env_t exec_env;
wasm_module_t wasm_module;
wasm_module_inst_t wasm_module_inst;
unsigned char *wasm_file_buf;
char error_buf[128];
};
struct ret_env
load_wasm(char *wasm_file_tested, unsigned int app_heap_size)
{
std::string wasm_mem_page = wasm_file_tested;
const char *wasm_file = strdup(wasm_mem_page.c_str());
wasm_module_inst_t wasm_module_inst = nullptr;
wasm_module_t wasm_module = nullptr;
wasm_exec_env_t exec_env = nullptr;
unsigned char *wasm_file_buf = nullptr;
unsigned int wasm_file_size = 0;
unsigned int stack_size = 16 * 1024, heap_size = app_heap_size;
char error_buf[128] = { 0 };
struct ret_env ret_module_env;
memset(ret_module_env.error_buf, 0, 128);
wasm_file_buf =
(unsigned char *)bh_read_file_to_buffer(wasm_file, &wasm_file_size);
if (!wasm_file_buf) {
goto fail;
}
wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf,
sizeof(error_buf));
if (!wasm_module) {
memcpy(ret_module_env.error_buf, error_buf, 128);
goto fail;
}
wasm_module_inst = wasm_runtime_instantiate(
wasm_module, stack_size, heap_size, error_buf, sizeof(error_buf));
if (!wasm_module_inst) {
memcpy(ret_module_env.error_buf, error_buf, 128);
goto fail;
}
exec_env = wasm_runtime_create_exec_env(wasm_module_inst, stack_size);
fail:
ret_module_env.exec_env = exec_env;
ret_module_env.wasm_module = wasm_module;
ret_module_env.wasm_module_inst = wasm_module_inst;
ret_module_env.wasm_file_buf = wasm_file_buf;
return ret_module_env;
}
void
destroy_module_env(struct ret_env module_env)
{
if (module_env.exec_env) {
wasm_runtime_destroy_exec_env(module_env.exec_env);
}
if (module_env.wasm_module_inst) {
wasm_runtime_deinstantiate(module_env.wasm_module_inst);
}
if (module_env.wasm_module) {
wasm_runtime_unload(module_env.wasm_module);
}
if (module_env.wasm_file_buf) {
wasm_runtime_free(module_env.wasm_file_buf);
}
}
TEST_F(shared_heap_test, test_shared_heap)
{
struct ret_env tmp_module_env;
WASMFunctionInstanceCommon *func_test = nullptr;
bool ret = false;
uint32 argv[1] = { 65535 };
const char *exception = nullptr;
SharedHeapInitArgs args;
WASMSharedHeap *shared_heap = nullptr;
args.size = 1024;
shared_heap = wasm_runtime_create_shared_heap(&args);
tmp_module_env = load_wasm((char *)"test.wasm", 0);
if (!shared_heap) {
printf("Failed to create shared heap\n");
goto test_failed;
}
if (!wasm_runtime_attach_shared_heap(tmp_module_env.wasm_module_inst, shared_heap)) {
printf("Failed to attach shared heap\n");
goto test_failed;
}
func_test = wasm_runtime_lookup_function(
tmp_module_env.wasm_module_inst, "test");
if (!func_test) {
printf("\nFailed to wasm_runtime_lookup_function!\n");
goto test_failed;
}
ret =
wasm_runtime_call_wasm(tmp_module_env.exec_env, func_test, 1, argv);
if (!ret) {
printf("\nFailed to wasm_runtime_call_wasm!\n");
const char *s = wasm_runtime_get_exception(tmp_module_env.wasm_module_inst);
printf("exception: %s\n", s);
goto test_failed;
}
wasm_runtime_detach_shared_heap(tmp_module_env.wasm_module_inst);
EXPECT_EQ(10, argv[0]);
destroy_module_env(tmp_module_env);
return;
test_failed:
destroy_module_env(tmp_module_env);
EXPECT_EQ(1, 0);
}

View File

@ -0,0 +1,39 @@
# Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required(VERSION 3.14)
project(wasm-apps)
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
set(CMAKE_SYSTEM_PROCESSOR wasm32)
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")
set(CMAKE_C_COMPILER_TARGET "wasm32")
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"
)
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"
)

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
extern void *
shared_heap_malloc(int size);
extern void
shared_heap_free(void *offset);
int
test()
{
int *ptr = (int *)shared_heap_malloc(10);
*ptr = 10;
int a = *ptr;
shared_heap_free(ptr);
return a;
}

View File

@ -206,6 +206,7 @@ print_help()
printf(" --enable-linux-perf Enable linux perf support\n"); printf(" --enable-linux-perf Enable linux perf support\n");
#endif #endif
printf(" --mllvm=<option> Add the LLVM command line option\n"); printf(" --mllvm=<option> Add the LLVM command line option\n");
printf(" --enable-shared-heap Enable shared heap feature\n");
printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n"); printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
printf(" --version Show version information\n"); printf(" --version Show version information\n");
printf("Examples: wamrc -o test.aot test.wasm\n"); printf("Examples: wamrc -o test.aot test.wasm\n");
@ -647,6 +648,9 @@ main(int argc, char *argv[])
llvm_options[llvm_options_count - 2] = "wamrc"; llvm_options[llvm_options_count - 2] = "wamrc";
llvm_options[llvm_options_count - 1] = argv[0] + 8; llvm_options[llvm_options_count - 1] = argv[0] + 8;
} }
else if (!strcmp(argv[0], "--enable-shared-heap")) {
option.enable_shared_heap = true;
}
else if (!strcmp(argv[0], "--version")) { else if (!strcmp(argv[0], "--version")) {
uint32 major, minor, patch; uint32 major, minor, patch;
wasm_runtime_get_version(&major, &minor, &patch); wasm_runtime_get_version(&major, &minor, &patch);