Implement GC (Garbage Collection) feature for interpreter, AOT and LLVM-JIT (#3125)

Implement the GC (Garbage Collection) feature for interpreter mode,
AOT mode and LLVM-JIT mode, and support most features of the latest
spec proposal, and also enable the stringref feature.

Use `cmake -DWAMR_BUILD_GC=1/0` to enable/disable the feature,
and `wamrc --enable-gc` to generate the AOT file with GC supported.

And update the AOT file version from 2 to 3 since there are many AOT
ABI breaks, including the changes of AOT file format, the changes of
AOT module/memory instance layouts, the AOT runtime APIs for the
AOT code to invoke and so on.
This commit is contained in:
Wenyong Huang
2024-02-06 20:47:11 +08:00
committed by GitHub
parent 5931aaacbe
commit 16a4d71b34
98 changed files with 33469 additions and 3159 deletions

View File

@ -8461,7 +8461,7 @@ jit_codegen_compile_call_to_llvm_jit(const WASMType *func_type)
/* r10 = outs_area->lp */
{
x86::Mem m(regs_i64[hreg_info->exec_env_hreg_index],
(uint32)offsetof(WASMExecEnv, wasm_stack.s.top));
(uint32)offsetof(WASMExecEnv, wasm_stack.top));
a.mov(reg_lp, m);
a.add(reg_lp, (uint32)offsetof(WASMInterpFrame, lp));
}
@ -8701,15 +8701,15 @@ fast_jit_alloc_frame(WASMExecEnv *exec_env, uint32 param_cell_num,
* frame to store the function results from jit function to call,
* the second is the frame for the jit function
*/
if ((uint8 *)exec_env->wasm_stack.s.top + size_frame1 + size_frame2
> exec_env->wasm_stack.s.top_boundary) {
if ((uint8 *)exec_env->wasm_stack.top + size_frame1 + size_frame2
> exec_env->wasm_stack.top_boundary) {
wasm_set_exception(module_inst, "wasm operand stack overflow");
return NULL;
}
/* Allocate the frame */
frame = (WASMInterpFrame *)exec_env->wasm_stack.s.top;
exec_env->wasm_stack.s.top += size_frame1;
frame = (WASMInterpFrame *)exec_env->wasm_stack.top;
exec_env->wasm_stack.top += size_frame1;
frame->function = NULL;
frame->ip = NULL;
@ -9073,9 +9073,9 @@ jit_codegen_compile_call_to_fast_jit(const WASMModule *module, uint32 func_idx)
/* rdx = exec_env->cur_frame->prev_frame */
a.mov(x86::rdx,
x86::ptr(x86::rsi, (uint32)offsetof(WASMInterpFrame, prev_frame)));
/* exec_env->wasm_stack.s.top = cur_frame */
/* exec_env->wasm_stack.top = cur_frame */
{
x86::Mem m(x86::rdi, offsetof(WASMExecEnv, wasm_stack.s.top));
x86::Mem m(x86::rdi, offsetof(WASMExecEnv, wasm_stack.top));
a.mov(m, x86::rsi);
}
/* exec_env->cur_frame = prev_frame */

View File

@ -396,8 +396,9 @@ handle_func_return(JitCompContext *cc, JitBlock *block)
#endif
#if WASM_ENABLE_PERF_PROFILING != 0
/* time_end = os_time_get_boot_us() */
if (!jit_emit_callnative(cc, os_time_get_boot_us, time_end, NULL, 0)) {
/* time_end = os_time_thread_cputime_us() */
if (!jit_emit_callnative(cc, os_time_thread_cputime_us, time_end, NULL,
0)) {
return false;
}
/* time_start = cur_frame->time_started */
@ -449,9 +450,9 @@ handle_func_return(JitCompContext *cc, JitBlock *block)
}
/* Free stack space of the current frame:
exec_env->wasm_stack.s.top = cur_frame */
exec_env->wasm_stack.top = cur_frame */
GEN_INSN(STPTR, cc->fp_reg, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top)));
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.top)));
/* Set the prev_frame as the current frame:
exec_env->cur_frame = prev_frame */
GEN_INSN(STPTR, prev_frame, cc->exec_env_reg,

View File

@ -499,7 +499,9 @@ jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
if (UINTPTR_MAX == UINT64_MAX) {
offset_i32 = jit_cc_new_reg_I32(cc);
offset = jit_cc_new_reg_I64(cc);
GEN_INSN(SHL, offset_i32, elem_idx, NEW_CONST(I32, 2));
/* Calculate offset by pointer size (elem_idx *
* sizeof(table_elem_type_t)) */
GEN_INSN(SHL, offset_i32, elem_idx, NEW_CONST(I32, 3));
GEN_INSN(I32TOI64, offset, offset_i32);
}
else {

View File

@ -46,7 +46,8 @@ jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx)
GEN_INSN(I32TOI64, elem_idx_long, elem_idx);
offset = jit_cc_new_reg_I64(cc);
GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(uint32)));
GEN_INSN(MUL, offset, elem_idx_long,
NEW_CONST(I64, sizeof(table_elem_type_t)));
res = jit_cc_new_reg_I32(cc);
tbl_elems = get_table_elems_reg(cc->jit_frame, tbl_idx);
@ -77,7 +78,8 @@ jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx)
GEN_INSN(I32TOI64, elem_idx_long, elem_idx);
offset = jit_cc_new_reg_I64(cc);
GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(uint32)));
GEN_INSN(MUL, offset, elem_idx_long,
NEW_CONST(I64, sizeof(table_elem_type_t)));
tbl_elems = get_table_elems_reg(cc->jit_frame, tbl_idx);
GEN_INSN(STI32, elem_val, tbl_elems, offset);
@ -92,14 +94,15 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 seg_idx,
uint32 dst_offset, uint32 len, uint32 src_offset)
{
WASMTableInstance *tbl;
uint32 tbl_sz;
WASMTableSeg *tbl_seg = inst->module->table_segments + seg_idx;
uint32 *tbl_seg_elems = NULL, tbl_seg_len = 0;
InitializerExpression *tbl_seg_init_values = NULL, *init_values;
uint32 tbl_sz, tbl_seg_len = 0, i;
table_elem_type_t *addr;
if (!bh_bitmap_get_bit(inst->e->common.elem_dropped, seg_idx)) {
/* table segment isn't dropped */
tbl_seg_elems = tbl_seg->func_indexes;
tbl_seg_len = tbl_seg->function_count;
tbl_seg_init_values = tbl_seg->init_values;
tbl_seg_len = tbl_seg->value_count;
}
if (offset_len_out_of_bounds(src_offset, len, tbl_seg_len))
@ -113,10 +116,13 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 seg_idx,
if (!len)
return 0;
bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems)
+ dst_offset * sizeof(uint32),
(uint32)((tbl_sz - dst_offset) * sizeof(uint32)),
tbl_seg_elems + src_offset, (uint32)(len * sizeof(uint32)));
addr =
(table_elem_type_t *)((uint8 *)tbl + offsetof(WASMTableInstance, elems)
+ dst_offset * sizeof(table_elem_type_t));
init_values = tbl_seg_init_values + src_offset;
for (i = 0; i < len; i++) {
addr[i] = (table_elem_type_t)(uintptr_t)init_values[+i].u.ref_index;
}
return 0;
out_of_bounds:
@ -175,12 +181,13 @@ wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx,
if (offset_len_out_of_bounds(src_offset, len, src_tbl_sz))
goto out_of_bounds;
bh_memmove_s((uint8 *)dst_tbl + offsetof(WASMTableInstance, elems)
+ dst_offset * sizeof(uint32),
(uint32)((dst_tbl_sz - dst_offset) * sizeof(uint32)),
(uint8 *)src_tbl + offsetof(WASMTableInstance, elems)
+ src_offset * sizeof(uint32),
(uint32)(len * sizeof(uint32)));
bh_memmove_s(
(uint8 *)dst_tbl + offsetof(WASMTableInstance, elems)
+ dst_offset * sizeof(table_elem_type_t),
(uint32)((dst_tbl_sz - dst_offset) * sizeof(table_elem_type_t)),
(uint8 *)src_tbl + offsetof(WASMTableInstance, elems)
+ src_offset * sizeof(table_elem_type_t),
(uint32)(len * sizeof(table_elem_type_t)));
return 0;
out_of_bounds:
@ -272,7 +279,7 @@ fail:
static int
wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst_offset,
uint32 val, uint32 len)
uintptr_t val, uint32 len)
{
WASMTableInstance *tbl;
uint32 tbl_sz;

View File

@ -97,9 +97,9 @@ jit_frontend_get_table_inst_offset(const WASMModule *module, uint32 tbl_idx)
offset += (uint32)offsetof(WASMTableInstance, elems);
#if WASM_ENABLE_MULTI_MODULE != 0
offset += (uint32)sizeof(uint32) * table->max_size;
offset += (uint32)sizeof(table_elem_type_t) * table->max_size;
#else
offset += (uint32)sizeof(uint32)
offset += (uint32)sizeof(table_elem_type_t)
* (table->possible_grow ? table->max_size : table->init_size);
#endif
@ -1157,21 +1157,22 @@ init_func_translation(JitCompContext *cc)
func_inst = jit_cc_new_reg_ptr(cc);
#if WASM_ENABLE_PERF_PROFILING != 0
time_started = jit_cc_new_reg_I64(cc);
/* Call os_time_get_boot_us() to get time_started firstly
/* Call os_time_thread_cputime_us() to get time_started firstly
as there is stack frame switching below, calling native in them
may cause register spilling work inproperly */
if (!jit_emit_callnative(cc, os_time_get_boot_us, time_started, NULL, 0)) {
if (!jit_emit_callnative(cc, os_time_thread_cputime_us, time_started, NULL,
0)) {
return NULL;
}
#endif
#endif
/* top = exec_env->wasm_stack.s.top */
/* top = exec_env->wasm_stack.top */
GEN_INSN(LDPTR, top, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top)));
/* top_boundary = exec_env->wasm_stack.s.top_boundary */
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.top)));
/* top_boundary = exec_env->wasm_stack.top_boundary */
GEN_INSN(LDPTR, top_boundary, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top_boundary)));
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.top_boundary)));
/* frame_boundary = top + frame_size + outs_size */
GEN_INSN(ADD, frame_boundary, top, NEW_CONST(PTR, frame_size + outs_size));
/* if frame_boundary > top_boundary, throw stack overflow exception */
@ -1184,9 +1185,9 @@ init_func_translation(JitCompContext *cc)
/* Add first and then sub to reduce one used register */
/* new_top = frame_boundary - outs_size = top + frame_size */
GEN_INSN(SUB, new_top, frame_boundary, NEW_CONST(PTR, outs_size));
/* exec_env->wasm_stack.s.top = new_top */
/* exec_env->wasm_stack.top = new_top */
GEN_INSN(STPTR, new_top, cc->exec_env_reg,
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top)));
NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.top)));
/* frame_sp = frame->lp + local_size */
GEN_INSN(ADD, frame_sp, top,
NEW_CONST(PTR, offsetof(WASMInterpFrame, lp) + local_size));