Implement memory64 for classic interpreter (#3266)
Adding a new cmake flag (cache variable) `WAMR_BUILD_MEMORY64` to enable the memory64 feature, it can only be enabled on the 64-bit platform/target and can only use software boundary check. And when it is enabled, it can support both i32 and i64 linear memory types. The main modifications are: - wasm loader & mini-loader: loading and bytecode validating process - wasm runtime: memory instantiating process - classic-interpreter: wasm code executing process - Support memory64 memory in related runtime APIs - Modify main function type check when it's memory64 wasm file - Modify `wasm_runtime_invoke_native` and `wasm_runtime_invoke_native_raw` to handle registered native function pointer argument when memory64 is enabled - memory64 classic-interpreter spec test in `test_wamr.sh` and in CI Currently, it supports memory64 memory wasm file that uses core spec (including bulk memory proposal) opcodes and threads opcodes. ps. https://github.com/bytecodealliance/wasm-micro-runtime/issues/3091 https://github.com/bytecodealliance/wasm-micro-runtime/pull/3240 https://github.com/bytecodealliance/wasm-micro-runtime/pull/3260
This commit is contained in:
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user