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:
@ -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 */
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
|
||||
Reference in New Issue
Block a user