diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 481b06676..f1e437774 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -65,6 +65,7 @@ env: WASI_TEST_OPTIONS: "-s wasi_certification -w" WAMR_COMPILER_TEST_OPTIONS: "-s wamr_compiler -S -b -P" GC_TEST_OPTIONS: "-s spec -G -b -P" + MEMORY64_TEST_OPTIONS: "-s spec -W -b -P" jobs: build_llvm_libraries_on_ubuntu_2204: @@ -144,6 +145,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_MEMORY64=1", ] os: [ubuntu-22.04] platform: [android, linux] @@ -202,6 +204,21 @@ jobs: make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Memory64 only on CLASSIC INTERP mode, and only on 64-bit platform + - make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + platform: android + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" # Fast-JIT and Multi-Tier-JIT mode don't support android - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS platform: android @@ -503,6 +520,7 @@ jobs: $THREADS_TEST_OPTIONS, $WASI_TEST_OPTIONS, $GC_TEST_OPTIONS, + $MEMORY64_TEST_OPTIONS, ] wasi_sdk_release: [ @@ -541,19 +559,30 @@ jobs: test_option: $GC_TEST_OPTIONS - running_mode: "multi-tier-jit" test_option: $GC_TEST_OPTIONS + # aot, fast-interp, fast-jit, llvm-jit, multi-tier-jit don't support Memory64 + - running_mode: "aot" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "fast-interp" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "fast-jit" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "jit" + test_option: $MEMORY64_TEST_OPTIONS + - running_mode: "multi-tier-jit" + test_option: $MEMORY64_TEST_OPTIONS steps: - name: checkout uses: actions/checkout@v4 - name: Set-up OCaml uses: ocaml/setup-ocaml@v2 - if: matrix.test_option == '$GC_TEST_OPTIONS' + if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS' with: ocaml-compiler: 4.13 - name: Set-up Ocamlbuild - if: matrix.test_option == '$GC_TEST_OPTIONS' - run: opam install ocamlbuild dune + if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS' + run: opam install ocamlbuild dune menhir - name: download and install wasi-sdk if: matrix.test_option == '$WASI_TEST_OPTIONS' @@ -617,13 +646,13 @@ jobs: - name: run tests timeout-minutes: 30 - if: matrix.test_option != '$GC_TEST_OPTIONS' + if: matrix.test_option != '$GC_TEST_OPTIONS' && matrix.test_option != '$MEMORY64_TEST_OPTIONS' run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} working-directory: ./tests/wamr-test-suites - - name: run gc tests + - name: run gc or memory64 tests timeout-minutes: 20 - if: matrix.test_option == '$GC_TEST_OPTIONS' + if: matrix.test_option == '$GC_TEST_OPTIONS' || matrix.test_option == '$MEMORY64_TEST_OPTIONS' run: | eval $(opam env) ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index 9d13e41e2..341194df8 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -130,6 +130,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_MEMORY64=1", ] os: [ubuntu-20.04] platform: [android, linux] @@ -188,6 +189,21 @@ jobs: make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Memory64 only on CLASSIC INTERP mode, and only on 64-bit platform + - make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + platform: android + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" # Fast-JIT and Multi-Tier-JIT mode don't support android - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS platform: android @@ -271,6 +287,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_MEMORY64=1", ] exclude: # uncompatiable feature and platform @@ -299,6 +316,11 @@ jobs: # MINI_LOADER only on INTERP mode - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Memory64 only on CLASSIC INTERP mode + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MEMORY64=1" steps: - name: checkout uses: actions/checkout@v3 diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 6c211d213..8422b060b 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -248,6 +248,15 @@ if (WAMR_BUILD_SHARED_MEMORY EQUAL 1) else () add_definitions (-DWASM_ENABLE_SHARED_MEMORY=0) endif () +if (WAMR_BUILD_MEMORY64 EQUAL 1) + # if native is 32-bit or cross-compiled to 32-bit + if (NOT WAMR_BUILD_TARGET MATCHES ".*64.*") + message (FATAL_ERROR "-- Memory64 is only available on the 64-bit platform/target") + endif() + add_definitions (-DWASM_ENABLE_MEMORY64=1) + set (WAMR_DISABLE_HW_BOUND_CHECK 1) + message (" Memory64 memory enabled") +endif () if (WAMR_BUILD_THREAD_MGR EQUAL 1) message (" Thread manager enabled") endif () diff --git a/core/config.h b/core/config.h index 7cb8ce7ed..d84ed3f36 100644 --- a/core/config.h +++ b/core/config.h @@ -415,7 +415,7 @@ #else #define DEFAULT_WASM_STACK_SIZE (12 * 1024) #endif -/* Min auxilliary stack size of each wasm thread */ +/* Min auxiliary stack size of each wasm thread */ #define WASM_THREAD_AUX_STACK_SIZE_MIN (256) /* Default/min native stack size of each app thread */ @@ -564,7 +564,7 @@ #endif /* Support registering quick AOT/JIT function entries of some func types - to speedup the calling process of invoking the AOT/JIT functions of + to speed up the calling process of invoking the AOT/JIT functions of these types from the host embedder */ #ifndef WASM_ENABLE_QUICK_AOT_ENTRY #define WASM_ENABLE_QUICK_AOT_ENTRY 1 @@ -578,6 +578,11 @@ #define WASM_ENABLE_AOT_INTRINSICS 1 #endif +/* Disable memory64 by default */ +#ifndef WASM_ENABLE_MEMORY64 +#define WASM_ENABLE_MEMORY64 0 +#endif + #ifndef WASM_TABLE_MAX_SIZE #define WASM_TABLE_MAX_SIZE 1024 #endif diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index aeecc8606..d10db89af 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -914,9 +914,10 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, bh_assert(max_memory_data_size <= MAX_LINEAR_MEMORY_SIZE); (void)max_memory_data_size; - if (wasm_allocate_linear_memory(&p, is_shared_memory, num_bytes_per_page, - init_page_count, max_page_count, - &memory_data_size) + /* TODO: memory64 uses is_memory64 flag */ + if (wasm_allocate_linear_memory(&p, is_shared_memory, false, + num_bytes_per_page, init_page_count, + max_page_count, &memory_data_size) != BHT_OK) { set_error_buf(error_buf, error_buf_size, "allocate linear memory failed"); diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 7aa4a563a..13ad2b1a6 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -61,7 +61,7 @@ static union { * Implementation of wasm_application_execute_main() */ static bool -check_main_func_type(const WASMFuncType *type) +check_main_func_type(const WASMFuncType *type, bool is_memory64) { if (!(type->param_count == 0 || type->param_count == 2) || type->result_count > 1) { @@ -72,7 +72,8 @@ check_main_func_type(const WASMFuncType *type) if (type->param_count == 2 && !(type->types[0] == VALUE_TYPE_I32 - && type->types[1] == VALUE_TYPE_I32)) { + && type->types[1] + == (is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32))) { LOG_ERROR( "WASM execute application failed: invalid main function type.\n"); return false; @@ -94,14 +95,18 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) WASMFunctionInstanceCommon *func; WASMFuncType *func_type = NULL; WASMExecEnv *exec_env = NULL; - uint32 argc1 = 0, argv1[2] = { 0 }; + uint32 argc1 = 0, argv1[3] = { 0 }; uint32 total_argv_size = 0; uint64 total_size; uint64 argv_buf_offset = 0; int32 i; char *argv_buf, *p, *p_end; uint32 *argv_offsets, module_type; - bool ret, is_import_func = true; + bool ret, is_import_func = true, is_memory64 = false; +#if WASM_ENABLE_MEMORY64 != 0 + WASMModuleInstance *wasm_module_inst = (WASMModuleInstance *)module_inst; + is_memory64 = wasm_module_inst->memories[0]->is_memory64; +#endif exec_env = wasm_runtime_get_exec_env_singleton(module_inst); if (!exec_env) { @@ -187,7 +192,7 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) return false; } - if (!check_main_func_type(func_type)) { + if (!check_main_func_type(func_type, is_memory64)) { wasm_runtime_set_exception(module_inst, "invalid function type of main function"); return false; @@ -218,11 +223,21 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) p += strlen(argv[i]) + 1; } - argc1 = 2; argv1[0] = (uint32)argc; - /* TODO: memory64 uint64 when the memory idx is i64 */ - argv1[1] = - (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + argc1 = 3; + uint64 app_addr = + wasm_runtime_addr_native_to_app(module_inst, argv_offsets); + PUT_I64_TO_ADDR(&argv[1], app_addr); + } + else +#endif + { + argc1 = 2; + argv1[1] = (uint32)wasm_runtime_addr_native_to_app(module_inst, + argv_offsets); + } } ret = wasm_runtime_call_wasm(exec_env, func, argc1, argv1); diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index 381e6b447..1d2cd1677 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/core/iwasm/common/wasm_memory.c @@ -286,6 +286,7 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, { WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; WASMMemoryInstance *memory_inst; + uint64 max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode || module_inst_comm->module_type == Wasm_Module_AoT); @@ -299,9 +300,13 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } +#if WASM_ENABLE_MEMORY64 != 0 + if (memory_inst->is_memory64) + max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; +#endif /* boundary overflow check */ - if (size > MAX_LINEAR_MEMORY_SIZE - || app_offset > MAX_LINEAR_MEMORY_SIZE - size) { + if (size > max_linear_memory_size + || app_offset > max_linear_memory_size - size) { goto fail; } @@ -324,7 +329,7 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, uint64 app_str_offset) { WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; - uint64 app_end_offset; + uint64 app_end_offset, max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; char *str, *str_end; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode @@ -338,10 +343,14 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, &app_end_offset)) goto fail; +#if WASM_ENABLE_MEMORY64 != 0 + if (module_inst->memories[0]->is_memory64) + max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; +#endif /* boundary overflow check, max start offset can only be size - 1, while end * offset can be size */ - if (app_str_offset >= MAX_LINEAR_MEMORY_SIZE - || app_end_offset > MAX_LINEAR_MEMORY_SIZE) + if (app_str_offset >= max_linear_memory_size + || app_end_offset > max_linear_memory_size) goto fail; str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset); @@ -364,6 +373,7 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; WASMMemoryInstance *memory_inst; uint8 *addr = (uint8 *)native_ptr; + uint64 max_linear_memory_size = MAX_LINEAR_MEMORY_SIZE; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode || module_inst_comm->module_type == Wasm_Module_AoT); @@ -377,8 +387,12 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } +#if WASM_ENABLE_MEMORY64 != 0 + if (memory_inst->is_memory64) + max_linear_memory_size = MAX_LINEAR_MEM64_MEMORY_SIZE; +#endif /* boundary overflow check */ - if (size > MAX_LINEAR_MEMORY_SIZE || (uintptr_t)addr > UINTPTR_MAX - size) { + if (size > max_linear_memory_size || (uintptr_t)addr > UINTPTR_MAX - size) { goto fail; } @@ -748,12 +762,13 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) goto return_func; } - bh_assert(total_size_new <= MAX_LINEAR_MEMORY_SIZE); + bh_assert(total_size_new + <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); if (full_size_mmaped) { #ifdef BH_PLATFORM_WINDOWS if (!os_mem_commit(memory->memory_data_end, - (uint32)(total_size_new - total_size_old), + (mem_offset_t)(total_size_new - total_size_old), MMAP_PROT_READ | MMAP_PROT_WRITE)) { ret = false; goto return_func; @@ -761,12 +776,12 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) #endif if (os_mprotect(memory->memory_data_end, - (uint32)(total_size_new - total_size_old), + (mem_offset_t)(total_size_new - total_size_old), MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { #ifdef BH_PLATFORM_WINDOWS os_mem_decommit(memory->memory_data_end, - (uint32)(total_size_new - total_size_old)); + (mem_offset_t)(total_size_new - total_size_old)); #endif ret = false; goto return_func; @@ -895,8 +910,9 @@ wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst) int wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory, - uint64 num_bytes_per_page, uint64 init_page_count, - uint64 max_page_count, uint64 *memory_data_size) + bool is_memory64, uint64 num_bytes_per_page, + uint64 init_page_count, uint64 max_page_count, + uint64 *memory_data_size) { uint64 map_size, page_size; @@ -925,7 +941,16 @@ wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory, page_size = os_getpagesize(); *memory_data_size = init_page_count * num_bytes_per_page; - bh_assert(*memory_data_size <= MAX_LINEAR_MEMORY_SIZE); + +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + bh_assert(*memory_data_size <= MAX_LINEAR_MEM64_MEMORY_SIZE); + } + else +#endif + { + bh_assert(*memory_data_size <= MAX_LINEAR_MEMORY_SIZE); + } align_as_and_cast(*memory_data_size, page_size); if (map_size > 0) { diff --git a/core/iwasm/common/wasm_memory.h b/core/iwasm/common/wasm_memory.h index 2ada2e618..a5dfefae9 100644 --- a/core/iwasm/common/wasm_memory.h +++ b/core/iwasm/common/wasm_memory.h @@ -64,8 +64,9 @@ wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst); int wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory, - uint64 num_bytes_per_page, uint64 init_page_count, - uint64 max_page_count, uint64 *memory_data_size); + bool is_memory64, uint64 num_bytes_per_page, + uint64 init_page_count, uint64 max_page_count, + uint64 *memory_data_size); #ifdef __cplusplus } diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index a3c8f39eb..e3b4ca7b5 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3746,7 +3746,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); typedef void (*NativeRawFuncPtr)(WASMExecEnv *, uint64 *); NativeRawFuncPtr invoke_native_raw = (NativeRawFuncPtr)func_ptr; - uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size; + uint64 argv_buf[16] = { 0 }, *argv1 = argv_buf, *argv_dst, size, arg_i64; uint32 *argv_src = argv, i, argc1, ptr_len; uint32 arg_i32; bool ret = false; @@ -3770,9 +3770,11 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, case VALUE_TYPE_FUNCREF: #endif { - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ *(uint32 *)argv_dst = arg_i32 = *argv_src++; + /* TODO: memory64 if future there is a way for supporting + * wasm64 and wasm32 in libc at the same time, remove the + * macro control */ +#if WASM_ENABLE_MEMORY64 == 0 if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -3802,9 +3804,49 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, module, (uint64)arg_i32); } } +#endif break; } case VALUE_TYPE_I64: +#if WASM_ENABLE_MEMORY64 != 0 + { + PUT_I64_TO_ADDR((uint32 *)argv_dst, + GET_I64_FROM_ADDR(argv_src)); + argv_src += 2; + arg_i64 = *argv_dst; + if (signature) { + /* TODO: memory64 pointer with length need a new symbol + * to represent type i64, with '~' still represent i32 + * length */ + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i64, + (uint64)ptr_len)) + goto fail; + + *argv_dst = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i64)) + goto fail; + + *argv_dst = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + } + break; + } +#endif case VALUE_TYPE_F64: bh_memcpy_s(argv_dst, sizeof(uint64), argv_src, sizeof(uint32) * 2); @@ -3933,6 +3975,9 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, fail: if (argv1 != argv_buf) wasm_runtime_free(argv1); +#if WASM_ENABLE_MEMORY64 == 0 + (void)arg_i64; +#endif return ret; } @@ -4195,8 +4240,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv_src++; - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -4572,8 +4615,6 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv++; - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -4889,8 +4930,10 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, { arg_i32 = *argv_src++; arg_i64 = arg_i32; - /* TODO: memory64 the data type of ptr_len and argc depends on - * mem idx type */ + /* TODO: memory64 if future there is a way for supporting + * wasm64 and wasm32 in libc at the same time, remove the + * macro control */ +#if WASM_ENABLE_MEMORY64 == 0 if (signature) { if (signature[i + 1] == '*') { /* param is a pointer */ @@ -4918,6 +4961,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, module, (uint64)arg_i32); } } +#endif if (n_ints < MAX_REG_INTS) ints[n_ints++] = arg_i64; else @@ -4925,6 +4969,47 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, break; } case VALUE_TYPE_I64: +#if WASM_ENABLE_MEMORY64 != 0 + { + arg_i64 = GET_I64_FROM_ADDR(argv_src); + argv_src += 2; + if (signature) { + /* TODO: memory64 pointer with length need a new symbol + * to represent type i64, with '~' still represent i32 + * length */ + if (signature[i + 1] == '*') { + /* param is a pointer */ + if (signature[i + 2] == '~') + /* pointer with length followed */ + ptr_len = *argv_src; + else + /* pointer without length followed */ + ptr_len = 1; + + if (!wasm_runtime_validate_app_addr(module, arg_i64, + (uint64)ptr_len)) + goto fail; + + arg_i64 = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + else if (signature[i + 1] == '$') { + /* param is a string */ + if (!wasm_runtime_validate_app_str_addr(module, + arg_i64)) + goto fail; + + arg_i64 = (uint64)wasm_runtime_addr_app_to_native( + module, arg_i64); + } + } + if (n_ints < MAX_REG_INTS) + ints[n_ints++] = arg_i64; + else + stacks[n_stacks++] = arg_i64; + break; + } +#endif #if WASM_ENABLE_GC != 0 case REF_TYPE_FUNCREF: case REF_TYPE_EXTERNREF: diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index aaf04ec2f..62c35473a 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -373,7 +373,7 @@ typedef struct WASMModuleCommon { /* The following uint8[1] member is a dummy just to indicate some module_type dependent members follow. - Typically it should be accessed by casting to the corresponding + Typically, it should be accessed by casting to the corresponding actual module_type dependent structure, not via this member. */ uint8 module_data[1]; } WASMModuleCommon; @@ -389,7 +389,7 @@ typedef struct WASMModuleInstanceCommon { /* The following uint8[1] member is a dummy just to indicate some module_type dependent members follow. - Typically it should be accessed by casting to the corresponding + Typically, it should be accessed by casting to the corresponding actual module_type dependent structure, not via this member. */ uint8 module_inst_data[1]; } WASMModuleInstanceCommon; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 56c8ebe75..5fd86b572 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -90,11 +90,22 @@ extern "C" { */ #define VALUE_TYPE_GC_REF 0x43 +#define MAX_PAGE_COUNT_FLAG 0x01 +#define SHARED_MEMORY_FLAG 0x02 +#define MEMORY64_FLAG 0x04 + #define DEFAULT_NUM_BYTES_PER_PAGE 65536 #define DEFAULT_MAX_PAGES 65536 +#define DEFAULT_MEM64_MAX_PAGES UINT32_MAX /* Max size of linear memory */ #define MAX_LINEAR_MEMORY_SIZE (4 * (uint64)BH_GB) +/* Roughly 274 TB */ +#define MAX_LINEAR_MEM64_MEMORY_SIZE \ + (DEFAULT_MEM64_MAX_PAGES * (uint64)64 * (uint64)BH_KB) +/* Macro to check memory flag and return appropriate memory size */ +#define GET_MAX_LINEAR_MEMORY_SIZE(is_memory64) \ + (is_memory64 ? MAX_LINEAR_MEM64_MEMORY_SIZE : MAX_LINEAR_MEMORY_SIZE) #if WASM_ENABLE_GC == 0 typedef uintptr_t table_elem_type_t; @@ -484,6 +495,12 @@ typedef struct WASMTable { #endif } WASMTable; +#if WASM_ENABLE_MEMORY64 != 0 +typedef uint64 mem_offset_t; +#else +typedef uint32 mem_offset_t; +#endif + typedef struct WASMMemory { uint32 flags; uint32 num_bytes_per_page; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index d8fd2d708..ca972fd4b 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -46,8 +46,10 @@ typedef float64 CellType_F64; #define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #endif -#if !defined(OS_ENABLE_HW_BOUND_CHECK) \ - || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 +#if WASM_ENABLE_MEMORY64 == 0 + +#if (!defined(OS_ENABLE_HW_BOUND_CHECK) \ + || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0) #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ @@ -69,7 +71,8 @@ typedef float64 CellType_F64; else \ goto out_of_bounds; \ } while (0) -#else +#else /* else of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ + WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ @@ -80,8 +83,37 @@ typedef float64 CellType_F64; do { \ maddr = memory->memory_data + (uint32)(start); \ } while (0) -#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \ - || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ +#endif /* end of !defined(OS_ENABLE_HW_BOUND_CHECK) || \ + WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */ + +#else /* else of WASM_ENABLE_MEMORY64 == 0 */ + +#define CHECK_MEMORY_OVERFLOW(bytes) \ + do { \ + uint64 offset1 = (uint64)offset + (uint64)addr; \ + /* If memory64 is enabled, offset1, offset1 + bytes can overflow */ \ + if (disable_bounds_checks \ + || (offset1 >= offset && offset1 + bytes >= offset1 \ + && offset1 + bytes <= get_linear_mem_size())) \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ + } while (0) +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ + do { \ + uint64 offset1 = (uint64)(start); \ + /* If memory64 is enabled, offset1 + bytes can overflow */ \ + if (disable_bounds_checks \ + || (offset1 + bytes >= offset1 \ + && offset1 + bytes <= get_linear_mem_size())) \ + /* App heap space is not valid space for \ + bulk memory operation */ \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ + } while (0) + +#endif /* end of WASM_ENABLE_MEMORY64 == 0 */ #define CHECK_ATOMIC_MEMORY_ACCESS() \ do { \ @@ -472,6 +504,23 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) #define SET_LABEL_TYPE(_label_type) (void)0 #endif +#if WASM_ENABLE_MEMORY64 != 0 +#define PUSH_MEM_OFFSET(value) \ + do { \ + if (is_memory64) { \ + PUT_I64_TO_ADDR(frame_sp, value); \ + frame_sp += 2; \ + } \ + else { \ + *(int32 *)frame_sp++ = (int32)(value); \ + } \ + } while (0) +#else +#define PUSH_MEM_OFFSET(value) PUSH_I32(value) +#endif + +#define PUSH_PAGE_COUNT(value) PUSH_MEM_OFFSET(value) + #define PUSH_CSP(_label_type, param_cell_num, cell_num, _target_addr) \ do { \ bh_assert(frame_csp < frame->csp_boundary); \ @@ -501,6 +550,14 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) GET_REF_FROM_ADDR(frame_sp)) #endif +#if WASM_ENABLE_MEMORY64 != 0 +#define POP_MEM_OFFSET() (is_memory64 ? POP_I64() : POP_I32()) +#else +#define POP_MEM_OFFSET() POP_I32() +#endif + +#define POP_PAGE_COUNT() POP_MEM_OFFSET() + #define POP_CSP_CHECK_OVERFLOW(n) \ do { \ bh_assert(frame_csp - n >= frame->csp_bottom); \ @@ -567,51 +624,73 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) frame_csp = frame->csp; \ } while (0) -#define read_leb_int64(p, p_end, res) \ - do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = (int64)_val; \ - if (_val & 0x40) \ - /* sign extend */ \ - res |= 0xFFFFFFFFFFFFFF80LL; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (int64)read_leb(p, &_off, 64, true); \ - p += _off; \ +#define read_leb_int64(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = (int64)_val; \ + if (_val & 0x40) \ + /* sign extend */ \ + res |= 0xFFFFFFFFFFFFFF80LL; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (int64)read_leb(p, &_off, 64, true); \ + p += _off; \ + } \ } while (0) -#define read_leb_uint32(p, p_end, res) \ - do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = _val; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (uint32)read_leb(p, &_off, 32, false); \ - p += _off; \ +#define read_leb_uint32(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = _val; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (uint32)read_leb(p, &_off, 32, false); \ + p += _off; \ + } \ } while (0) -#define read_leb_int32(p, p_end, res) \ - do { \ - uint8 _val = *p; \ - if (!(_val & 0x80)) { \ - res = (int32)_val; \ - if (_val & 0x40) \ - /* sign extend */ \ - res |= 0xFFFFFF80; \ - p++; \ - break; \ - } \ - uint32 _off = 0; \ - res = (int32)read_leb(p, &_off, 32, true); \ - p += _off; \ +#define read_leb_int32(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = (int32)_val; \ + if (_val & 0x40) \ + /* sign extend */ \ + res |= 0xFFFFFF80; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (int32)read_leb(p, &_off, 32, true); \ + p += _off; \ + } \ } while (0) +#if WASM_ENABLE_MEMORY64 != 0 +#define read_leb_mem_offset(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = (mem_offset_t)_val; \ + p++; \ + } \ + else { \ + uint32 _off = 0; \ + res = (mem_offset_t)read_leb(p, &_off, is_memory64 ? 64 : 32, \ + false); \ + p += _off; \ + } \ + } while (0) +#else +#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res) +#endif + #if WASM_ENABLE_LABELS_AS_VALUES == 0 #define RECOVER_FRAME_IP_END() frame_ip_end = wasm_get_func_code_end(cur_func) #else @@ -872,7 +951,7 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, uint32 readv, sval; \ \ sval = POP_I32(); \ - addr = POP_I32(); \ + addr = POP_MEM_OFFSET(); \ \ if (opcode == WASM_OP_ATOMIC_RMW_I32_##OP_NAME##8_U) { \ CHECK_MEMORY_OVERFLOW(1); \ @@ -912,7 +991,7 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, uint64 readv, sval; \ \ sval = (uint64)POP_I64(); \ - addr = POP_I32(); \ + addr = POP_MEM_OFFSET(); \ \ if (opcode == WASM_OP_ATOMIC_RMW_I64_##OP_NAME##8_U) { \ CHECK_MEMORY_OVERFLOW(1); \ @@ -1430,6 +1509,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMStringviewIterObjectRef stringview_iter_obj; #endif #endif +#if WASM_ENABLE_MEMORY64 != 0 + /* TODO: multi-memories for now assuming the memory idx type is consistent + * across multi-memories */ + bool is_memory64 = false; + if (memory) + is_memory64 = memory->is_memory64; +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 uint8 *frame_ip_orig = NULL; @@ -4087,8 +4173,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); - /* TODO: Memory64 the data type depends on mem idx type */ - aux_stack_top = (uint64)(*(uint32 *)(frame_sp - 1)); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + aux_stack_top = *(uint64 *)(frame_sp - 2); + } + else +#endif + { + aux_stack_top = (uint64)(*(uint32 *)(frame_sp - 1)); + } if (aux_stack_top <= (uint64)exec_env->aux_stack_boundary) { wasm_set_exception(module, "wasm auxiliary stack overflow"); goto got_exception; @@ -4098,8 +4191,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, "wasm auxiliary stack underflow"); goto got_exception; } - *(int32 *)global_addr = aux_stack_top; - frame_sp--; +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + *(uint64 *)global_addr = aux_stack_top; + frame_sp -= 2; + } + else +#endif + { + *(uint32 *)global_addr = aux_stack_top; + frame_sp--; + } #if WASM_ENABLE_MEMORY_PROFILING != 0 if (module->module->aux_stack_top_global_index != (uint32)-1) { uint32 aux_stack_used = @@ -4126,11 +4228,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD) HANDLE_OP(WASM_OP_F32_LOAD) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); PUSH_I32(LOAD_I32(maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4141,11 +4244,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD) HANDLE_OP(WASM_OP_F64_LOAD) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(8); PUSH_I64(LOAD_I64(maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4155,11 +4259,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD8_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I32(sign_ext_8_32(*(int8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4169,11 +4274,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD8_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I32((uint32)(*(uint8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4183,11 +4289,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD16_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4197,11 +4304,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_LOAD16_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I32((uint32)(LOAD_U16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4211,11 +4319,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD8_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I64(sign_ext_8_64(*(int8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4225,11 +4334,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD8_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(1); PUSH_I64((uint64)(*(uint8 *)maddr)); CHECK_READ_WATCHPOINT(addr, offset); @@ -4239,11 +4349,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD16_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4253,11 +4364,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD16_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(2); PUSH_I64((uint64)(LOAD_U16(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4267,12 +4379,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD32_S) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4282,11 +4395,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_LOAD32_U) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); - addr = POP_I32(); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); PUSH_I64((uint64)(LOAD_U32(maddr))); CHECK_READ_WATCHPOINT(addr, offset); @@ -4298,14 +4412,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_STORE) HANDLE_OP(WASM_OP_F32_STORE) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); frame_sp--; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); - STORE_U32(maddr, frame_sp[1]); +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + STORE_U32(maddr, frame_sp[2]); + } + else +#endif + { + STORE_U32(maddr, frame_sp[1]); + } CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); @@ -4314,15 +4437,26 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_STORE) HANDLE_OP(WASM_OP_F64_STORE) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); frame_sp -= 2; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(8); - PUT_I64_TO_ADDR((uint32 *)maddr, - GET_I64_FROM_ADDR(frame_sp + 1)); + +#if WASM_ENABLE_MEMORY64 != 0 + if (is_memory64) { + PUT_I64_TO_ADDR((mem_offset_t *)maddr, + GET_I64_FROM_ADDR(frame_sp + 2)); + } + else +#endif + { + PUT_I64_TO_ADDR((uint32 *)maddr, + GET_I64_FROM_ADDR(frame_sp + 1)); + } CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); @@ -4331,14 +4465,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I32_STORE8) HANDLE_OP(WASM_OP_I32_STORE16) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; uint32 sval; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); sval = (uint32)POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_I32_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -4357,14 +4492,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_I64_STORE16) HANDLE_OP(WASM_OP_I64_STORE32) { - uint32 offset, flags, addr; + uint32 flags; + mem_offset_t offset, addr; uint64 sval; opcode = *(frame_ip - 1); read_leb_uint32(frame_ip, frame_ip_end, flags); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); sval = (uint64)POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_I64_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -4388,7 +4524,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 reserved; read_leb_uint32(frame_ip, frame_ip_end, reserved); - PUSH_I32(memory->cur_page_count); + PUSH_PAGE_COUNT(memory->cur_page_count); (void)reserved; HANDLE_OP_END(); } @@ -4399,15 +4535,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, prev_page_count = memory->cur_page_count; read_leb_uint32(frame_ip, frame_ip_end, reserved); - delta = (uint32)POP_I32(); + delta = (uint32)POP_PAGE_COUNT(); if (!wasm_enlarge_memory(module, delta)) { /* failed to memory.grow, return -1 */ - PUSH_I32(-1); + PUSH_PAGE_COUNT(-1); } else { /* success, return previous page count */ - PUSH_I32(prev_page_count); + PUSH_PAGE_COUNT(prev_page_count); /* update memory size, no need to update memory ptr as it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ @@ -5407,7 +5543,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_BULK_MEMORY != 0 case WASM_OP_MEMORY_INIT: { - uint32 addr, segment; + uint32 segment; + mem_offset_t addr; uint64 bytes, offset, seg_len; uint8 *data; @@ -5417,7 +5554,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bytes = (uint64)(uint32)POP_I32(); offset = (uint64)(uint32)POP_I32(); - addr = (uint32)POP_I32(); + addr = (mem_offset_t)POP_MEM_OFFSET(); #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); @@ -5460,14 +5597,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } case WASM_OP_MEMORY_COPY: { - uint32 dst, src, len; + mem_offset_t dst, src, len; uint8 *mdst, *msrc; frame_ip += 2; - - len = POP_I32(); - src = POP_I32(); - dst = POP_I32(); + len = POP_MEM_OFFSET(); + src = POP_MEM_OFFSET(); + dst = POP_MEM_OFFSET(); #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); @@ -5493,13 +5629,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } case WASM_OP_MEMORY_FILL: { - uint32 dst, len; + mem_offset_t dst, len; uint8 fill_val, *mdst; frame_ip++; - len = POP_I32(); + len = POP_MEM_OFFSET(); fill_val = POP_I32(); - dst = POP_I32(); + dst = POP_MEM_OFFSET(); #if WASM_ENABLE_THREAD_MGR != 0 linear_mem_size = get_linear_mem_size(); @@ -5729,7 +5865,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_SHARED_MEMORY != 0 HANDLE_OP(WASM_OP_ATOMIC_PREFIX) { - uint32 offset = 0, align = 0, addr; + mem_offset_t offset = 0, addr; + uint32 align = 0; uint32 opcode1; read_leb_uint32(frame_ip, frame_ip_end, opcode1); @@ -5739,7 +5876,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (opcode != WASM_OP_ATOMIC_FENCE) { read_leb_uint32(frame_ip, frame_ip_end, align); - read_leb_uint32(frame_ip, frame_ip_end, offset); + read_leb_mem_offset(frame_ip, frame_ip_end, offset); } switch (opcode) { @@ -5748,7 +5885,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 notify_count, ret; notify_count = POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); CHECK_ATOMIC_MEMORY_ACCESS(); @@ -5768,7 +5905,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, timeout = POP_I64(); expect = POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(4); CHECK_ATOMIC_MEMORY_ACCESS(); @@ -5792,7 +5929,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, timeout = POP_I64(); expect = POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); CHECK_MEMORY_OVERFLOW(8); CHECK_ATOMIC_MEMORY_ACCESS(); @@ -5823,7 +5960,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint32 readv; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I32_LOAD8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -5858,7 +5995,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { uint64 readv; - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I64_LOAD8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -5900,7 +6037,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 sval; sval = (uint32)POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I32_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -5934,7 +6071,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint64 sval; sval = (uint64)POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_I64_STORE8) { CHECK_MEMORY_OVERFLOW(1); @@ -5961,7 +6098,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_MEMORY_OVERFLOW(8); CHECK_ATOMIC_MEMORY_ACCESS(); shared_memory_lock(memory); - PUT_I64_TO_ADDR((uint32 *)maddr, sval); + STORE_I64(maddr, sval); shared_memory_unlock(memory); } break; @@ -5975,7 +6112,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, sval = POP_I32(); expect = POP_I32(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_RMW_I32_CMPXCHG8_U) { CHECK_MEMORY_OVERFLOW(1); @@ -6021,7 +6158,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, sval = (uint64)POP_I64(); expect = (uint64)POP_I64(); - addr = POP_I32(); + addr = POP_MEM_OFFSET(); if (opcode == WASM_OP_ATOMIC_RMW_I64_CMPXCHG8_U) { CHECK_MEMORY_OVERFLOW(1); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index b602df877..51384cb69 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -45,6 +45,16 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) } } +#if WASM_ENABLE_MEMORY64 != 0 +static void +set_error_buf_mem_offset_out_of_range(char *error_buf, uint32 error_buf_size) +{ + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, "offset out of range"); + } +} +#endif + static void set_error_buf_v(char *error_buf, uint32 error_buf_size, const char *format, ...) { @@ -102,6 +112,7 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length, #define skip_leb_int64(p, p_end) skip_leb(p) #define skip_leb_uint32(p, p_end) skip_leb(p) #define skip_leb_int32(p, p_end) skip_leb(p) +#define skip_leb_mem_offset(p, p_end) skip_leb(p) static bool read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, @@ -139,7 +150,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 32) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -154,7 +165,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 64) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -191,6 +202,21 @@ fail: res = (int64)res64; \ } while (0) +#if WASM_ENABLE_MEMORY64 != 0 +#define read_leb_mem_offset(p, p_end, res) \ + do { \ + uint64 res64; \ + if (!read_leb((uint8 **)&p, p_end, is_memory64 ? 64 : 32, false, \ + &res64, error_buf, error_buf_size)) { \ + set_error_buf_mem_offset_out_of_range(error_buf, error_buf_size); \ + goto fail; \ + } \ + res = (mem_offset_t)res64; \ + } while (0) +#else +#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res) +#endif + #define read_leb_uint32(p, p_end, res) \ do { \ uint64 res64; \ @@ -2582,31 +2608,92 @@ fail: } static bool -check_memory_init_size(uint32 init_size, char *error_buf, uint32 error_buf_size) +check_memory_init_size(bool is_memory64, uint32 init_size, char *error_buf, + uint32 error_buf_size) { - if (init_size > DEFAULT_MAX_PAGES) { + uint32 default_max_size = + is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; + + if (!is_memory64 && init_size > default_max_size) { set_error_buf(error_buf, error_buf_size, "memory size must be at most 65536 pages (4GiB)"); return false; } +#if WASM_ENABLE_MEMORY64 != 0 + else if (is_memory64 && init_size > default_max_size) { + set_error_buf( + error_buf, error_buf_size, + "memory size must be at most 4,294,967,295 pages (274 Terabyte)"); + return false; + } +#endif return true; } static bool -check_memory_max_size(uint32 init_size, uint32 max_size, char *error_buf, - uint32 error_buf_size) +check_memory_max_size(bool is_memory64, uint32 init_size, uint32 max_size, + char *error_buf, uint32 error_buf_size) { + uint32 default_max_size = + is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; + if (max_size < init_size) { set_error_buf(error_buf, error_buf_size, "size minimum must not be greater than maximum"); return false; } - if (max_size > DEFAULT_MAX_PAGES) { + if (!is_memory64 && max_size > default_max_size) { set_error_buf(error_buf, error_buf_size, "memory size must be at most 65536 pages (4GiB)"); return false; } +#if WASM_ENABLE_MEMORY64 != 0 + else if (is_memory64 && max_size > default_max_size) { + set_error_buf( + error_buf, error_buf_size, + "memory size must be at most 4,294,967,295 pages (274 Terabyte)"); + return false; + } +#endif + + return true; +} + +static bool +check_memory_flag(const uint8 mem_flag, char *error_buf, uint32 error_buf_size) +{ + /* Check whether certain features indicated by mem_flag are enabled in + * runtime */ + if (mem_flag > MAX_PAGE_COUNT_FLAG) { +#if WASM_ENABLE_SHARED_MEMORY == 0 + if (mem_flag & SHARED_MEMORY_FLAG) { + LOG_VERBOSE("shared memory flag was found, please enable shared " + "memory, lib-pthread or lib-wasi-threads"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } +#endif +#if WASM_ENABLE_MEMORY64 == 0 + if (mem_flag & MEMORY64_FLAG) { + LOG_VERBOSE("memory64 flag was found, please enable memory64"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } +#endif + } + + if (mem_flag > MAX_PAGE_COUNT_FLAG + SHARED_MEMORY_FLAG + MEMORY64_FLAG) { + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + else if ((mem_flag & SHARED_MEMORY_FLAG) + && !(mem_flag & MAX_PAGE_COUNT_FLAG)) { + set_error_buf(error_buf, error_buf_size, + "shared memory must have maximum"); + return false; + } + return true; } @@ -2616,15 +2703,16 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, const char *memory_name, WASMMemoryImport *memory, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; #if WASM_ENABLE_APP_FRAMEWORK != 0 uint32 pool_size = wasm_runtime_memory_pool_size(); uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; #endif /* WASM_ENABLE_APP_FRAMEWORK */ - uint32 declare_max_page_count_flag = 0; + uint32 mem_flag = 0; + bool is_memory64 = false; uint32 declare_init_page_count = 0; uint32 declare_max_page_count = 0; #if WASM_ENABLE_MULTI_MODULE != 0 @@ -2632,16 +2720,31 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *linked_memory = NULL; #endif - read_leb_uint32(p, p_end, declare_max_page_count_flag); + p_org = p; + read_leb_uint32(p, p_end, mem_flag); + is_memory64 = mem_flag & MEMORY64_FLAG; + if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + + if (!check_memory_flag(mem_flag, error_buf, error_buf_size)) { + return false; + } + read_leb_uint32(p, p_end, declare_init_page_count); - if (!check_memory_init_size(declare_init_page_count, error_buf, + if (!check_memory_init_size(is_memory64, declare_init_page_count, error_buf, error_buf_size)) { return false; } - if (declare_max_page_count_flag & 1) { +#if WASM_ENABLE_APP_FRAMEWORK == 0 + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; +#endif + if (mem_flag & MAX_PAGE_COUNT_FLAG) { read_leb_uint32(p, p_end, declare_max_page_count); - if (!check_memory_max_size(declare_init_page_count, + if (!check_memory_max_size(is_memory64, declare_init_page_count, declare_max_page_count, error_buf, error_buf_size)) { return false; @@ -2664,7 +2767,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_LIB_WASI_THREADS != 0 /* Avoid memory import failure when wasi-threads is enabled and the memory is shared */ - if (!(declare_max_page_count_flag & 2)) + if (!(mem_flag & SHARED_MEMORY_FLAG)) return false; #else return false; @@ -2712,7 +2815,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, } /* now we believe all declaration are ok */ - memory->flags = declare_max_page_count_flag; + memory->flags = mem_flag; memory->init_page_count = declare_init_page_count; memory->max_page_count = declare_max_page_count; memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; @@ -3013,53 +3116,34 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; #endif + bool is_memory64 = false; p_org = p; read_leb_uint32(p, p_end, memory->flags); -#if WASM_ENABLE_SHARED_MEMORY == 0 - if (p - p_org > 1) { - set_error_buf(error_buf, error_buf_size, - "integer representation too long"); - return false; - } - if (memory->flags > 1) { - if (memory->flags & 2) { - set_error_buf(error_buf, error_buf_size, - "shared memory flag was found, " - "please enable shared memory, lib-pthread " - "or lib-wasi-threads"); - } - else { - set_error_buf(error_buf, error_buf_size, "invalid memory flags"); - } - return false; - } -#else + is_memory64 = memory->flags & MEMORY64_FLAG; if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } - if (memory->flags > 3) { - set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + + if (!check_memory_flag(memory->flags, error_buf, error_buf_size)) { return false; } - else if (memory->flags == 2) { - set_error_buf(error_buf, error_buf_size, - "shared memory must have maximum"); - return false; - } -#endif read_leb_uint32(p, p_end, memory->init_page_count); - if (!check_memory_init_size(memory->init_page_count, error_buf, + if (!check_memory_init_size(is_memory64, memory->init_page_count, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_APP_FRAMEWORK == 0 + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; +#endif if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); - if (!check_memory_max_size(memory->init_page_count, + if (!check_memory_max_size(is_memory64, memory->init_page_count, memory->max_page_count, error_buf, error_buf_size)) return false; @@ -4450,6 +4534,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, bool is_passive = false; uint32 mem_flag; #endif + uint8 mem_offset_type; read_leb_uint32(p, p_end, data_seg_count); @@ -4515,11 +4600,35 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, } #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_BULK_MEMORY != 0 + if (!is_passive) +#endif + { +#if WASM_ENABLE_MEMORY64 != 0 + /* This memory_flag is from memory instead of data segment */ + uint8 memory_flag; + if (module->import_memory_count > 0) { + memory_flag = + module->import_memories[mem_index].u.memory.flags; + } + else { + memory_flag = + module + ->memories[mem_index - module->import_memory_count] + .flags; + } + mem_offset_type = memory_flag & MEMORY64_FLAG ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif + } + #if WASM_ENABLE_BULK_MEMORY != 0 if (!is_passive) #endif if (!load_init_expr(module, &p, p_end, &init_expr, - VALUE_TYPE_I32, NULL, error_buf, + mem_offset_type, NULL, error_buf, error_buf_size)) return false; @@ -6979,8 +7088,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ break; case WASM_OP_MEMORY_SIZE: @@ -7326,6 +7435,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) case WASM_OP_SIMD_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; read_leb_uint32(p, p_end, opcode1); @@ -7422,6 +7532,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; /* atomic_op (u32_leb) + memarg (2 u32_leb) */ @@ -7431,8 +7542,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, opcode = (uint8)opcode1; if (opcode != WASM_OP_ATOMIC_FENCE) { - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ } else { /* atomic.fence doesn't have memarg */ @@ -9334,6 +9445,8 @@ fail: #define PUSH_EXTERNREF() TEMPLATE_PUSH(EXTERNREF) #define PUSH_REF(Type) TEMPLATE_PUSH_REF(Type) #define POP_REF(Type) TEMPLATE_POP_REF(Type) +#define PUSH_MEM_OFFSET() TEMPLATE_PUSH_REF(mem_offset_type) +#define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() #define POP_I32() TEMPLATE_POP(I32) #define POP_F32() TEMPLATE_POP(F32) @@ -9343,6 +9456,7 @@ fail: #define POP_FUNCREF() TEMPLATE_POP(FUNCREF) #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF) #define POP_STRINGREF() TEMPLATE_POP(STRINGREF) +#define POP_MEM_OFFSET() TEMPLATE_POP_REF(mem_offset_type) #if WASM_ENABLE_FAST_INTERP != 0 @@ -10510,11 +10624,12 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, *local_types, local_type, global_type; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; BlockType func_block_type; uint16 *local_offsets, local_offset; uint32 type_idx, func_idx, local_idx, global_idx, table_idx; - uint32 table_seg_idx, data_seg_idx, count, align, mem_offset, i; + uint32 table_seg_idx, data_seg_idx, count, align, i; + mem_offset_t mem_offset; int32 i32_const = 0; int64 i64_const; uint8 opcode; @@ -10539,6 +10654,19 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n", func->param_cell_num, func->local_cell_num, func->ret_cell_num); #endif +#if WASM_ENABLE_MEMORY64 != 0 + bool is_memory64 = false; + /* TODO: multi-memories for now assuming the memory idx type is consistent + * across multi-memories */ + if (module->import_memory_count > 0) + is_memory64 = module->import_memories[0].u.memory.flags & MEMORY64_FLAG; + else if (module->memory_count > 0) + is_memory64 = module->memories[0].flags & MEMORY64_FLAG; + + mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif global_count = module->import_global_count + module->global_count; @@ -12730,8 +12858,8 @@ re_scan: } #endif CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ if (!check_memory_access_align(opcode, align, error_buf, error_buf_size)) { goto fail; @@ -12749,7 +12877,7 @@ re_scan: case WASM_OP_I32_LOAD8_U: case WASM_OP_I32_LOAD16_S: case WASM_OP_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_I64_LOAD: case WASM_OP_I64_LOAD8_S: @@ -12758,35 +12886,35 @@ re_scan: case WASM_OP_I64_LOAD16_U: case WASM_OP_I64_LOAD32_S: case WASM_OP_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_F32_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F32); break; case WASM_OP_F64_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F64); break; /* store */ case WASM_OP_I32_STORE: case WASM_OP_I32_STORE8: case WASM_OP_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_I64_STORE: case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F32_STORE: POP_F32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F64_STORE: POP_F64(); - POP_I32(); + POP_MEM_OFFSET(); break; default: break; @@ -12802,7 +12930,7 @@ re_scan: "zero byte expected"); goto fail; } - PUSH_I32(); + PUSH_PAGE_COUNT(); module->possible_memory_grow = true; #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 @@ -12818,7 +12946,7 @@ re_scan: "zero byte expected"); goto fail; } - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, mem_offset_type); module->possible_memory_grow = true; #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ @@ -14179,7 +14307,7 @@ re_scan: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -14222,9 +14350,9 @@ re_scan: && module->memory_count == 0) goto fail_unknown_memory; - POP_I32(); - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -14242,10 +14370,9 @@ re_scan: && module->memory_count == 0) { goto fail_unknown_memory; } - - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -14491,6 +14618,7 @@ re_scan: #if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) case WASM_OP_SIMD_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -15167,8 +15295,8 @@ re_scan: #endif if (opcode1 != WASM_OP_ATOMIC_FENCE) { CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ if (!check_memory_align_equal(opcode1, align, error_buf, error_buf_size)) { goto fail; @@ -15182,18 +15310,20 @@ re_scan: #endif switch (opcode1) { case WASM_OP_ATOMIC_NOTIFY: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT32: POP_I64(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT64: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_FENCE: @@ -15207,26 +15337,26 @@ re_scan: case WASM_OP_ATOMIC_I32_LOAD: case WASM_OP_ATOMIC_I32_LOAD8_U: case WASM_OP_ATOMIC_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_ATOMIC_I32_STORE: case WASM_OP_ATOMIC_I32_STORE8: case WASM_OP_ATOMIC_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_I64_LOAD: case WASM_OP_ATOMIC_I64_LOAD8_U: case WASM_OP_ATOMIC_I64_LOAD16_U: case WASM_OP_ATOMIC_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_ATOMIC_I64_STORE: case WASM_OP_ATOMIC_I64_STORE8: case WASM_OP_ATOMIC_I64_STORE16: case WASM_OP_ATOMIC_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_RMW_I32_ADD: case WASM_OP_ATOMIC_RMW_I32_ADD8_U: @@ -15246,7 +15376,9 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_XCHG: case WASM_OP_ATOMIC_RMW_I32_XCHG8_U: case WASM_OP_ATOMIC_RMW_I32_XCHG16_U: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_ADD: case WASM_OP_ATOMIC_RMW_I64_ADD8_U: @@ -15273,7 +15405,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_XCHG16_U: case WASM_OP_ATOMIC_RMW_I64_XCHG32_U: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: @@ -15281,7 +15413,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: @@ -15290,7 +15422,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; default: diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 51dbbe003..f1023fa01 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -47,6 +47,7 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) #define skip_leb_int64(p, p_end) skip_leb(p) #define skip_leb_uint32(p, p_end) skip_leb(p) #define skip_leb_int32(p, p_end) skip_leb(p) +#define skip_leb_mem_offset(p, p_end) skip_leb(p) static bool is_32bit_type(uint8 type) @@ -116,7 +117,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 32) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -132,7 +133,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, } else if (sign && maxbits == 64) { if (shift < maxbits) { - /* Sign extend, second highest bit is the sign bit */ + /* Sign extend, second-highest bit is the sign bit */ if ((uint8)byte & 0x40) result |= (~((uint64)0)) << shift; } @@ -180,6 +181,18 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, res = (int32)res64; \ } while (0) +#if WASM_ENABLE_MEMORY64 != 0 +#define read_leb_mem_offset(p, p_end, res) \ + do { \ + uint64 res64; \ + read_leb((uint8 **)&p, p_end, is_memory64 ? 64 : 32, false, &res64, \ + error_buf, error_buf_size); \ + res = (mem_offset_t)res64; \ + } while (0) +#else +#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res) +#endif + static void * loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) { @@ -683,6 +696,38 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, return true; } +static bool +check_memory_flag(const uint8 mem_flag) +{ + /* Check whether certain features indicated by mem_flag are enabled in + * runtime */ + if (mem_flag > MAX_PAGE_COUNT_FLAG) { +#if WASM_ENABLE_SHARED_MEMORY == 0 + if (mem_flag & SHARED_MEMORY_FLAG) { + LOG_VERBOSE("shared memory flag was found, please enable shared " + "memory, lib-pthread or lib-wasi-threads"); + return false; + } +#endif +#if WASM_ENABLE_MEMORY64 == 0 + if (mem_flag & MEMORY64_FLAG) { + LOG_VERBOSE("memory64 flag was found, please enable memory64"); + return false; + } +#endif + } + + if (mem_flag > MAX_PAGE_COUNT_FLAG + SHARED_MEMORY_FLAG + MEMORY64_FLAG) { + return false; + } + else if ((mem_flag & SHARED_MEMORY_FLAG) + && !(mem_flag & MAX_PAGE_COUNT_FLAG)) { + return false; + } + + return true; +} + static bool load_memory_import(const uint8 **p_buf, const uint8 *buf_end, WASMModule *parent_module, const char *sub_module_name, @@ -695,20 +740,28 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; #endif /* WASM_ENABLE_APP_FRAMEWORK */ - uint32 declare_max_page_count_flag = 0; + uint32 mem_flag = 0; + bool is_memory64 = false; uint32 declare_init_page_count = 0; uint32 declare_max_page_count = 0; - read_leb_uint32(p, p_end, declare_max_page_count_flag); - read_leb_uint32(p, p_end, declare_init_page_count); - bh_assert(declare_init_page_count <= 65536); + read_leb_uint32(p, p_end, mem_flag); + bh_assert(check_memory_flag(mem_flag)); - if (declare_max_page_count_flag & 1) { +#if WASM_ENABLE_APP_FRAMEWORK == 0 + is_memory64 = mem_flag & MEMORY64_FLAG; + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; +#endif + + read_leb_uint32(p, p_end, declare_init_page_count); + bh_assert(declare_init_page_count <= max_page_count); + + if (mem_flag & MAX_PAGE_COUNT_FLAG) { read_leb_uint32(p, p_end, declare_max_page_count); bh_assert(declare_init_page_count <= declare_max_page_count); - bh_assert(declare_max_page_count <= 65536); + bh_assert(declare_max_page_count <= max_page_count); if (declare_max_page_count > max_page_count) { declare_max_page_count = max_page_count; } @@ -719,12 +772,13 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, } /* now we believe all declaration are ok */ - memory->flags = declare_max_page_count_flag; + memory->flags = mem_flag; memory->init_page_count = declare_init_page_count; memory->max_page_count = declare_max_page_count; memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; + (void)check_memory_flag; return true; } @@ -811,26 +865,28 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT / DEFAULT_NUM_BYTES_PER_PAGE; #else - uint32 max_page_count = DEFAULT_MAX_PAGES; + uint32 max_page_count; + bool is_memory64 = false; #endif p_org = p; read_leb_uint32(p, p_end, memory->flags); bh_assert(p - p_org <= 1); (void)p_org; -#if WASM_ENABLE_SHARED_MEMORY == 0 - bh_assert(memory->flags <= 1); -#else - bh_assert(memory->flags <= 3 && memory->flags != 2); + bh_assert(check_memory_flag(memory->flags)); + +#if WASM_ENABLE_APP_FRAMEWORK == 0 + is_memory64 = memory->flags & MEMORY64_FLAG; + max_page_count = is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; #endif read_leb_uint32(p, p_end, memory->init_page_count); - bh_assert(memory->init_page_count <= 65536); + bh_assert(memory->init_page_count <= max_page_count); if (memory->flags & 1) { read_leb_uint32(p, p_end, memory->max_page_count); bh_assert(memory->init_page_count <= memory->max_page_count); - bh_assert(memory->max_page_count <= 65536); + bh_assert(memory->max_page_count <= max_page_count); if (memory->max_page_count > max_page_count) memory->max_page_count = max_page_count; } @@ -842,6 +898,7 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; + (void)check_memory_flag; return true; } @@ -1704,6 +1761,7 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, bool is_passive = false; uint32 mem_flag; #endif + uint8 mem_offset_type; read_leb_uint32(p, p_end, data_seg_count); @@ -1750,11 +1808,35 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, < module->import_memory_count + module->memory_count); #endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_BULK_MEMORY != 0 + if (!is_passive) +#endif /* WASM_ENABLE_BULK_MEMORY */ + { +#if WASM_ENABLE_MEMORY64 != 0 + /* This memory_flag is from memory instead of data segment */ + uint8 memory_flag; + if (module->import_memory_count > 0) { + memory_flag = + module->import_memories[mem_index].u.memory.flags; + } + else { + memory_flag = + module + ->memories[mem_index - module->import_memory_count] + .flags; + } + mem_offset_type = memory_flag & MEMORY64_FLAG ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif /* WASM_ENABLE_MEMORY64 */ + } + #if WASM_ENABLE_BULK_MEMORY != 0 if (!is_passive) #endif if (!load_init_expr(module, &p, p_end, &init_expr, - VALUE_TYPE_I32, error_buf, error_buf_size)) + mem_offset_type, error_buf, error_buf_size)) return false; read_leb_uint32(p, p_end, data_seg_len); @@ -3532,8 +3614,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ break; case WASM_OP_MEMORY_SIZE: @@ -3748,6 +3830,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, #if WASM_ENABLE_SHARED_MEMORY != 0 case WASM_OP_ATOMIC_PREFIX: { + /* TODO: memory64 offset type changes */ uint32 opcode1; /* atomic_op (u32_leb) + memarg (2 u32_leb) */ @@ -3757,8 +3840,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, opcode = (uint8)opcode1; if (opcode != WASM_OP_ATOMIC_FENCE) { - skip_leb_uint32(p, p_end); /* align */ - skip_leb_uint32(p, p_end); /* offset */ + skip_leb_uint32(p, p_end); /* align */ + skip_leb_mem_offset(p, p_end); /* offset */ } else { /* atomic.fence doesn't have memarg */ @@ -5075,6 +5158,11 @@ fail: goto fail; \ } while (0) +#define PUSH_MEM_OFFSET() PUSH_OFFSET_TYPE(mem_offset_type) +#define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() + +#define POP_MEM_OFFSET() POP_OFFSET_TYPE(mem_offset_type) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref_offset( \ @@ -5129,6 +5217,15 @@ fail: goto fail; \ } while (0) +#define PUSH_MEM_OFFSET() \ + do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, mem_offset_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + +#define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() + #define POP_I32() \ do { \ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, error_buf, \ @@ -5164,6 +5261,13 @@ fail: goto fail; \ } while (0) +#define POP_MEM_OFFSET() \ + do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, mem_offset_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, type_push, \ @@ -5774,10 +5878,11 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, *local_types, local_type, global_type; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; BlockType func_block_type; uint16 *local_offsets, local_offset; - uint32 count, local_idx, global_idx, u32, align, mem_offset, i; + uint32 count, local_idx, global_idx, u32, align, i; + mem_offset_t mem_offset; int32 i32, i32_const = 0; int64 i64_const; uint8 opcode, u8; @@ -5799,6 +5904,19 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, LOG_OP("\nProcessing func | [%d] params | [%d] locals | [%d] return\n", func->param_cell_num, func->local_cell_num, func->ret_cell_num); #endif +#if WASM_ENABLE_MEMORY64 != 0 + bool is_memory64 = false; + /* TODO: multi-memories for now assuming the memory idx type is consistent + * across multi-memories */ + if (module->import_memory_count > 0) + is_memory64 = module->import_memories[0].u.memory.flags & MEMORY64_FLAG; + else if (module->memory_count > 0) + is_memory64 = module->memories[0].flags & MEMORY64_FLAG; + + mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; +#else + mem_offset_type = VALUE_TYPE_I32; +#endif global_count = module->import_global_count + module->global_count; @@ -7107,8 +7225,8 @@ re_scan: } #endif CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, mem_offset); #endif @@ -7122,7 +7240,7 @@ re_scan: case WASM_OP_I32_LOAD8_U: case WASM_OP_I32_LOAD16_S: case WASM_OP_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_I64_LOAD: case WASM_OP_I64_LOAD8_S: @@ -7131,35 +7249,35 @@ re_scan: case WASM_OP_I64_LOAD16_U: case WASM_OP_I64_LOAD32_S: case WASM_OP_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_F32_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F32); break; case WASM_OP_F64_LOAD: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_F64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_F64); break; /* store */ case WASM_OP_I32_STORE: case WASM_OP_I32_STORE8: case WASM_OP_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_I64_STORE: case WASM_OP_I64_STORE8: case WASM_OP_I64_STORE16: case WASM_OP_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F32_STORE: POP_F32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_F64_STORE: POP_F64(); - POP_I32(); + POP_MEM_OFFSET(); break; default: break; @@ -7172,7 +7290,7 @@ re_scan: /* reserved byte 0x00 */ bh_assert(*p == 0x00); p++; - PUSH_I32(); + PUSH_PAGE_COUNT(); module->possible_memory_grow = true; #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 @@ -7185,7 +7303,7 @@ re_scan: /* reserved byte 0x00 */ bh_assert(*p == 0x00); p++; - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, mem_offset_type); module->possible_memory_grow = true; #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ @@ -7536,7 +7654,7 @@ re_scan: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -7565,9 +7683,9 @@ re_scan: + module->memory_count > 0); - POP_I32(); - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -7582,9 +7700,9 @@ re_scan: + module->memory_count > 0); + POP_MEM_OFFSET(); POP_I32(); - POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); #if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 func->has_memory_operations = true; #endif @@ -7748,8 +7866,8 @@ re_scan: #endif if (opcode1 != WASM_OP_ATOMIC_FENCE) { CHECK_MEMORY(); - read_leb_uint32(p, p_end, align); /* align */ - read_leb_uint32(p, p_end, mem_offset); /* offset */ + read_leb_uint32(p, p_end, align); /* align */ + read_leb_mem_offset(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, mem_offset); #endif @@ -7759,18 +7877,20 @@ re_scan: #endif switch (opcode1) { case WASM_OP_ATOMIC_NOTIFY: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT32: POP_I64(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_WAIT64: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_FENCE: @@ -7781,26 +7901,26 @@ re_scan: case WASM_OP_ATOMIC_I32_LOAD: case WASM_OP_ATOMIC_I32_LOAD8_U: case WASM_OP_ATOMIC_I32_LOAD16_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I32); break; case WASM_OP_ATOMIC_I32_STORE: case WASM_OP_ATOMIC_I32_STORE8: case WASM_OP_ATOMIC_I32_STORE16: POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_I64_LOAD: case WASM_OP_ATOMIC_I64_LOAD8_U: case WASM_OP_ATOMIC_I64_LOAD16_U: case WASM_OP_ATOMIC_I64_LOAD32_U: - POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I64); + POP_AND_PUSH(mem_offset_type, VALUE_TYPE_I64); break; case WASM_OP_ATOMIC_I64_STORE: case WASM_OP_ATOMIC_I64_STORE8: case WASM_OP_ATOMIC_I64_STORE16: case WASM_OP_ATOMIC_I64_STORE32: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); break; case WASM_OP_ATOMIC_RMW_I32_ADD: case WASM_OP_ATOMIC_RMW_I32_ADD8_U: @@ -7820,7 +7940,9 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_XCHG: case WASM_OP_ATOMIC_RMW_I32_XCHG8_U: case WASM_OP_ATOMIC_RMW_I32_XCHG16_U: - POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); + POP_I32(); + POP_MEM_OFFSET(); + PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_ADD: case WASM_OP_ATOMIC_RMW_I64_ADD8_U: @@ -7847,7 +7969,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_XCHG16_U: case WASM_OP_ATOMIC_RMW_I64_XCHG32_U: POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; case WASM_OP_ATOMIC_RMW_I32_CMPXCHG: @@ -7855,7 +7977,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I32_CMPXCHG16_U: POP_I32(); POP_I32(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I32(); break; case WASM_OP_ATOMIC_RMW_I64_CMPXCHG: @@ -7864,7 +7986,7 @@ re_scan: case WASM_OP_ATOMIC_RMW_I64_CMPXCHG32_U: POP_I64(); POP_I64(); - POP_I32(); + POP_MEM_OFFSET(); PUSH_I64(); break; default: diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f80d182df..71e7d54ee 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -162,7 +162,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, char *error_buf, uint32 error_buf_size) { WASMModule *module = module_inst->module; - uint32 inc_page_count, global_idx; + uint32 inc_page_count, global_idx, default_max_page; uint32 bytes_of_last_page, bytes_to_page_end; uint64 aux_heap_base, heap_offset = (uint64)num_bytes_per_page * init_page_count; @@ -171,7 +171,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, bool is_shared_memory = false; #if WASM_ENABLE_SHARED_MEMORY != 0 - is_shared_memory = flags & 0x02 ? true : false; + is_shared_memory = flags & SHARED_MEMORY_FLAG ? true : false; /* shared memory */ if (is_shared_memory && parent != NULL) { @@ -186,6 +186,14 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, (void)flags; #endif /* end of WASM_ENABLE_SHARED_MEMORY */ +#if WASM_ENABLE_MEMORY64 != 0 + if (flags & MEMORY64_FLAG) { + memory->is_memory64 = 1; + } +#endif + default_max_page = + memory->is_memory64 ? DEFAULT_MEM64_MAX_PAGES : DEFAULT_MAX_PAGES; + if (heap_size > 0 && module_inst->module->malloc_function != (uint32)-1 && module_inst->module->free_function != (uint32)-1) { /* Disable app heap, use malloc/free function exported @@ -195,7 +203,8 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, /* If initial memory is the largest size allowed, disallowing insert host * managed heap */ - if (heap_size > 0 && heap_offset == MAX_LINEAR_MEMORY_SIZE) { + if (heap_size > 0 + && heap_offset == GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)) { set_error_buf(error_buf, error_buf_size, "failed to insert app heap into linear memory, " "try using `--heap-size=0` option"); @@ -253,8 +262,18 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, && global_idx < module_inst->e->global_count); global_addr = module_inst->global_data + module_inst->e->globals[global_idx].data_offset; - *(uint32 *)global_addr = (uint32)aux_heap_base; - LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + /* For memory64, the global value should be i64 */ + *(uint64 *)global_addr = aux_heap_base; + } + else +#endif + { + /* For memory32, the global value should be i32 */ + *(uint32 *)global_addr = (uint32)aux_heap_base; + } + LOG_VERBOSE("Reset __heap_base global to %lu", aux_heap_base); } else { /* Insert app heap before new page */ @@ -267,14 +286,15 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, } init_page_count += inc_page_count; max_page_count += inc_page_count; - if (init_page_count > DEFAULT_MAX_PAGES) { + if (init_page_count > default_max_page) { set_error_buf(error_buf, error_buf_size, "failed to insert app heap into linear memory, " "try using `--heap-size=0` option"); return NULL; } - if (max_page_count > DEFAULT_MAX_PAGES) - max_page_count = DEFAULT_MAX_PAGES; + + if (max_page_count > default_max_page) + max_page_count = default_max_page; } LOG_VERBOSE("Memory instantiate:"); @@ -283,14 +303,16 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); max_memory_data_size = (uint64)num_bytes_per_page * max_page_count; - bh_assert(max_memory_data_size <= MAX_LINEAR_MEMORY_SIZE); + bh_assert(max_memory_data_size + <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); (void)max_memory_data_size; bh_assert(memory != NULL); if (wasm_allocate_linear_memory(&memory->memory_data, is_shared_memory, - num_bytes_per_page, init_page_count, - max_page_count, &memory_data_size) + memory->is_memory64, num_bytes_per_page, + init_page_count, max_page_count, + &memory_data_size) != BHT_OK) { set_error_buf(error_buf, error_buf_size, "allocate linear memory failed"); @@ -1947,7 +1969,8 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, WASMGlobalInstance *globals = NULL, *global; WASMTableInstance *first_table; uint32 global_count, i; - uint32 base_offset, length, extra_info_offset; + uint32 length, extra_info_offset; + mem_offset_t base_offset; uint32 module_inst_struct_size = offsetof(WASMModuleInstance, global_table_data.bytes); uint64 module_inst_mem_inst_size; @@ -2305,10 +2328,12 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, (uint64)memory->num_bytes_per_page * memory->cur_page_count; bh_assert(memory_data || memory_size == 0); - bh_assert(data_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_I32_CONST - || data_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL); + bh_assert( + data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL + || (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + && !memory->is_memory64) + || (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I64_CONST + && memory->is_memory64)); if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { if (!check_global_init_expr(module, @@ -2319,17 +2344,37 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, if (!globals || globals[data_seg->base_offset.u.global_index].type - != VALUE_TYPE_I32) { + != (memory->is_memory64 ? VALUE_TYPE_I64 + : VALUE_TYPE_I32)) { set_error_buf(error_buf, error_buf_size, "data segment does not fit"); goto fail; } - base_offset = - globals[data_seg->base_offset.u.global_index].initial_value.i32; +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + base_offset = + (uint64)globals[data_seg->base_offset.u.global_index] + .initial_value.i64; + } + else +#endif + { + base_offset = + (uint32)globals[data_seg->base_offset.u.global_index] + .initial_value.i32; + } } else { - base_offset = (uint32)data_seg->base_offset.u.i32; +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + base_offset = (uint64)data_seg->base_offset.u.i64; + } + else +#endif + { + base_offset = (uint32)data_seg->base_offset.u.i32; + } } /* check offset */ diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 5933e6a9c..3b01f05cd 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -103,7 +103,7 @@ struct WASMMemoryInstance { /* Whether the memory is shared */ uint8 is_shared_memory; - /* TODO: Memory64 whether the memory has 64-bit memory addresses */ + /* Whether the memory has 64-bit memory addresses */ uint8 is_memory64; /* Reference count of the memory instance: diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index 7aa3444f9..2ac381033 100644 --- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -17,7 +17,7 @@ void wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); uint32 -wasm_runtime_module_realloc(wasm_module_inst_t module, uint32 ptr, uint32 size, +wasm_runtime_module_realloc(wasm_module_inst_t module, uint64 ptr, uint64 size, void **p_native_addr); /* clang-format off */ diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index c9a7e5897..c76abf137 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -65,9 +65,11 @@ os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) /* integer overflow */ return NULL; +#if WASM_ENABLE_MEMORY64 == 0 if (request_size > 16 * (uint64)UINT32_MAX) - /* at most 16 G is allowed */ + /* at most 64 G is allowed */ return NULL; +#endif if (prot & MMAP_PROT_READ) map_prot |= PROT_READ; diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 8027abde0..98f5c1e63 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -14,7 +14,7 @@ import time """ The script itself has to be put under the same directory with the "spec". -To run a single non-GC case with interpreter mode: +To run a single non-GC and non-memory64 case with interpreter mode: cd workspace python3 runtest.py --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \ spec/test/core/xxx.wast @@ -22,7 +22,7 @@ To run a single non-GC case with aot mode: cd workspace python3 runtest.py --aot --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \ --aot-compiler wamrc spec/test/core/xxx.wast -To run a single GC case: +To run a single GC case or single memory64 case: cd workspace python3 runtest.py --wast2wasm spec/interpreter/wasm --interpreter iwasm \ --aot-compiler wamrc --gc spec/test/core/xxx.wast @@ -78,6 +78,7 @@ def ignore_the_case( multi_thread_flag=False, simd_flag=False, gc_flag=False, + memory64_flag=False, xip_flag=False, eh_flag=False, qemu_flag=False, @@ -162,6 +163,7 @@ def test_case( clean_up_flag=True, verbose_flag=True, gc_flag=False, + memory64_flag=False, qemu_flag=False, qemu_firmware="", log="", @@ -169,7 +171,7 @@ def test_case( ): CMD = [sys.executable, "runtest.py"] CMD.append("--wast2wasm") - CMD.append(WAST2WASM_CMD if not gc_flag else SPEC_INTERPRETER_CMD) + CMD.append(WAST2WASM_CMD if not gc_flag and not memory64_flag else SPEC_INTERPRETER_CMD) CMD.append("--interpreter") if sgx_flag: CMD.append(IWASM_SGX_CMD) @@ -217,6 +219,9 @@ def test_case( if gc_flag: CMD.append("--gc") + if memory64_flag: + CMD.append("--memory64") + if log != "": CMD.append("--log-dir") CMD.append(log) @@ -283,6 +288,7 @@ def test_suite( clean_up_flag=True, verbose_flag=True, gc_flag=False, + memory64_flag=False, parl_flag=False, qemu_flag=False, qemu_firmware="", @@ -325,6 +331,7 @@ def test_suite( multi_thread_flag, simd_flag, gc_flag, + memory64_flag, xip_flag, eh_flag, qemu_flag, @@ -357,6 +364,7 @@ def test_suite( clean_up_flag, verbose_flag, gc_flag, + memory64_flag, qemu_flag, qemu_firmware, log, @@ -382,6 +390,7 @@ def test_suite( else: print(f"----- Run the whole spec test suite -----") for case_path in case_list: + print(case_path) try: test_case( str(case_path), @@ -396,6 +405,7 @@ def test_suite( clean_up_flag, verbose_flag, gc_flag, + memory64_flag, qemu_flag, qemu_firmware, log, @@ -521,6 +531,13 @@ def main(): dest="gc_flag", help="Running with GC feature", ) + parser.add_argument( + "--memory64", + action="store_true", + default=False, + dest="memory64_flag", + help="Running with memory64 feature", + ) parser.add_argument( "cases", metavar="path_to__case", @@ -563,6 +580,7 @@ def main(): options.clean_up_flag, options.verbose_flag, options.gc_flag, + options.memory64_flag, options.parl_flag, options.qemu_flag, options.qemu_firmware, @@ -589,6 +607,7 @@ def main(): options.clean_up_flag, options.verbose_flag, options.gc_flag, + options.memory64_flag, options.qemu_flag, options.qemu_firmware, options.log, diff --git a/tests/wamr-test-suites/spec-test-script/memory64.patch b/tests/wamr-test-suites/spec-test-script/memory64.patch new file mode 100644 index 000000000..739a1df60 --- /dev/null +++ b/tests/wamr-test-suites/spec-test-script/memory64.patch @@ -0,0 +1,28 @@ +diff --git a/test/core/memory.wast b/test/core/memory.wast +index 1dd5b84..497b69f 100644 +--- a/test/core/memory.wast ++++ b/test/core/memory.wast +@@ -76,17 +76,17 @@ + "memory size must be at most 65536 pages (4GiB)" + ) + +-(assert_invalid ++(assert_malformed + (module quote "(memory 0x1_0000_0000)") +- "memory size must be at most 65536 pages (4GiB)" ++ "i32 constant out of range" + ) +-(assert_invalid ++(assert_malformed + (module quote "(memory 0x1_0000_0000 0x1_0000_0000)") +- "memory size must be at most 65536 pages (4GiB)" ++ "i32 constant out of range" + ) +-(assert_invalid ++(assert_malformed + (module quote "(memory 0 0x1_0000_0000)") +- "memory size must be at most 65536 pages (4GiB)" ++ "i32 constant out of range" + ) + + (module diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index 344e4fd44..13229d977 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -313,6 +313,9 @@ parser.add_argument('--multi-thread', default=False, action='store_true', parser.add_argument('--gc', default=False, action='store_true', help='Test with GC') +parser.add_argument('--memory64', default=False, action='store_true', + help='Test with Memory64') + parser.add_argument('--qemu', default=False, action='store_true', help="Enable QEMU") @@ -1071,7 +1074,7 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): log("Compiling WASM to '%s'" % wasm_tempfile) # default arguments - if opts.gc: + if opts.gc or opts.memory64: cmd = [opts.wast2wasm, "-u", "-d", wast_tempfile, "-o", wasm_tempfile] elif opts.eh: cmd = [opts.wast2wasm, "--enable-thread", "--no-check", "--enable-exceptions", "--enable-tail-call", wast_tempfile, "-o", wasm_tempfile ] @@ -1116,6 +1119,9 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = ' cmd.append("--enable-gc") cmd.append("--enable-tail-call") + if opts.memory64: + cmd.append("--enable-memory64") + if output == 'object': cmd.append("--format=object") elif output == 'ir': diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 933583816..0c56acac4 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -23,6 +23,7 @@ function help() echo "-p enable multi thread feature" echo "-S enable SIMD feature" echo "-G enable GC feature" + echo "-W enable memory64 feature" echo "-X enable XIP feature" echo "-e enable exception handling" echo "-x test SGX" @@ -50,6 +51,7 @@ ENABLE_MULTI_THREAD=0 COLLECT_CODE_COVERAGE=0 ENABLE_SIMD=0 ENABLE_GC=0 +ENABLE_MEMORY64=0 ENABLE_XIP=0 ENABLE_EH=0 ENABLE_DEBUG_VERSION=0 @@ -72,7 +74,7 @@ WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2" TARGET_LIST=("AARCH64" "AARCH64_VFP" "ARMV7" "ARMV7_VFP" "THUMBV7" "THUMBV7_VFP" \ "RISCV32" "RISCV32_ILP32F" "RISCV32_ILP32D" "RISCV64" "RISCV64_LP64F" "RISCV64_LP64D") -while getopts ":s:cabgvt:m:MCpSXexwPGQF:j:T:" opt +while getopts ":s:cabgvt:m:MCpSXexwWPGQF:j:T:" opt do OPT_PARSED="TRUE" case $opt in @@ -131,6 +133,10 @@ do echo "enable multi module feature" ENABLE_MULTI_MODULE=1 ;; + W) + echo "enable wasm64(memory64) feature" + ENABLE_MEMORY64=1 + ;; C) echo "enable code coverage" COLLECT_CODE_COVERAGE=1 @@ -478,6 +484,29 @@ function spec_test() popd fi + # update memory64 cases + if [[ ${ENABLE_MEMORY64} == 1 ]]; then + echo "checkout spec for memory64 proposal" + + popd + rm -fr spec + # check spec test cases for memory64 + git clone -b main --single-branch https://github.com/WebAssembly/memory64.git spec + pushd spec + + git restore . && git clean -ffd . + # Reset to commit: "Merge remote-tracking branch 'upstream/main' into merge2" + git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6 + git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast + git apply ../../spec-test-script/ignore_cases.patch + git apply ../../spec-test-script/memory64.patch + + echo "compile the reference intepreter" + pushd interpreter + make + popd + fi + popd echo $(pwd) @@ -488,7 +517,7 @@ function spec_test() local ARGS_FOR_SPEC_TEST="" - # multi-module only enable in interp mode + # multi-module only enable in interp mode and aot mode if [[ 1 == ${ENABLE_MULTI_MODULE} ]]; then if [[ $1 == 'classic-interp' || $1 == 'fast-interp' || $1 == 'aot' ]]; then ARGS_FOR_SPEC_TEST+="-M " @@ -537,6 +566,13 @@ function spec_test() ARGS_FOR_SPEC_TEST+="--gc " fi + # wasm64(memory64) is only enabled in interp and aot mode + if [[ 1 == ${ENABLE_MEMORY64} ]]; then + if [[ $1 == 'classic-interp' || $1 == 'aot' ]]; then + ARGS_FOR_SPEC_TEST+="--memory64 " + fi + fi + if [[ ${ENABLE_QEMU} == 1 ]]; then ARGS_FOR_SPEC_TEST+="--qemu " ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} " @@ -833,6 +869,12 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MULTI_MODULE=0" fi + if [[ ${ENABLE_MEMORY64} == 1 ]];then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MEMORY64=1" + else + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MEMORY64=0" + fi + if [[ ${ENABLE_MULTI_THREAD} == 1 ]];then EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_PTHREAD=1" fi