Add support for multi-memory proposal in classic interpreter (#3742)

Implement multi-memory for classic-interpreter. Support core spec (and bulk memory) opcodes now,
and will support atomic opcodes, and add multi-memory export APIs in the future. 

PS: Multi-memory spec test patched a lot for linking test to adapt for multi-module implementation.
This commit is contained in:
Wenyong Huang
2024-08-21 12:22:23 +08:00
committed by GitHub
parent f4383a9e62
commit 1329e1d3e1
22 changed files with 1658 additions and 262 deletions

View File

@ -697,6 +697,44 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame)
#define read_leb_mem_offset(p, p_end, res) read_leb_uint32(p, p_end, res)
#endif
#if WASM_ENABLE_MULTI_MEMORY != 0
/* If the current memidx differs than the last cached one,
* update memory related information */
#define read_leb_memidx(p, p_end, res) \
do { \
read_leb_uint32(p, p_end, res); \
if (res != memidx_cached) { \
memory = wasm_get_memory_with_idx(module, res); \
linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); \
memidx_cached = res; \
} \
} while (0)
/* First read the alignment, then if it has flag indicating following memidx,
* read and update memory related information, if it differs than the
* last(cached) one. If it doesn't have flag reset the
* memory instance to the default memories[0] */
#define read_leb_memarg(p, p_end, res) \
do { \
read_leb_uint32(p, p_end, res); \
if (!(res & OPT_MEMIDX_FLAG)) \
memidx = 0; \
else \
read_leb_uint32(p, p_end, memidx); \
if (memidx != memidx_cached) { \
memory = wasm_get_memory_with_idx(module, memidx); \
linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); \
memidx_cached = memidx; \
} \
} while (0)
#else
#define read_leb_memarg(p, p_end, res) \
do { \
read_leb_uint32(p, p_end, res); \
(void)res; \
} while (0)
#define read_leb_memidx(p, p_end, res) read_leb_memarg(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
@ -1567,6 +1605,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
if (memory)
is_memory64 = memory->is_memory64;
#endif
#if WASM_ENABLE_MULTI_MEMORY != 0
uint32 memidx = 0;
uint32 memidx_cached = (uint32)-1;
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0
uint8 *frame_ip_orig = NULL;
@ -4292,13 +4334,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4308,13 +4349,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4323,13 +4363,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4338,13 +4377,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4353,13 +4391,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4368,13 +4405,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4383,13 +4419,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4398,13 +4433,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4413,13 +4447,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4428,13 +4461,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4443,14 +4475,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
opcode = *(frame_ip - 1);
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4459,13 +4489,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
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);
(void)flags;
HANDLE_OP_END();
}
@ -4476,7 +4505,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
read_leb_mem_offset(frame_ip, frame_ip_end, offset);
frame_sp--;
addr = POP_MEM_OFFSET();
@ -4491,7 +4520,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
STORE_U32(maddr, frame_sp[1]);
}
CHECK_WRITE_WATCHPOINT(addr, offset);
(void)flags;
HANDLE_OP_END();
}
@ -4501,7 +4529,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 flags;
mem_offset_t offset, addr;
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
read_leb_mem_offset(frame_ip, frame_ip_end, offset);
frame_sp -= 2;
addr = POP_MEM_OFFSET();
@ -4519,7 +4547,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
GET_I64_FROM_ADDR(frame_sp + 1));
}
CHECK_WRITE_WATCHPOINT(addr, offset);
(void)flags;
HANDLE_OP_END();
}
@ -4531,7 +4558,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 sval;
opcode = *(frame_ip - 1);
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
read_leb_mem_offset(frame_ip, frame_ip_end, offset);
sval = (uint32)POP_I32();
addr = POP_MEM_OFFSET();
@ -4545,7 +4572,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
STORE_U16(maddr, (uint16)sval);
}
CHECK_WRITE_WATCHPOINT(addr, offset);
(void)flags;
HANDLE_OP_END();
}
@ -4558,7 +4584,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint64 sval;
opcode = *(frame_ip - 1);
read_leb_uint32(frame_ip, frame_ip_end, flags);
read_leb_memarg(frame_ip, frame_ip_end, flags);
read_leb_mem_offset(frame_ip, frame_ip_end, offset);
sval = (uint64)POP_I64();
addr = POP_MEM_OFFSET();
@ -4576,29 +4602,27 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
STORE_U32(maddr, (uint32)sval);
}
CHECK_WRITE_WATCHPOINT(addr, offset);
(void)flags;
HANDLE_OP_END();
}
/* memory size and memory grow instructions */
HANDLE_OP(WASM_OP_MEMORY_SIZE)
{
uint32 reserved;
read_leb_uint32(frame_ip, frame_ip_end, reserved);
uint32 mem_idx;
read_leb_memidx(frame_ip, frame_ip_end, mem_idx);
PUSH_PAGE_COUNT(memory->cur_page_count);
(void)reserved;
HANDLE_OP_END();
}
HANDLE_OP(WASM_OP_MEMORY_GROW)
{
uint32 reserved, delta,
prev_page_count = memory->cur_page_count;
uint32 mem_idx, delta, prev_page_count;
read_leb_uint32(frame_ip, frame_ip_end, reserved);
read_leb_memidx(frame_ip, frame_ip_end, mem_idx);
prev_page_count = memory->cur_page_count;
delta = (uint32)POP_PAGE_COUNT();
if (!wasm_enlarge_memory(module, delta)) {
if (!wasm_enlarge_memory_with_idx(module, delta, mem_idx)) {
/* failed to memory.grow, return -1 */
PUSH_PAGE_COUNT(-1);
}
@ -4614,7 +4638,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#endif
}
(void)reserved;
HANDLE_OP_END();
}
@ -5610,8 +5633,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 *data;
read_leb_uint32(frame_ip, frame_ip_end, segment);
#if WASM_ENABLE_MULTI_MEMORY != 0
read_leb_memidx(frame_ip, frame_ip_end, memidx);
#else
/* skip memory index */
frame_ip++;
#endif
bytes = (uint64)(uint32)POP_I32();
offset = (uint64)(uint32)POP_I32();
@ -5660,33 +5687,54 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
{
mem_offset_t dst, src, len;
uint8 *mdst, *msrc;
uint64 dlen;
frame_ip += 2;
len = POP_MEM_OFFSET();
src = POP_MEM_OFFSET();
dst = POP_MEM_OFFSET();
#if WASM_ENABLE_MULTI_MEMORY != 0
/* dst memidx */
read_leb_memidx(frame_ip, frame_ip_end, memidx);
#else
/* skip dst memidx */
frame_ip += 1;
#endif
#if WASM_ENABLE_THREAD_MGR != 0
linear_mem_size = get_linear_mem_size();
#endif
/* dst boundary check */
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else
if ((uint64)(uint32)src + len > linear_mem_size)
if ((uint64)dst + len > linear_mem_size)
goto out_of_bounds;
msrc = memory->memory_data + (uint32)src;
mdst = memory->memory_data + dst;
#endif
dlen = linear_mem_size - dst;
if ((uint64)(uint32)dst + len > linear_mem_size)
#if WASM_ENABLE_MULTI_MEMORY != 0
/* src memidx */
read_leb_memidx(frame_ip, frame_ip_end, memidx);
#else
/* skip src memidx */
frame_ip += 1;
#endif
#if WASM_ENABLE_THREAD_MGR != 0
linear_mem_size = get_linear_mem_size();
#endif
/* src boundary check */
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
#else
if ((uint64)src + len > linear_mem_size)
goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst;
msrc = memory->memory_data + src;
#endif
/* allowing the destination and source to overlap */
#if WASM_ENABLE_MEMORY64 == 0
bh_memmove_s(mdst, (uint32)(linear_mem_size - dst),
msrc, (uint32)len);
/* allowing the destination and source to overlap */
bh_memmove_s(mdst, (uint32)dlen, msrc, (uint32)len);
#else
/* use memmove when memory64 is enabled since len
may be larger than UINT32_MAX */
@ -5698,7 +5746,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
{
mem_offset_t dst, len;
uint8 fill_val, *mdst;
#if WASM_ENABLE_MULTI_MEMORY != 0
read_leb_memidx(frame_ip, frame_ip_end, memidx);
#else
/* skip memory index */
frame_ip++;
#endif
len = POP_MEM_OFFSET();
fill_val = POP_I32();