Răsfoiți Sursa

[GC] Fix frame ref not cleared issue in classic and fast interpreter (#2206)

Xu Jun 2 ani în urmă
părinte
comite
9fd8480107

+ 1 - 1
core/iwasm/common/gc/gc_object.c

@@ -715,7 +715,7 @@ wasm_object_get_ref_list(WASMObjectRef obj, bool *p_is_compact_mode,
         WASMArrayType *type = (WASMArrayType *)rtt_type->defined_type;
         if (wasm_is_type_reftype(type->elem_type)) {
             *p_is_compact_mode = true;
-            *p_ref_num = (uint16)wasm_array_obj_length((WASMArrayObjectRef)obj);
+            *p_ref_num = wasm_array_obj_length((WASMArrayObjectRef)obj);
             *p_ref_start_offset = (uint16)offsetof(WASMArrayObject, elem_data);
         }
         else {

+ 49 - 11
core/iwasm/interpreter/wasm_interp_classic.c

@@ -349,7 +349,8 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
     memset(frame_ref, 0, cell_num);
 
     for (i = 0, j = 0; i < func->param_count; i++) {
-        if (wasm_is_type_reftype(func->param_types[i])) {
+        if (wasm_is_type_reftype(func->param_types[i])
+            && !wasm_is_reftype_i31ref(func->param_types[i])) {
             frame_ref[j++] = 1;
 #if UINTPTR_MAX == UINT64_MAX
             frame_ref[j++] = 1;
@@ -363,7 +364,8 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
     }
 
     for (i = 0; i < func->local_count; i++) {
-        if (wasm_is_type_reftype(func->local_types[i])) {
+        if (wasm_is_type_reftype(func->local_types[i])
+            && !wasm_is_reftype_i31ref(func->local_types[i])) {
             frame_ref[j++] = 1;
 #if UINTPTR_MAX == UINT64_MAX
             frame_ref[j++] = 1;
@@ -428,6 +430,11 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
         *frame_ref_tmp = *(frame_ref_tmp + 1) = 1; \
         frame_sp += 2;                             \
     } while (0)
+#define PUSH_I31REF(value)                \
+    do {                                  \
+        PUT_REF_TO_ADDR(frame_sp, value); \
+        frame_sp += 2;                    \
+    } while (0)
 #else
 #define PUSH_REF(value)                      \
     do {                                     \
@@ -436,6 +443,11 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
         *frame_ref_tmp = 1;                  \
         frame_sp++;                          \
     } while (0)
+#define PUSH_I31REF(value)                \
+    do {                                  \
+        PUT_REF_TO_ADDR(frame_sp, value); \
+        frame_sp++;                       \
+    } while (0)
 #endif
 
 #define PUSH_CSP(_label_type, param_cell_num, cell_num, _target_addr) \
@@ -1100,11 +1112,13 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
         && wasm_is_type_reftype(func_type->types[cur_func->param_count])) {
         frame_ref = (uint8 *)prev_frame->csp_boundary
                     + (unsigned)(uintptr_t)(prev_frame->sp - prev_frame->lp);
+        if (!wasm_is_reftype_i31ref(func_type->types[cur_func->param_count])) {
 #if UINTPTR_MAX == UINT64_MAX
-        *frame_ref = *(frame_ref + 1) = 1;
+            *frame_ref = *(frame_ref + 1) = 1;
 #else
-        *frame_ref = 1;
+            *frame_ref = 1;
 #endif
+        }
     }
 #endif
 
@@ -1805,6 +1819,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         *(frame_sp - 1) = *frame_sp;
                 }
 
+#if WASM_ENABLE_GC != 0
+                frame_ref_tmp = FRAME_REF(frame_sp);
+                *frame_ref_tmp = 0;
+#if UINTPTR_MAX == UINT64_MAX
+                *(frame_ref_tmp + 1) = 0;
+#endif
+#endif
                 (void)vec_len;
                 HANDLE_OP_END();
             }
@@ -2088,7 +2109,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             &field_value);
 
                         field_type = struct_type->fields[field_idx].field_type;
-                        if (wasm_is_type_reftype(field_type)) {
+                        if (wasm_is_reftype_i31ref(field_type)) {
+                            PUSH_I31REF(field_value.gc_obj);
+                        }
+                        else if (wasm_is_type_reftype(field_type)) {
                             PUSH_REF(field_value.gc_obj);
                         }
                         else if (field_type == VALUE_TYPE_I32
@@ -2340,7 +2364,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             &array_elem);
                         elem_size_log = wasm_array_obj_elem_size_log(array_obj);
 
-                        if (wasm_is_type_reftype(array_type->elem_type)) {
+                        if (wasm_is_reftype_i31ref(array_type->elem_type)) {
+                            PUSH_I31REF(array_elem.gc_obj);
+                        }
+                        else if (wasm_is_type_reftype(array_type->elem_type)) {
                             PUSH_REF(array_elem.gc_obj);
                         }
                         else if (elem_size_log < 3) {
@@ -2450,7 +2477,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
                         i31_val = POP_I32();
                         i31_obj = wasm_i31_obj_new(i31_val);
-                        PUSH_REF(i31_obj);
+                        PUSH_I31REF(i31_obj);
                         HANDLE_OP_END();
                     }
                     case WASM_OP_I31_GET_S:
@@ -2635,8 +2662,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     default:
 #if WASM_ENABLE_GC != 0
                         if (wasm_is_type_reftype(local_type)) {
-                            PUSH_REF(
-                                GET_REF_FROM_ADDR(frame_lp + local_offset));
+                            if (wasm_is_reftype_i31ref(local_type)) {
+                                PUSH_I31REF(
+                                    GET_REF_FROM_ADDR(frame_lp + local_offset));
+                            }
+                            else {
+                                PUSH_REF(
+                                    GET_REF_FROM_ADDR(frame_lp + local_offset));
+                            }
                         }
                         else
 #endif
@@ -2766,10 +2799,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_GC == 0
                 PUSH_I32(*(uint32 *)global_addr);
 #else
-                if (!wasm_is_type_reftype(global->type))
+                if (!wasm_is_type_reftype(global->type)) {
                     PUSH_I32(*(uint32 *)global_addr);
-                else
+                }
+                else if (wasm_is_reftype_i31ref(global->type)) {
+                    PUSH_I31REF(GET_REF_FROM_ADDR((uint32 *)global_addr));
+                }
+                else {
                     PUSH_REF(GET_REF_FROM_ADDR((uint32 *)global_addr));
+                }
 #endif
                 /* clang-format on */
                 HANDLE_OP_END();

+ 216 - 24
core/iwasm/interpreter/wasm_interp_fast.c

@@ -313,7 +313,8 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
     memset(frame_ref, 0, cell_num);
 
     for (i = 0, j = 0; i < func->param_count; i++) {
-        if (wasm_is_type_reftype(func->param_types[i])) {
+        if (wasm_is_type_reftype(func->param_types[i])
+            && !wasm_is_reftype_i31ref(func->param_types[i])) {
             frame_ref[j++] = 1;
 #if UINTPTR_MAX == UINT64_MAX
             frame_ref[j++] = 1;
@@ -327,7 +328,8 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
     }
 
     for (i = 0; i < func->local_count; i++) {
-        if (wasm_is_type_reftype(func->local_types[i])) {
+        if (wasm_is_type_reftype(func->local_types[i])
+            && !wasm_is_reftype_i31ref(func->local_types[i])) {
             frame_ref[j++] = 1;
 #if UINTPTR_MAX == UINT64_MAX
             frame_ref[j++] = 1;
@@ -350,10 +352,14 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
 
 #if UINTPTR_MAX == UINT64_MAX
 #define SET_FRAME_REF(off) *FRAME_REF(off) = *FRAME_REF(off + 1) = 1
-#define CLEAR_FRAME_REF(off) *FRAME_REF(off) = *FRAME_REF(off + 1) = 0
+#define CLEAR_FRAME_REF(off)                          \
+    (unsigned)off >= local_cell_num                   \
+        ? (*FRAME_REF(off) = *FRAME_REF(off + 1) = 0) \
+        : (void)0
 #else
 #define SET_FRAME_REF(off) *FRAME_REF(off) = 1
-#define CLEAR_FRAME_REF(off) *FRAME_REF(off) = 0
+#define CLEAR_FRAME_REF(off) \
+    (unsigned)off >= local_cell_num ? (*FRAME_REF(off) = 0) : (void)0
 #endif
 
 #define FRAME_REF_FOR(frame, p) \
@@ -458,6 +464,14 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
         SET_FRAME_REF(opnd_off);          \
     } while (0)
 
+#define PUSH_I31REF(value)                \
+    do {                                  \
+        uint32 *addr_tmp;                 \
+        opnd_off = GET_OFFSET();          \
+        addr_tmp = frame_lp + opnd_off;   \
+        PUT_REF_TO_ADDR(addr_tmp, value); \
+    } while (0)
+
 #define POP_I32() (*(int32 *)(frame_lp + GET_OFFSET()))
 
 #define POP_F32() (*(float32 *)(frame_lp + GET_OFFSET()))
@@ -466,8 +480,8 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
 
 #define POP_F64() (GET_F64_FROM_ADDR(frame_lp + GET_OFFSET()))
 
-#define POP_REF()                                        \
-    (opnd_off = GET_OFFSET(), CLEAR_FRAME_REF(opnd_off), \
+#define POP_REF()                                                    \
+    (opnd_off = GET_OFFSET(), CLEAR_FRAME_REF((unsigned)(opnd_off)), \
      GET_REF_FROM_ADDR(frame_lp + opnd_off))
 
 #if WASM_ENABLE_GC != 0
@@ -818,6 +832,9 @@ trunc_f64_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp,
 
 static bool
 copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, uint32 arity,
+#if WASM_ENABLE_GC != 0
+                  uint8 *frame_ref,
+#endif
                   uint32 total_cell_num, const uint8 *cells,
                   const int16 *src_offsets, const uint16 *dst_offsets)
 {
@@ -825,11 +842,16 @@ copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, uint32 arity,
      * we use 2 steps to do the copy. First step, copy the src values
      * to a tmp buf. Second step, copy the values from tmp buf to dst.
      */
+    bool ret = false;
     uint32 buf[16] = { 0 }, i;
     uint32 *tmp_buf = buf;
     uint8 cell;
     int16 src, buf_index = 0;
     uint16 dst;
+#if WASM_ENABLE_GC != 0
+    uint8 ref_buf[4];
+    uint8 *tmp_ref_buf = ref_buf;
+#endif
 
     /* Allocate memory if the buf is not large enough */
     if (total_cell_num > sizeof(buf) / sizeof(uint32)) {
@@ -837,19 +859,41 @@ copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, uint32 arity,
         if (total_size >= UINT32_MAX
             || !(tmp_buf = wasm_runtime_malloc((uint32)total_size))) {
             wasm_set_exception(module, "allocate memory failed");
-            return false;
+            goto fail;
+        }
+    }
+
+#if WASM_ENABLE_GC != 0
+    if (total_cell_num > sizeof(ref_buf) / sizeof(uint8)) {
+        uint64 total_size = sizeof(uint8) * (uint64)total_cell_num;
+        if (total_size >= UINT32_MAX
+            || !(tmp_ref_buf = wasm_runtime_malloc((uint32)total_size))) {
+            wasm_set_exception(module, "allocate memory failed");
+            goto fail;
         }
     }
+#endif
 
     /* 1) Copy values from src to tmp buf */
     for (i = 0; i < arity; i++) {
         cell = cells[i * CELL_SIZE];
         src = src_offsets[i];
-        if (cell == 1)
+        if (cell == 1) {
             tmp_buf[buf_index] = frame_lp[src];
+#if WASM_ENABLE_GC != 0
+            tmp_ref_buf[buf_index] = frame_ref[src];
+            frame_ref[src] = 0;
+#endif
+        }
         else {
             tmp_buf[buf_index] = frame_lp[src];
             tmp_buf[buf_index + 1] = frame_lp[src + 1];
+#if WASM_ENABLE_GC != 0
+            tmp_ref_buf[buf_index] = frame_ref[src];
+            tmp_ref_buf[buf_index + 1] = frame_ref[src + 1];
+            frame_ref[src] = 0;
+            frame_ref[src + 1] = 0;
+#endif
         }
         buf_index += cell;
     }
@@ -859,22 +903,87 @@ copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, uint32 arity,
     for (i = 0; i < arity; i++) {
         cell = cells[i * CELL_SIZE];
         dst = dst_offsets[i];
-        if (cell == 1)
+        if (cell == 1) {
             frame_lp[dst] = tmp_buf[buf_index];
+#if WASM_ENABLE_GC != 0
+            frame_ref[dst] = tmp_ref_buf[buf_index];
+#endif
+        }
         else {
             frame_lp[dst] = tmp_buf[buf_index];
             frame_lp[dst + 1] = tmp_buf[buf_index + 1];
+#if WASM_ENABLE_GC != 0
+            frame_ref[dst] = tmp_ref_buf[buf_index];
+            frame_ref[dst + 1] = tmp_ref_buf[buf_index + 1];
+#endif
         }
         buf_index += cell;
     }
 
+    ret = true;
+
+fail:
     if (tmp_buf != buf) {
         wasm_runtime_free(tmp_buf);
     }
 
-    return true;
+#if WASM_ENABLE_GC != 0
+    if (tmp_ref_buf != ref_buf) {
+        wasm_runtime_free(tmp_ref_buf);
+    }
+#endif
+
+    return ret;
 }
 
+#if WASM_ENABLE_GC != 0
+#define RECOVER_BR_INFO()                                                  \
+    do {                                                                   \
+        uint32 arity;                                                      \
+        /* read arity */                                                   \
+        arity = read_uint32(frame_ip);                                     \
+        if (arity) {                                                       \
+            uint32 total_cell;                                             \
+            uint16 *dst_offsets = NULL;                                    \
+            uint8 *cells;                                                  \
+            int16 *src_offsets = NULL;                                     \
+            /* read total cell num */                                      \
+            total_cell = read_uint32(frame_ip);                            \
+            /* cells */                                                    \
+            cells = (uint8 *)frame_ip;                                     \
+            frame_ip += arity * CELL_SIZE;                                 \
+            /* src offsets */                                              \
+            src_offsets = (int16 *)frame_ip;                               \
+            frame_ip += arity * sizeof(int16);                             \
+            /* dst offsets */                                              \
+            dst_offsets = (uint16 *)frame_ip;                              \
+            frame_ip += arity * sizeof(uint16);                            \
+            if (arity == 1) {                                              \
+                if (cells[0] == 1) {                                       \
+                    frame_lp[dst_offsets[0]] = frame_lp[src_offsets[0]];   \
+                    CLEAR_FRAME_REF((unsigned)(src_offsets[0]));           \
+                    SET_FRAME_REF(dst_offsets[0]);                         \
+                }                                                          \
+                else if (cells[0] == 2) {                                  \
+                    frame_lp[dst_offsets[0]] = frame_lp[src_offsets[0]];   \
+                    frame_lp[dst_offsets[0] + 1] =                         \
+                        frame_lp[src_offsets[0] + 1];                      \
+                    CLEAR_FRAME_REF((unsigned)src_offsets[0]);             \
+                    CLEAR_FRAME_REF((unsigned)(src_offsets[0] + 1));       \
+                    SET_FRAME_REF((unsigned)dst_offsets[0]);               \
+                    SET_FRAME_REF((unsigned)(dst_offsets[0] + 1));         \
+                }                                                          \
+            }                                                              \
+            else {                                                         \
+                if (!copy_stack_values(module, frame_lp, arity, frame_ref, \
+                                       total_cell, cells, src_offsets,     \
+                                       dst_offsets))                       \
+                    goto got_exception;                                    \
+            }                                                              \
+        }                                                                  \
+        frame_ip = (uint8 *)LOAD_PTR(frame_ip);                            \
+    } while (0)
+#else
 #define RECOVER_BR_INFO()                                                   \
     do {                                                                    \
         uint32 arity;                                                       \
@@ -913,6 +1022,7 @@ copy_stack_values(WASMModuleInstance *module, uint32 *frame_lp, uint32 arity,
         }                                                                   \
         frame_ip = (uint8 *)LOAD_PTR(frame_ip);                             \
     } while (0)
+#endif
 
 #define SKIP_BR_INFO()                                                        \
     do {                                                                      \
@@ -1103,7 +1213,8 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
 #if WASM_ENABLE_GC != 0
     func_type = cur_func->u.func_import->func_type;
     if (func_type->result_count
-        && wasm_is_type_reftype(func_type->types[cur_func->param_count])) {
+        && wasm_is_type_reftype(func_type->types[cur_func->param_count])
+        && !wasm_is_reftype_i31ref(func_type->types[cur_func->param_count])) {
         frame_ref = prev_frame->frame_ref + prev_frame->ret_offset;
 #if UINTPTR_MAX == UINT64_MAX
         *frame_ref = *(frame_ref + 1) = 1;
@@ -1329,6 +1440,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #endif
 #if WASM_ENABLE_GC != 0
     register uint8 *frame_ref = NULL; /* cache of frame->ref */
+    uint32 local_cell_num = 0;
     int16 opnd_off;
 #endif
     uint8 *frame_ip_end = frame_ip + 1;
@@ -1338,7 +1450,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     int32 didx, val;
     uint8 *maddr = NULL;
     uint32 local_idx, local_offset, global_idx;
-    uint8 opcode, local_type, *global_addr;
+    uint8 opcode = 0, local_type, *global_addr;
 #if WASM_ENABLE_GC != 0
     WASMObjectRef gc_obj;
     WASMStructObjectRef struct_obj;
@@ -1488,6 +1600,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     else if (wasm_is_type_reftype(ret_types[ret_idx])) {
                         PUT_REF_TO_ADDR(prev_frame->lp + ret_offset,
                                         GET_OPERAND(void *, REF, off));
+                        if (!wasm_is_reftype_i31ref(ret_types[ret_idx])) {
+                            *(prev_frame->frame_ref + ret_offset) = 1;
+#if UINTPTR_MAX == UINT64_MAX
+                            *(prev_frame->frame_ref + ret_offset + 1) = 1;
+#endif
+                        }
                         ret_offset += REF_CELL_NUM;
                     }
 #endif
@@ -1646,9 +1764,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         PUT_REF_TO_ADDR(frame_lp + addr_ret,
                                         GET_REF_FROM_ADDR(frame_lp + addr2));
                 }
-                CLEAR_FRAME_REF(addr1);
-                CLEAR_FRAME_REF(addr2);
-                SET_FRAME_REF(addr_ret);
+                {
+                    uint8 orig_ref = *FRAME_REF(addr1);
+                    CLEAR_FRAME_REF(addr1);
+                    CLEAR_FRAME_REF(addr2);
+
+                    if (orig_ref) {
+                        /* If original ref is i31ref, should not set frameref
+                         * for target cell */
+                        SET_FRAME_REF(addr_ret);
+                    }
+                }
+
                 HANDLE_OP_END();
             }
 #endif
@@ -1924,7 +2051,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             &field_value);
 
                         field_type = struct_type->fields[field_idx].field_type;
-                        if (wasm_is_type_reftype(field_type)) {
+                        if (wasm_is_reftype_i31ref(field_type)) {
+                            PUSH_I31REF(field_value.gc_obj);
+                        }
+                        else if (wasm_is_type_reftype(field_type)) {
                             PUSH_REF(field_value.gc_obj);
                         }
                         else if (field_type == VALUE_TYPE_I32
@@ -2175,7 +2305,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             &array_elem);
                         elem_size_log = wasm_array_obj_elem_size_log(array_obj);
 
-                        if (wasm_is_type_reftype(array_type->elem_type)) {
+                        if (wasm_is_reftype_i31ref(array_type->elem_type)) {
+                            PUSH_I31REF(array_elem.gc_obj);
+                        }
+                        else if (wasm_is_type_reftype(array_type->elem_type)) {
                             PUSH_REF(array_elem.gc_obj);
                         }
                         else if (elem_size_log < 3) {
@@ -2284,7 +2417,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 
                         i31_val = POP_I32();
                         i31_obj = wasm_i31_obj_new(i31_val);
-                        PUSH_REF(i31_obj);
+                        PUSH_I31REF(i31_obj);
                         HANDLE_OP_END();
                     }
                     case WASM_OP_I31_GET_S:
@@ -2385,7 +2518,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                             if (opcode == WASM_OP_BR_ON_CAST_NULLABLE
                                 || opcode == WASM_OP_BR_ON_CAST_FAIL) {
                                 CLEAR_FRAME_REF(opnd_off);
-                                CLEAR_FRAME_REF(opnd_off_br);
+                                if (!wasm_is_reftype_i31ref(heap_type)) {
+                                    SET_FRAME_REF(opnd_off_br);
+                                }
                                 goto recover_br_info;
                             }
                         }
@@ -2412,7 +2547,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                         || opcode
                                                == WASM_OP_BR_ON_CAST_FAIL_NULLABLE))) {
                                 CLEAR_FRAME_REF(opnd_off);
-                                CLEAR_FRAME_REF(opnd_off_br);
+                                if (!wasm_is_reftype_i31ref(heap_type)) {
+                                    SET_FRAME_REF(opnd_off_br);
+                                }
                                 goto recover_br_info;
                             }
                         }
@@ -2507,9 +2644,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #else
                 if (!wasm_is_type_reftype(global->type))
                     frame_lp[addr_ret] = *(uint32 *)global_addr;
-                else
+                else {
                     PUT_REF_TO_ADDR(frame_lp + addr_ret,
                                     GET_REF_FROM_ADDR((uint32 *)global_addr));
+                    if (!wasm_is_reftype_i31ref(global->type)) {
+                        SET_FRAME_REF(addr_ret);
+                    }
+                }
 #endif
                 /* clang-format on */
                 HANDLE_OP_END();
@@ -2540,9 +2681,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #else
                 if (!wasm_is_type_reftype(global->type))
                     *(int32 *)global_addr = frame_lp[addr1];
-                else
+                else {
                     PUT_REF_TO_ADDR((uint32 *)global_addr,
                                     GET_REF_FROM_ADDR(frame_lp + addr1));
+                    CLEAR_FRAME_REF(addr1);
+                }
 #endif
                 /* clang-format on */
                 HANDLE_OP_END();
@@ -3799,6 +3942,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 addr1 = GET_OFFSET();
                 addr2 = GET_OFFSET();
                 frame_lp[addr2] = frame_lp[addr1];
+
+#if WASM_ENABLE_GC != 0
+                if (*FRAME_REF(addr1)) {
+                    CLEAR_FRAME_REF(addr1);
+                    SET_FRAME_REF(addr2);
+                }
+#endif
+
                 HANDLE_OP_END();
             }
 
@@ -3808,6 +3959,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 addr2 = GET_OFFSET();
                 frame_lp[addr2] = frame_lp[addr1];
                 frame_lp[addr2 + 1] = frame_lp[addr1 + 1];
+
+#if WASM_ENABLE_GC != 0
+                if (*FRAME_REF(addr1)) {
+                    CLEAR_FRAME_REF(addr1);
+                    CLEAR_FRAME_REF(addr1 + 1);
+                    SET_FRAME_REF(addr2);
+                    SET_FRAME_REF(addr2 + 1);
+                }
+#endif
+
                 HANDLE_OP_END();
             }
 
@@ -3833,6 +3994,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 frame_ip += values_count * sizeof(uint16);
 
                 if (!copy_stack_values(module, frame_lp, values_count,
+#if WASM_ENABLE_GC != 0
+                                       frame_ref,
+#endif
                                        total_cell, cells, src_offsets,
                                        dst_offsets))
                     goto got_exception;
@@ -3841,8 +4005,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             }
 
             HANDLE_OP(WASM_OP_SET_LOCAL)
+            {
+                opcode = WASM_OP_SET_LOCAL;
+                goto handle_op_set_tee_local;
+            }
             HANDLE_OP(WASM_OP_TEE_LOCAL)
             {
+                opcode = WASM_OP_TEE_LOCAL;
+            handle_op_set_tee_local:
+
                 GET_LOCAL_INDEX_TYPE_AND_OFFSET();
                 addr1 = GET_OFFSET();
 
@@ -3859,6 +4030,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                 else if (wasm_is_type_reftype(local_type)) {
                     PUT_REF_TO_ADDR((uint32 *)(frame_lp + local_offset),
                                     GET_REF_FROM_ADDR(frame_lp + addr1));
+                    if (opcode == WASM_OP_SET_LOCAL) {
+                        CLEAR_FRAME_REF(addr1);
+                    }
                 }
 #endif
                 else {
@@ -4794,6 +4968,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                     outs_area->lp,
                     GET_OPERAND(void *, REF,
                                 2 * (cur_func->param_count - i - 1)));
+                CLEAR_FRAME_REF(
+                    *(uint16 *)(frame_ip
+                                + (2 * (cur_func->param_count - i - 1))));
                 outs_area->lp += REF_CELL_NUM;
             }
 #endif
@@ -4862,6 +5039,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
 #if WASM_ENABLE_GC != 0
             /* area of frame_ref */
             all_cell_num += (cell_num_of_local_stack + 3) / 4;
+            /* cells occupied by locals, POP_REF should not clear frame_ref for
+             * these cells */
+            local_cell_num =
+                cur_func->param_cell_num + cur_func->local_cell_num;
 #endif
             /* param_cell_num, local_cell_num, const_cell_num and
                max_stack_cell_num are all no larger than UINT16_MAX (checked
@@ -4917,6 +5098,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
             return;
 
         RECOVER_CONTEXT(prev_frame);
+#if WASM_ENABLE_GC != 0
+        local_cell_num = cur_func->param_cell_num + cur_func->local_cell_num;
+#endif
         HANDLE_OP_END();
     }
 
@@ -5013,9 +5197,15 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
              i;
     /* This frame won't be used by JITed code, so only allocate interp
        frame here.  */
-    unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num);
+    unsigned frame_size;
     char exception[EXCEPTION_BUF_LEN];
 
+#if WASM_ENABLE_GC != 0
+    all_cell_num += (all_cell_num + 3) / 4;
+#endif
+
+    frame_size = wasm_interp_interp_frame_size(all_cell_num);
+
     if (argc < function->param_cell_num) {
         char buf[128];
         snprintf(buf, sizeof(buf),
@@ -5047,7 +5237,9 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
     /* There is no local variable. */
     frame->lp = frame->operand + 0;
 #if WASM_ENABLE_GC != 0
-    frame->frame_ref = (uint8 *)frame->lp;
+    frame->frame_ref =
+        (uint8 *)(frame->lp
+                  + (function->ret_cell_num > 2 ? function->ret_cell_num : 2));
 #endif
     frame->ret_offset = 0;