Browse Source

Implement GC AOT object reclaim process (#2762)

Wenyong Huang 2 years ago
parent
commit
5d9cbfe109

+ 45 - 7
core/iwasm/aot/aot_loader.c

@@ -1228,7 +1228,7 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
         data_list[i]->is_dropped = false;
         data_list[i]->table_index = table_index;
 #if WASM_ENABLE_GC != 0
-        if (wasm_is_type_multi_byte_type(reftype.ref_type)) {
+        if (wasm_is_type_multi_byte_type(elem_type)) {
             if (!(data_list[i]->elem_ref_type =
                       reftype_set_insert(module->ref_type_set, &reftype,
                                          error_buf, error_buf_size))) {
@@ -1430,14 +1430,33 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
         }
         else if (type_flag == WASM_TYPE_STRUCT) {
             AOTStructType *struct_type;
-            uint16 field_count;
+            const uint8 *buf_org;
+            uint16 *reference_table;
+            uint16 field_count, ref_field_count = 0;
             uint32 offset;
+
             read_uint16(buf, buf_end, field_count);
             read_uint16(buf, buf_end, ref_type_map_count);
-            struct_type =
-                loader_malloc(sizeof(AOTStructType)
-                                  + field_count * sizeof(WASMStructFieldType),
-                              error_buf, error_buf_size);
+
+            buf_org = buf;
+
+            /* Traverse first time to get ref_field_count */
+            for (j = 0; j < field_count; j++) {
+                uint8 field_flags, field_type;
+
+                read_uint8(buf, buf_end, field_flags);
+                read_uint8(buf, buf_end, field_type);
+                if (wasm_is_type_reftype(field_type))
+                    ref_field_count++;
+
+                (void)field_flags;
+            }
+
+            struct_type = loader_malloc(
+                sizeof(AOTStructType)
+                    + sizeof(WASMStructFieldType) * (uint64)field_count
+                    + sizeof(uint16) * (uint64)(ref_field_count + 1),
+                error_buf, error_buf_size);
             if (!struct_type) {
                 goto fail;
             }
@@ -1449,13 +1468,22 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
             struct_type->field_count = field_count;
             struct_type->ref_type_map_count = ref_type_map_count;
 
+            struct_type->reference_table = reference_table =
+                (uint16 *)((uint8 *)struct_type
+                           + offsetof(AOTStructType, fields)
+                           + sizeof(WASMStructFieldType) * field_count);
+            *reference_table++ = ref_field_count;
+
             LOG_VERBOSE(
                 "type %u: struct, field count: %d, ref type map count: %d", i,
                 field_count, ref_type_map_count);
 
-            /* Read types of fields */
+            buf = buf_org;
+
+            /* Traverse again to read each field */
             for (j = 0; j < field_count; j++) {
                 uint8 field_type, field_size;
+
                 read_uint8(buf, buf_end, struct_type->fields[j].field_flags);
                 read_uint8(buf, buf_end, field_type);
                 struct_type->fields[j].field_type = field_type;
@@ -1469,6 +1497,8 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
                     offset = align_uint(offset, 4);
 #endif
                 struct_type->fields[j].field_offset = offset;
+                if (wasm_is_type_reftype(field_type))
+                    *reference_table++ = offset;
                 offset += field_size;
                 LOG_VERBOSE("                field: %d, flags: %d, type: %d", j,
                             struct_type->fields[j].field_flags,
@@ -3856,6 +3886,14 @@ aot_unload(AOTModule *module)
         bh_hash_map_destroy(module->ref_type_set);
     }
     os_mutex_destroy(&module->rtt_type_lock);
+    if (module->rtt_types) {
+        uint32 i;
+        for (i = 0; i < module->type_count; i++) {
+            if (module->rtt_types[i])
+                wasm_runtime_free(module->rtt_types[i]);
+        }
+        wasm_runtime_free(module->rtt_types);
+    }
 #endif
 
     wasm_runtime_free(module);

+ 155 - 1
core/iwasm/aot/aot_runtime.c

@@ -3125,8 +3125,37 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
     frame->func_perf_prof_info = func_perf_prof;
 #endif
     frame->sp = frame->lp + max_local_cell_num;
+
 #if WASM_ENABLE_GC != 0
     frame->frame_ref = (uint8 *)(frame->sp + max_stack_cell_num);
+
+    /* Initialize frame ref flags for import function */
+    if (func_index < module->import_func_count) {
+        AOTFuncType *func_type = module->import_funcs[func_index].func_type;
+        uint8 *frame_ref = frame->frame_ref;
+        uint32 i, j, k, value_type_cell_num;
+
+        for (i = 0, j = 0; i < func_type->param_count; i++) {
+            if (wasm_is_type_reftype(func_type->types[i])
+                && !wasm_is_reftype_i31ref(func_type->types[i])) {
+                frame_ref[j++] = 1;
+#if UINTPTR_MAX == UINT64_MAX
+                frame_ref[j++] = 1;
+#endif
+            }
+            else {
+                value_type_cell_num =
+                    wasm_value_type_cell_num(func_type->types[i]);
+                for (k = 0; k < value_type_cell_num; k++)
+                    frame_ref[j++] = 0;
+            }
+        }
+
+        if (func_type->param_count == 0) {
+            /* We reserve at least two cells for native frame */
+            frame_ref[0] = frame_ref[1] = 0;
+        }
+    }
 #endif
 
     frame->prev_frame = (AOTFrame *)exec_env->cur_frame;
@@ -3855,7 +3884,6 @@ aot_dump_pgo_prof_data_to_buf(AOTModuleInstance *module_inst, char *buf,
 #endif /* end of WASM_ENABLE_STATIC_PGO != 0 */
 
 #if WASM_ENABLE_GC != 0
-
 void *
 aot_create_func_obj(AOTModuleInstance *module_inst, uint32 func_idx,
                     bool throw_exce, char *error_buf, uint32 error_buf_size)
@@ -3948,4 +3976,130 @@ aot_array_init_with_data(AOTModuleInstance *module_inst, uint32 seg_index,
     return true;
 }
 
+static bool
+aot_global_traverse_gc_rootset(AOTModuleInstance *module_inst, void *heap)
+{
+    AOTModule *module = (AOTModule *)module_inst->module;
+    uint8 *global_data = module_inst->global_data;
+    AOTImportGlobal *import_global = module->import_globals;
+    AOTGlobal *global = module->globals;
+    WASMObjectRef gc_obj;
+    uint32 i;
+
+    for (i = 0; i < module->import_global_count; i++, import_global++) {
+        if (wasm_is_type_reftype(import_global->type)) {
+            gc_obj = GET_REF_FROM_ADDR((uint32 *)global_data);
+            if (wasm_obj_is_created_from_heap(gc_obj)) {
+                if (0 != mem_allocator_add_root((mem_allocator_t)heap, gc_obj))
+                    return false;
+            }
+        }
+        global_data += import_global->size;
+    }
+
+    for (i = 0; i < module->global_count; i++, global++) {
+        if (wasm_is_type_reftype(global->type)) {
+            gc_obj = GET_REF_FROM_ADDR((uint32 *)global_data);
+            if (wasm_obj_is_created_from_heap(gc_obj)) {
+                if (0 != mem_allocator_add_root((mem_allocator_t)heap, gc_obj))
+                    return false;
+            }
+        }
+        global_data += global->size;
+    }
+
+    return true;
+}
+
+static bool
+aot_table_traverse_gc_rootset(WASMModuleInstance *module_inst, void *heap)
+{
+    AOTTableInstance **tables = (AOTTableInstance **)module_inst->tables;
+    AOTTableInstance *table;
+    uint32 table_count = module_inst->table_count, i, j;
+    WASMObjectRef gc_obj, *table_elems;
+
+    for (i = 0; i < table_count; i++) {
+        table = tables[i];
+        table_elems = (WASMObjectRef *)table->elems;
+        for (j = 0; j < table->cur_size; j++) {
+            gc_obj = table_elems[j];
+            if (wasm_obj_is_created_from_heap(gc_obj)) {
+                if (0 != mem_allocator_add_root((mem_allocator_t)heap, gc_obj))
+                    return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+static bool
+local_object_refs_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap)
+{
+    WASMLocalObjectRef *r;
+    WASMObjectRef gc_obj;
+
+    for (r = exec_env->cur_local_object_ref; r; r = r->prev) {
+        gc_obj = r->val;
+        if (wasm_obj_is_created_from_heap(gc_obj)) {
+            if (0 != mem_allocator_add_root((mem_allocator_t)heap, gc_obj))
+                return false;
+        }
+    }
+    return true;
+}
+
+static bool
+aot_frame_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap)
+{
+    AOTFrame *frame;
+    WASMObjectRef gc_obj;
+    int i;
+
+    frame = (AOTFrame *)wasm_exec_env_get_cur_frame(exec_env);
+    for (; frame; frame = frame->prev_frame) {
+        uint8 *frame_ref = frame->frame_ref;
+        for (i = 0; i < frame->sp - frame->lp; i++) {
+            if (frame_ref[i]) {
+                gc_obj = GET_REF_FROM_ADDR(frame->lp + i);
+                if (wasm_obj_is_created_from_heap(gc_obj)) {
+                    if (mem_allocator_add_root((mem_allocator_t)heap, gc_obj)) {
+                        return false;
+                    }
+                }
+#if UINTPTR_MAX == UINT64_MAX
+                bh_assert(frame_ref[i + 1]);
+                i++;
+#endif
+            }
+        }
+    }
+    return true;
+}
+
+bool
+aot_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap)
+{
+    AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
+    bool ret;
+
+    ret = aot_global_traverse_gc_rootset(module_inst, heap);
+    if (!ret)
+        return ret;
+
+    ret = aot_table_traverse_gc_rootset(module_inst, heap);
+    if (!ret)
+        return ret;
+
+    ret = local_object_refs_traverse_gc_rootset(exec_env, heap);
+    if (!ret)
+        return ret;
+
+    ret = aot_frame_traverse_gc_rootset(exec_env, heap);
+    if (!ret)
+        return ret;
+
+    return true;
+}
 #endif /* end of WASM_ENABLE_GC != 0 */

+ 2 - 0
core/iwasm/aot/aot_runtime.h

@@ -719,6 +719,8 @@ aot_array_init_with_data(AOTModuleInstance *module_inst, uint32 seg_index,
                          uint32 data_seg_offset, WASMArrayObjectRef array_obj,
                          uint32 elem_size, uint32 array_len);
 
+bool
+aot_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap);
 #endif /* end of WASM_ENABLE_GC != 0 */
 
 #ifdef __cplusplus

+ 1 - 2
core/iwasm/common/gc/gc_common.c

@@ -926,8 +926,7 @@ wasm_runtime_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap)
 #endif
 #if WASM_ENABLE_AOT != 0
     if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
-        /* TODO */
-        /*return aot_traverse_gc_rootset(exec_env, heap);*/
+        return aot_traverse_gc_rootset(exec_env, heap);
     }
 #endif
     return false;

+ 0 - 13
core/iwasm/common/gc/gc_object.c

@@ -598,19 +598,6 @@ wasm_obj_is_eq_obj(WASMObjectRef obj)
     }
 }
 
-bool
-wasm_obj_is_created_from_heap(WASMObjectRef obj)
-{
-    if (obj == NULL)
-        return false;
-
-    if (wasm_obj_is_i31_obj(obj))
-        return false;
-
-    /* struct/array/func/externref/anyref object */
-    return true;
-}
-
 bool
 wasm_obj_is_instance_of(WASMObjectRef obj, uint32 type_idx, WASMType **types,
                         uint32 type_count)

+ 8 - 2
core/iwasm/common/gc/gc_object.h

@@ -291,8 +291,14 @@ wasm_obj_is_null_obj(WASMObjectRef obj)
     return obj == NULL_REF ? true : false;
 }
 
-bool
-wasm_obj_is_created_from_heap(WASMObjectRef obj);
+inline static bool
+wasm_obj_is_created_from_heap(WASMObjectRef obj)
+{
+    if (obj == NULL || (((uintptr_t)obj) & 1))
+        /* null object or i31 object */
+        return false;
+    return true;
+}
 
 bool
 wasm_obj_is_instance_of(WASMObjectRef obj, uint32 type_idx, WASMType **types,

+ 7 - 1
core/iwasm/compilation/aot.c

@@ -176,9 +176,15 @@ get_value_type_size(uint8 value_type, bool gc_enabled, uint32 *p_size_64bit,
              value_type >= (uint8)REF_TYPE_NULLREF /* 0x65 */
 #endif
              && value_type <= (uint8)REF_TYPE_FUNCREF /* 0x70 */) {
-        size_64bit = sizeof(int64);
+        size_64bit = sizeof(uint64);
         size_32bit = sizeof(uint32);
     }
+    else if (gc_enabled && value_type == PACKED_TYPE_I8) {
+        size_64bit = size_32bit = sizeof(int8);
+    }
+    else if (gc_enabled && value_type == PACKED_TYPE_I16) {
+        size_64bit = size_32bit = sizeof(int16);
+    }
     else {
         bh_assert(0);
     }

+ 278 - 27
core/iwasm/compilation/aot_compiler.c

@@ -161,6 +161,35 @@ aot_validate_wasm(AOTCompContext *comp_ctx)
         OP_ATOMIC_##OP : bin_op = LLVMAtomicRMWBinOp##OP; \
         goto build_atomic_rmw;
 
+uint32
+offset_of_local_in_outs_area(AOTCompContext *comp_ctx, unsigned n)
+{
+    AOTCompFrame *frame = comp_ctx->aot_frame;
+    uint32 max_local_cell_num = frame->max_local_cell_num;
+    uint32 max_stack_cell_num = frame->max_stack_cell_num;
+    uint32 all_cell_num = max_local_cell_num + max_stack_cell_num;
+    uint32 frame_size;
+
+    if (!comp_ctx->is_jit_mode) {
+        /* Refer to aot_alloc_frame */
+        if (!comp_ctx->enable_gc)
+            frame_size = comp_ctx->pointer_size * 7 + all_cell_num * 4;
+        else
+            frame_size =
+                comp_ctx->pointer_size * 7 + align_uint(all_cell_num * 5, 4);
+    }
+    else {
+        /* Refer to wasm_interp_interp_frame_size */
+        if (!comp_ctx->enable_gc)
+            frame_size = offsetof(WASMInterpFrame, lp) + all_cell_num * 4;
+        else
+            frame_size =
+                offsetof(WASMInterpFrame, lp) + align_uint(all_cell_num * 5, 4);
+    }
+
+    return frame_size + offset_of_local(comp_ctx, n);
+}
+
 static bool
 store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type,
             LLVMValueRef cur_frame, uint32 offset)
@@ -217,6 +246,81 @@ store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type,
         return false;
     }
 
+    LLVMSetAlignment(res, 4);
+
+    return true;
+}
+
+bool
+aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value,
+                      uint8 value_type, LLVMValueRef cur_frame, uint32 offset)
+{
+    return store_value(comp_ctx, value, value_type, cur_frame, offset);
+}
+
+static bool
+store_ref(AOTCompContext *comp_ctx, uint32 ref, LLVMValueRef cur_frame,
+          uint32 offset, uint32 nbytes)
+{
+    LLVMValueRef value_ref = NULL, value_offset, value_addr, res;
+
+    if (!(value_offset = I32_CONST(offset))) {
+        aot_set_last_error("llvm build const failed");
+        return false;
+    }
+
+    if (!(value_addr =
+              LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
+                                    &value_offset, 1, "value_addr"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    switch (nbytes) {
+        case 1:
+            if (!(value_ref = I8_CONST((uint8)ref))) {
+                aot_set_last_error("llvm build const failed");
+            }
+            break;
+        case 2:
+            ref = (ref << 8) | ref;
+
+            if (!(value_ref = LLVMConstInt(INT16_TYPE, (uint16)ref, false))) {
+                aot_set_last_error("llvm build const failed");
+                return false;
+            }
+
+            if (!(value_addr =
+                      LLVMBuildBitCast(comp_ctx->builder, value_addr,
+                                       INT16_PTR_TYPE, "value_addr"))) {
+                aot_set_last_error("llvm build bit cast failed");
+                return false;
+            }
+            break;
+        case 4:
+            ref = (ref << 24) | (ref << 16) | (ref << 8) | ref;
+
+            if (!(value_ref = I32_CONST(ref))) {
+                aot_set_last_error("llvm build const failed");
+                return false;
+            }
+
+            if (!(value_addr =
+                      LLVMBuildBitCast(comp_ctx->builder, value_addr,
+                                       INT32_PTR_TYPE, "value_addr"))) {
+                aot_set_last_error("llvm build bit cast failed");
+                return false;
+            }
+            break;
+        default:
+            bh_assert(0);
+            break;
+    }
+
+    if (!(res = LLVMBuildStore(comp_ctx->builder, value_ref, value_addr))) {
+        aot_set_last_error("llvm build store failed");
+        return false;
+    }
     LLVMSetAlignment(res, 1);
 
     return true;
@@ -227,7 +331,7 @@ aot_gen_commit_values(AOTCompFrame *frame)
 {
     AOTCompContext *comp_ctx = frame->comp_ctx;
     AOTFuncContext *func_ctx = frame->func_ctx;
-    AOTValueSlot *p;
+    AOTValueSlot *p, *end;
     LLVMValueRef value;
     uint32 n;
 
@@ -238,6 +342,90 @@ aot_gen_commit_values(AOTCompFrame *frame)
         p->dirty = 0;
         n = p - frame->lp;
 
+        /* Commit reference flag */
+        if (comp_ctx->enable_gc) {
+            switch (p->type) {
+                case VALUE_TYPE_I32:
+                case VALUE_TYPE_F32:
+                case VALUE_TYPE_I1:
+                    if (p->ref != p->committed_ref - 1) {
+                        if (!store_ref(comp_ctx, p->ref, func_ctx->cur_frame,
+                                       offset_of_ref(comp_ctx, n), 1))
+                            return false;
+                        p->committed_ref = p->ref + 1;
+                    }
+                    break;
+
+                case VALUE_TYPE_I64:
+                case VALUE_TYPE_F64:
+                    bh_assert(p->ref == (p + 1)->ref);
+                    if (p->ref != p->committed_ref - 1
+                        || p->ref != (p + 1)->committed_ref - 1) {
+                        if (!store_ref(comp_ctx, p->ref, func_ctx->cur_frame,
+                                       offset_of_ref(comp_ctx, n), 2))
+                            return false;
+                        p->committed_ref = (p + 1)->committed_ref = p->ref + 1;
+                    }
+                    break;
+
+                case VALUE_TYPE_V128:
+                    bh_assert(p->ref == (p + 1)->ref && p->ref == (p + 2)->ref
+                              && p->ref == (p + 3)->ref);
+                    if (p->ref != p->committed_ref - 1
+                        || p->ref != (p + 1)->committed_ref - 1
+                        || p->ref != (p + 2)->committed_ref - 1
+                        || p->ref != (p + 3)->committed_ref - 1) {
+                        if (!store_ref(comp_ctx, p->ref, func_ctx->cur_frame,
+                                       offset_of_ref(comp_ctx, n), 4))
+                            return false;
+                        p->committed_ref = (p + 1)->committed_ref =
+                            (p + 2)->committed_ref = (p + 3)->committed_ref =
+                                p->ref + 1;
+                    }
+                    break;
+
+                case REF_TYPE_NULLFUNCREF:
+                case REF_TYPE_NULLEXTERNREF:
+                case REF_TYPE_NULLREF:
+                case REF_TYPE_FUNCREF:
+                case REF_TYPE_EXTERNREF:
+                case REF_TYPE_ANYREF:
+                case REF_TYPE_EQREF:
+                case REF_TYPE_HT_NULLABLE:
+                case REF_TYPE_HT_NON_NULLABLE:
+                case REF_TYPE_I31REF:
+                case REF_TYPE_STRUCTREF:
+                case REF_TYPE_ARRAYREF:
+                case VALUE_TYPE_GC_REF:
+                    if (comp_ctx->pointer_size == sizeof(uint64)) {
+                        bh_assert(p->ref == (p + 1)->ref);
+                        if (p->ref != p->committed_ref - 1
+                            || p->ref != (p + 1)->committed_ref - 1) {
+                            if (!store_ref(comp_ctx, p->ref,
+                                           func_ctx->cur_frame,
+                                           offset_of_ref(comp_ctx, n), 2))
+                                return false;
+                            p->committed_ref = (p + 1)->committed_ref =
+                                p->ref + 1;
+                        }
+                    }
+                    else {
+                        if (p->ref != p->committed_ref - 1) {
+                            if (!store_ref(comp_ctx, p->ref,
+                                           func_ctx->cur_frame,
+                                           offset_of_ref(comp_ctx, n), 1))
+                                return false;
+                            p->committed_ref = p->ref + 1;
+                        }
+                    }
+                    break;
+
+                default:
+                    bh_assert(0);
+                    break;
+            }
+        }
+
         switch (p->type) {
             case VALUE_TYPE_I32:
                 if (!store_value(comp_ctx, p->value, VALUE_TYPE_I32,
@@ -335,6 +523,24 @@ aot_gen_commit_values(AOTCompFrame *frame)
         }
     }
 
+    if (comp_ctx->enable_gc) {
+        end = frame->lp + frame->max_local_cell_num + frame->max_stack_cell_num;
+
+        /* Clear reference flags for unused stack slots.  */
+        for (p = frame->sp; p < end; p++) {
+            bh_assert(!p->ref);
+            n = p - frame->lp;
+
+            /* Commit reference flag.  */
+            if (p->ref != p->committed_ref - 1) {
+                if (!store_ref(comp_ctx, p->ref, func_ctx->cur_frame,
+                               offset_of_ref(comp_ctx, n), 1))
+                    return false;
+                p->committed_ref = 1 + p->ref;
+            }
+        }
+    }
+
     return true;
 }
 
@@ -581,6 +787,10 @@ init_comp_frame(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
     }
 
+    /* TODO: re-calculate param_cell_num according to the build target
+             after creating comp_ctx */
+    /* bh_assert(n == aot_func->param_cell_num); */
+
     /* Set all locals dirty since they were set to llvm value but
        haven't been committed to the AOT/JIT stack frame */
     for (i = 0; i < aot_func->local_count; i++) {
@@ -651,6 +861,14 @@ init_comp_frame(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
     }
 
+    /* TODO: re-calculate local_cell_num according to the build target
+             after creating comp_ctx */
+    /* bh_assert(n == aot_func->param_cell_num + aot_func->local_cell_num); */
+
+    /* No need to initialize aot_frame all cells' committed_ref flags
+       and all stack cells' ref flags since they have been initialized
+       as 0 (uncommited and not-reference) by the memset above */
+
     return true;
 }
 
@@ -660,7 +878,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
     AOTFuncContext *func_ctx = comp_ctx->func_ctxes[func_index];
     uint8 *frame_ip = func_ctx->aot_func->code, opcode, *p_f32, *p_f64;
     uint8 *frame_ip_end = frame_ip + func_ctx->aot_func->code_size;
-    uint8 *param_types = NULL;
+    uint8 *param_types = NULL, *frame_ip_org;
     uint8 *result_types = NULL;
     uint8 value_type;
     uint16 param_count;
@@ -785,19 +1003,31 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 break;
 
             case WASM_OP_BR:
+            {
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, br_depth);
-                if (!aot_compile_op_br(comp_ctx, func_ctx, br_depth, &frame_ip))
+                if (!aot_compile_op_br(comp_ctx, func_ctx, br_depth,
+                                       frame_ip_org, &frame_ip))
                     return false;
                 break;
+            }
 
             case WASM_OP_BR_IF:
+            {
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, br_depth);
                 if (!aot_compile_op_br_if(comp_ctx, func_ctx, br_depth,
-                                          &frame_ip))
+                                          frame_ip_org, &frame_ip))
                     return false;
                 break;
+            }
 
             case WASM_OP_BR_TABLE:
+            {
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, br_count);
                 if (!(br_depths = wasm_runtime_malloc((uint32)sizeof(uint32)
                                                       * (br_count + 1)))) {
@@ -813,13 +1043,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 #endif
 
                 if (!aot_compile_op_br_table(comp_ctx, func_ctx, br_depths,
-                                             br_count, &frame_ip)) {
+                                             br_count, frame_ip_org,
+                                             &frame_ip)) {
                     wasm_runtime_free(br_depths);
                     return false;
                 }
 
                 wasm_runtime_free(br_depths);
                 break;
+            }
 
 #if WASM_ENABLE_FAST_INTERP == 0
             case EXT_OP_BR_TABLE_CACHE:
@@ -827,17 +1059,18 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 BrTableCache *node = bh_list_first_elem(
                     comp_ctx->comp_data->wasm_module->br_table_cache_list);
                 BrTableCache *node_next;
-                uint8 *p_opcode = frame_ip - 1;
+
+                frame_ip_org = frame_ip - 1;
 
                 read_leb_uint32(frame_ip, frame_ip_end, br_count);
 
                 while (node) {
                     node_next = bh_list_elem_next(node);
-                    if (node->br_table_op_addr == p_opcode) {
+                    if (node->br_table_op_addr == frame_ip_org) {
                         br_depths = node->br_depths;
                         if (!aot_compile_op_br_table(comp_ctx, func_ctx,
                                                      br_depths, br_count,
-                                                     &frame_ip)) {
+                                                     frame_ip_org, &frame_ip)) {
                             return false;
                         }
                         break;
@@ -857,7 +1090,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 
             case WASM_OP_CALL:
             {
-                uint8 *frame_ip_org = frame_ip;
+                frame_ip_org = frame_ip - 1;
 
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
                 if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false,
@@ -868,9 +1101,10 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 
             case WASM_OP_CALL_INDIRECT:
             {
-                uint8 *frame_ip_org = frame_ip;
                 uint32 tbl_idx;
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
 
                 if (comp_ctx->enable_gc || comp_ctx->enable_ref_types) {
@@ -890,12 +1124,13 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 #if WASM_ENABLE_TAIL_CALL != 0
             case WASM_OP_RETURN_CALL:
             {
-                uint8 *frame_ip_org = frame_ip;
-
                 if (!comp_ctx->enable_tail_call) {
                     aot_set_last_error("unsupported opcode");
                     return false;
                 }
+
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
                 if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, true,
                                          frame_ip_org))
@@ -907,7 +1142,6 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 
             case WASM_OP_RETURN_CALL_INDIRECT:
             {
-                uint8 *frame_ip_org = frame_ip;
                 uint32 tbl_idx;
 
                 if (!comp_ctx->enable_tail_call) {
@@ -915,6 +1149,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                     return false;
                 }
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
                 if (comp_ctx->enable_gc || comp_ctx->enable_ref_types) {
                     read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
@@ -1039,8 +1275,11 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                     goto unsupport_gc_and_ref_types;
                 }
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
-                if (!aot_compile_op_ref_func(comp_ctx, func_ctx, func_idx))
+                if (!aot_compile_op_ref_func(comp_ctx, func_ctx, func_idx,
+                                             frame_ip_org))
                     return false;
                 break;
             }
@@ -1049,12 +1288,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 #if WASM_ENABLE_GC != 0
             case WASM_OP_CALL_REF:
             {
-                uint8 *frame_ip_org = frame_ip;
-
                 if (!comp_ctx->enable_gc) {
                     goto unsupport_gc;
                 }
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
                 if (!aot_compile_op_call_ref(comp_ctx, func_ctx, type_idx,
                                              false, frame_ip_org))
@@ -1064,12 +1303,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 
             case WASM_OP_RETURN_CALL_REF:
             {
-                uint8 *frame_ip_org = frame_ip;
-
                 if (!comp_ctx->enable_gc) {
                     goto unsupport_gc;
                 }
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
                 if (!aot_compile_op_call_ref(comp_ctx, func_ctx, type_idx, true,
                                              frame_ip_org))
@@ -1098,34 +1337,44 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 break;
 
             case WASM_OP_BR_ON_NULL:
+            {
                 if (!comp_ctx->enable_gc) {
                     goto unsupport_gc;
                 }
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, br_depth);
                 if (!aot_compile_op_br_on_null(comp_ctx, func_ctx, br_depth,
-                                               &frame_ip))
+                                               frame_ip_org, &frame_ip))
                     return false;
                 break;
+            }
 
             case WASM_OP_BR_ON_NON_NULL:
+            {
                 if (!comp_ctx->enable_gc) {
                     goto unsupport_gc;
                 }
 
+                frame_ip_org = frame_ip - 1;
+
                 read_leb_uint32(frame_ip, frame_ip_end, br_depth);
                 if (!aot_compile_op_br_on_non_null(comp_ctx, func_ctx, br_depth,
-                                                   &frame_ip))
+                                                   frame_ip_org, &frame_ip))
                     return false;
                 break;
+            }
 
             case WASM_OP_GC_PREFIX:
             {
+                uint32 opcode1, field_idx, data_seg_idx, array_len;
+
                 if (!comp_ctx->enable_gc) {
                     goto unsupport_gc;
                 }
 
-                uint32 opcode1, field_idx, data_seg_idx, array_len;
+                frame_ip_org = frame_ip - 1;
 
                 read_leb_uint32(frame_ip, frame_ip_end, opcode1);
                 opcode = (uint8)opcode1;
@@ -1136,7 +1385,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                         read_leb_uint32(frame_ip, frame_ip_end, type_index);
                         if (!aot_compile_op_struct_new(
                                 comp_ctx, func_ctx, type_index,
-                                opcode == WASM_OP_STRUCT_NEW_CANON_DEFAULT))
+                                opcode == WASM_OP_STRUCT_NEW_CANON_DEFAULT,
+                                frame_ip_org))
                             return false;
                         break;
 
@@ -1171,7 +1421,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                                 comp_ctx, func_ctx, type_index,
                                 opcode == WASM_OP_ARRAY_NEW_CANON_DEFAULT,
                                 opcode == WASM_OP_ARRAY_NEW_CANON_FIXED,
-                                array_len))
+                                array_len, frame_ip_org))
                             return false;
                         break;
 
@@ -1179,7 +1429,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                         read_leb_uint32(frame_ip, frame_ip_end, type_index);
                         read_leb_uint32(frame_ip, frame_ip_end, data_seg_idx);
                         if (!aot_compile_op_array_new_data(
-                                comp_ctx, func_ctx, type_index, data_seg_idx))
+                                comp_ctx, func_ctx, type_index, data_seg_idx,
+                                frame_ip_org))
                             return false;
                         break;
 
@@ -1283,7 +1534,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                                 opcode == WASM_OP_BR_ON_CAST_FAIL
                                     || opcode
                                            == WASM_OP_BR_ON_CAST_FAIL_NULLABLE,
-                                br_depth, &frame_ip))
+                                br_depth, frame_ip_org, &frame_ip))
                             return false;
                         break;
                     }
@@ -1295,8 +1546,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                         break;
 
                     case WASM_OP_EXTERN_EXTERNALIZE:
-                        if (!aot_compile_op_extern_externalize(comp_ctx,
-                                                               func_ctx))
+                        if (!aot_compile_op_extern_externalize(
+                                comp_ctx, func_ctx, frame_ip_org))
                             return false;
                         break;
 

+ 42 - 19
core/iwasm/compilation/aot_compiler.h

@@ -139,11 +139,15 @@ static inline uint32
 offset_of_local(AOTCompContext *comp_ctx, unsigned n)
 {
     if (!comp_ctx->is_jit_mode)
+        /* In AOTFrame, there are 7 pointers before field lp */
         return comp_ctx->pointer_size * 7 + sizeof(uint32) * n;
     else
         return offsetof(WASMInterpFrame, lp) + sizeof(uint32) * n;
 }
 
+uint32
+offset_of_local_in_outs_area(AOTCompContext *comp_ctx, unsigned n);
+
 /**
  * Get the offset from frame pointer to the n-th local variable's
  * reference flag slot.
@@ -179,6 +183,10 @@ bool
 aot_gen_commit_sp_ip(AOTCompFrame *frame, const AOTValueSlot *sp,
                      const uint8 *ip);
 
+bool
+aot_frame_store_value(AOTCompContext *comp_ctx, LLVMValueRef value,
+                      uint8 value_type, LLVMValueRef cur_frame, uint32 offset);
+
 static inline void
 push_32bit(AOTCompFrame *frame, AOTValue *aot_value)
 {
@@ -245,13 +253,29 @@ push_gc_ref(AOTCompFrame *frame, AOTValue *aot_value)
 {
     bh_assert(frame->comp_ctx->enable_gc);
     bh_assert(aot_value->type == VALUE_TYPE_GC_REF);
-    if (frame->comp_ctx->pointer_size == sizeof(uint64))
+    if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
         push_64bit(frame, aot_value);
-    else
+        (frame->sp - 1)->ref = (frame->sp - 2)->ref = 1;
+    }
+    else {
         push_32bit(frame, aot_value);
+        (frame->sp - 1)->ref = 1;
+    }
 }
 #endif
 
+/* Clear value slots except ref and committed_ref */
+static inline void
+clear_frame_value_slots(AOTValueSlot *slots, uint32 n)
+{
+    uint32 i;
+    for (i = 0; i < n; i++) {
+        slots[i].value = 0;
+        slots[i].type = 0;
+        slots[i].dirty = 0;
+    }
+}
+
 static inline void
 pop_i32(AOTCompFrame *frame)
 {
@@ -259,7 +283,7 @@ pop_i32(AOTCompFrame *frame)
     bh_assert((frame->sp - 1)->type == VALUE_TYPE_I32
               || (frame->sp - 1)->type == VALUE_TYPE_I1);
     frame->sp--;
-    memset(frame->sp, 0, sizeof(*frame->sp));
+    clear_frame_value_slots(frame->sp, 1);
 }
 
 static inline void
@@ -269,7 +293,7 @@ pop_i64(AOTCompFrame *frame)
     bh_assert((frame->sp - 1)->type == VALUE_TYPE_I64
               && (frame->sp - 2)->type == VALUE_TYPE_I64);
     frame->sp -= 2;
-    memset(frame->sp, 0, sizeof(*frame->sp) * 2);
+    clear_frame_value_slots(frame->sp, 2);
 }
 
 static inline void
@@ -278,7 +302,7 @@ pop_f32(AOTCompFrame *frame)
     bh_assert(frame->sp - frame->lp >= 1);
     bh_assert((frame->sp - 1)->type == VALUE_TYPE_F32);
     frame->sp--;
-    memset(frame->sp, 0, sizeof(*frame->sp));
+    clear_frame_value_slots(frame->sp, 1);
 }
 
 static inline void
@@ -288,7 +312,7 @@ pop_f64(AOTCompFrame *frame)
     bh_assert((frame->sp - 1)->type == VALUE_TYPE_F64
               && (frame->sp - 2)->type == VALUE_TYPE_F64);
     frame->sp -= 2;
-    memset(frame->sp, 0, sizeof(*frame->sp) * 2);
+    clear_frame_value_slots(frame->sp, 2);
 }
 
 static inline void
@@ -300,7 +324,7 @@ pop_v128(AOTCompFrame *frame)
               && (frame->sp - 3)->type == VALUE_TYPE_V128
               && (frame->sp - 4)->type == VALUE_TYPE_V128);
     frame->sp -= 4;
-    memset(frame->sp, 0, sizeof(*frame->sp) * 4);
+    clear_frame_value_slots(frame->sp, 4);
 }
 
 static inline void
@@ -310,31 +334,28 @@ pop_ref(AOTCompFrame *frame)
     bh_assert((frame->sp - 1)->type == VALUE_TYPE_FUNCREF
               || (frame->sp - 1)->type == VALUE_TYPE_EXTERNREF);
     frame->sp -= 1;
-    memset(frame->sp, 0, sizeof(*frame->sp) * 1);
+    clear_frame_value_slots(frame->sp, 1);
 }
 
 #if WASM_ENABLE_GC != 0
 static inline void
 pop_gc_ref(AOTCompFrame *frame)
 {
-    uint32 i;
-    for (i = 0; i < frame->comp_ctx->pointer_size / sizeof(uint32); i++) {
+    bh_assert(frame->sp - frame->lp >= 1);
+    bh_assert((frame->sp - 1)->type == VALUE_TYPE_GC_REF);
+    frame->sp -= 1;
+    clear_frame_value_slots(frame->sp, 1);
+    frame->sp->ref = 0;
+    if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
         bh_assert(frame->sp - frame->lp >= 1);
         bh_assert((frame->sp - 1)->type == VALUE_TYPE_GC_REF);
         frame->sp -= 1;
-        memset(frame->sp, 0, sizeof(*frame->sp) * 1);
+        clear_frame_value_slots(frame->sp, 1);
+        frame->sp->ref = 0;
     }
 }
 #endif
 
-static inline void
-pop(AOTCompFrame *frame, uint32 n)
-{
-    bh_assert(frame->sp - frame->lp >= n);
-    frame->sp -= n;
-    memset(frame->sp, 0, sizeof(*frame->sp) * n);
-}
-
 static inline void
 set_local_i32(AOTCompFrame *frame, int n, LLVMValueRef value)
 {
@@ -402,10 +423,12 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
     frame->lp[n].value = value;
     frame->lp[n].type = ref_type;
     frame->lp[n].dirty = 1;
+    frame->lp[n].ref = 1;
     if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
         frame->lp[n + 1].value = value;
         frame->lp[n + 1].type = ref_type;
         frame->lp[n + 1].dirty = 1;
+        frame->lp[n + 1].ref = 1;
     }
 }
 #endif

+ 71 - 32
core/iwasm/compilation/aot_emit_control.c

@@ -166,18 +166,25 @@ clear_frame_locals(AOTCompFrame *aot_frame)
     for (i = 0; i < aot_frame->max_local_cell_num; i++) {
         aot_frame->lp[i].dirty = 0;
         aot_frame->lp[i].value = NULL;
+        if (aot_frame->comp_ctx->enable_gc)
+            /* Mark the ref flag as committed */
+            aot_frame->lp[i].committed_ref = aot_frame->lp[i].ref + 1;
     }
 }
 
 static void
 restore_frame_sp(AOTBlock *block, AOTCompFrame *aot_frame)
 {
-    uint32 stack_cell_num;
+    uint32 all_cell_num, stack_cell_num;
 
     bh_assert(aot_frame->sp >= block->frame_sp_begin);
 
-    stack_cell_num = aot_frame->sp - block->frame_sp_begin;
+    all_cell_num =
+        aot_frame->max_local_cell_num + aot_frame->max_stack_cell_num;
+    stack_cell_num = aot_frame->lp + all_cell_num - block->frame_sp_begin;
+
     if (stack_cell_num > 0) {
+        /* Clear the stack operands and mark the ref flags as uncommitted */
         memset(block->frame_sp_begin, 0, sizeof(AOTValueSlot) * stack_cell_num);
     }
     aot_frame->sp = block->frame_sp_begin;
@@ -234,20 +241,24 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         block_prev = block->prev;
         block = aot_block_stack_pop(&func_ctx->block_stack);
 
-        if (aot_frame) {
-            /* Restore the frame sp */
-            restore_frame_sp(block, aot_frame);
-        }
-
         if (block->label_type == LABEL_TYPE_IF) {
             if (block->llvm_else_block && !block->skip_wasm_code_else
                 && *p_frame_ip <= block->wasm_code_else) {
                 /* Clear value stack and start to translate else branch */
                 aot_value_stack_destroy(comp_ctx, &block->value_stack);
+
+                if (aot_frame) {
+                    /* Restore the frame sp */
+                    restore_frame_sp(block, aot_frame);
+                }
+
                 SET_BUILDER_POS(block->llvm_else_block);
                 *p_frame_ip = block->wasm_code_else + 1;
                 /* Push back the block */
                 aot_block_stack_push(&func_ctx->block_stack, block);
+                /* Recover parameters of else branch */
+                for (i = 0; i < block->param_count; i++)
+                    PUSH(block->else_param_phis[i], block->param_types[i]);
                 return true;
             }
             else if (block->llvm_end_block) {
@@ -267,6 +278,25 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         return true;
     }
 
+    if (block->label_type == LABEL_TYPE_IF && block->llvm_else_block
+        && !block->skip_wasm_code_else
+        && *p_frame_ip <= block->wasm_code_else) {
+        /* Clear value stack and start to translate else branch */
+        aot_value_stack_destroy(comp_ctx, &block->value_stack);
+
+        if (aot_frame) {
+            /* Restore the frame sp */
+            restore_frame_sp(block, aot_frame);
+        }
+
+        /* Recover parameters of else branch */
+        for (i = 0; i < block->param_count; i++)
+            PUSH(block->else_param_phis[i], block->param_types[i]);
+        SET_BUILDER_POS(block->llvm_else_block);
+        *p_frame_ip = block->wasm_code_else + 1;
+        return true;
+    }
+
     *p_frame_ip = block->wasm_code_end + 1;
     SET_BUILDER_POS(block->llvm_end_block);
 
@@ -701,11 +731,8 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         aot_value_stack_destroy(comp_ctx, &block->value_stack);
 
         if (comp_ctx->aot_frame) {
-            comp_ctx->aot_frame->sp = block->frame_sp_begin;
-            for (i = 0; i < comp_ctx->aot_frame->max_local_cell_num; i++) {
-                comp_ctx->aot_frame->lp[i].dirty = 0;
-                comp_ctx->aot_frame->lp[i].value = NULL;
-            }
+            clear_frame_locals(aot_frame);
+            restore_frame_sp(block, aot_frame);
         }
 
         for (i = 0; i < block->param_count; i++)
@@ -765,7 +792,7 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     if (comp_ctx->aot_frame) {
-        restore_frame_sp(block, comp_ctx->aot_frame);
+        bh_assert(comp_ctx->aot_frame->sp == block->frame_sp_begin);
     }
 
     /* Jump to the end block */
@@ -852,7 +879,7 @@ fail:
 
 bool
 aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                  uint32 br_depth, uint8 **p_frame_ip)
+                  uint32 br_depth, const uint8 *frame_ip_br, uint8 **p_frame_ip)
 {
     AOTBlock *block_dst;
     LLVMValueRef value_ret, value_param;
@@ -867,9 +894,10 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             return false;
+
         if (block_dst->label_type == LABEL_TYPE_LOOP) {
             if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
-                                      comp_ctx->aot_frame->sp, *p_frame_ip))
+                                      comp_ctx->aot_frame->sp, frame_ip_br))
                 return false;
         }
     }
@@ -925,8 +953,8 @@ fail:
 
 static bool
 aot_compile_conditional_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                           uint32 br_depth, uint8 **p_frame_ip,
-                           LLVMValueRef value_cmp)
+                           uint32 br_depth, LLVMValueRef value_cmp,
+                           const uint8 *frame_ip_br_if, uint8 **p_frame_ip)
 {
     AOTBlock *block_dst;
     LLVMValueRef value, *values = NULL;
@@ -942,9 +970,10 @@ aot_compile_conditional_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             return false;
+
         if (block_dst->label_type == LABEL_TYPE_LOOP) {
             if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
-                                      comp_ctx->aot_frame->sp, *p_frame_ip))
+                                      comp_ctx->aot_frame->sp, frame_ip_br_if))
                 return false;
         }
     }
@@ -1055,7 +1084,8 @@ aot_compile_conditional_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     else {
         if ((int32)LLVMConstIntGetZExtValue(value_cmp) != 0) {
             /* Compare value is not 0, condition is true, same as op_br */
-            return aot_compile_op_br(comp_ctx, func_ctx, br_depth, p_frame_ip);
+            return aot_compile_op_br(comp_ctx, func_ctx, br_depth,
+                                     frame_ip_br_if, p_frame_ip);
         }
         else {
             /* Compare value is not 0, condition is false, skip br_if */
@@ -1071,21 +1101,23 @@ fail:
 
 bool
 aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                     uint32 br_depth, uint8 **p_frame_ip)
+                     uint32 br_depth, const uint8 *frame_ip_br_if,
+                     uint8 **p_frame_ip)
 {
     LLVMValueRef value_cmp;
 
     POP_COND(value_cmp);
 
-    return aot_compile_conditional_br(comp_ctx, func_ctx, br_depth, p_frame_ip,
-                                      value_cmp);
+    return aot_compile_conditional_br(comp_ctx, func_ctx, br_depth, value_cmp,
+                                      frame_ip_br_if, p_frame_ip);
 fail:
     return false;
 }
 
 bool
 aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        uint32 *br_depths, uint32 br_count, uint8 **p_frame_ip)
+                        uint32 *br_depths, uint32 br_count,
+                        const uint8 *frame_ip_br_table, uint8 **p_frame_ip)
 {
     uint32 i, j;
     LLVMValueRef value_switch, value_cmp, value_case, value, *values = NULL;
@@ -1115,8 +1147,10 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         if (comp_ctx->aot_frame) {
             if (!aot_gen_commit_values(comp_ctx->aot_frame))
                 return false;
+
             if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
-                                      comp_ctx->aot_frame->sp, *p_frame_ip))
+                                      comp_ctx->aot_frame->sp,
+                                      frame_ip_br_table))
                 return false;
         }
 
@@ -1236,7 +1270,8 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         if (depth_idx < br_count) {
             br_depth = br_depths[depth_idx];
         }
-        return aot_compile_op_br(comp_ctx, func_ctx, br_depth, p_frame_ip);
+        return aot_compile_op_br(comp_ctx, func_ctx, br_depth,
+                                 frame_ip_br_table, p_frame_ip);
     }
 fail:
     if (values)
@@ -1328,7 +1363,7 @@ aot_handle_next_reachable_block(AOTCompContext *comp_ctx,
 static bool
 commit_gc_and_check_suspend_flags(AOTCompContext *comp_ctx,
                                   AOTFuncContext *func_ctx, uint32 br_depth,
-                                  uint8 **p_frame_ip)
+                                  const uint8 *frame_ip_br_on)
 {
     AOTBlock *block_dst;
 
@@ -1339,9 +1374,10 @@ commit_gc_and_check_suspend_flags(AOTCompContext *comp_ctx,
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             return false;
+
         if (block_dst->label_type == LABEL_TYPE_LOOP) {
             if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame,
-                                      comp_ctx->aot_frame->sp, *p_frame_ip))
+                                      comp_ctx->aot_frame->sp, frame_ip_br_on))
                 return false;
         }
     }
@@ -1459,12 +1495,13 @@ fail:
 
 bool
 aot_compile_op_br_on_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                          uint32 br_depth, uint8 **p_frame_ip)
+                          uint32 br_depth, const uint8 *frame_ip_br_on_null,
+                          uint8 **p_frame_ip)
 {
     LLVMValueRef gc_obj, value_cmp;
 
     if (!commit_gc_and_check_suspend_flags(comp_ctx, func_ctx, br_depth,
-                                           p_frame_ip)) {
+                                           frame_ip_br_on_null)) {
         return false;
     }
 
@@ -1489,12 +1526,13 @@ fail:
 bool
 aot_compile_op_br_on_non_null(AOTCompContext *comp_ctx,
                               AOTFuncContext *func_ctx, uint32 br_depth,
+                              const uint8 *frame_ip_br_on_non_null,
                               uint8 **p_frame_ip)
 {
     LLVMValueRef gc_obj, value_cmp;
 
     if (!commit_gc_and_check_suspend_flags(comp_ctx, func_ctx, br_depth,
-                                           p_frame_ip)) {
+                                           frame_ip_br_on_non_null)) {
         return false;
     }
 
@@ -1519,13 +1557,14 @@ fail:
 bool
 aot_compile_op_br_on_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                           int32 heap_type, bool nullable, bool br_on_fail,
-                          uint32 br_depth, uint8 **p_frame_ip)
+                          uint32 br_depth, const uint8 *frame_ip_br_on_cast,
+                          uint8 **p_frame_ip)
 {
     LLVMValueRef gc_obj, is_null, castable, not_castable, br_if_phi;
     LLVMBasicBlockRef block_curr, block_non_null, block_br_if;
 
     if (!commit_gc_and_check_suspend_flags(comp_ctx, func_ctx, br_depth,
-                                           p_frame_ip)) {
+                                           frame_ip_br_on_cast)) {
         return false;
     }
 

+ 11 - 5
core/iwasm/compilation/aot_emit_control.h

@@ -28,15 +28,18 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
 bool
 aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                  uint32 br_depth, uint8 **p_frame_ip);
+                  uint32 br_depth, const uint8 *frame_ip_br,
+                  uint8 **p_frame_ip);
 
 bool
 aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                     uint32 br_depth, uint8 **p_frame_ip);
+                     uint32 br_depth, const uint8 *frame_ip_br_if,
+                     uint8 **p_frame_ip);
 
 bool
 aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        uint32 *br_depths, uint32 br_count, uint8 **p_frame_ip);
+                        uint32 *br_depths, uint32 br_count,
+                        const uint8 *frame_ip_br_table, uint8 **p_frame_ip);
 
 bool
 aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@@ -59,17 +62,20 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 #if WASM_ENABLE_GC != 0
 bool
 aot_compile_op_br_on_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                          uint32 br_depth, uint8 **p_frame_ip);
+                          uint32 br_depth, const uint8 *frame_ip_br_on_null,
+                          uint8 **p_frame_ip);
 
 bool
 aot_compile_op_br_on_non_null(AOTCompContext *comp_ctx,
                               AOTFuncContext *func_ctx, uint32 br_depth,
+                              const uint8 *frame_ip_br_on_non_null,
                               uint8 **p_frame_ip);
 
 bool
 aot_compile_op_br_on_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                           int32 heap_type, bool nullable, bool br_on_fail,
-                          uint32 br_depth, uint8 **p_frame_ip);
+                          uint32 br_depth, const uint8 *frame_ip_br_on_cast,
+                          uint8 **p_frame_ip);
 #endif
 
 #ifdef __cplusplus

+ 7 - 0
core/iwasm/compilation/aot_emit_exception.c

@@ -21,10 +21,17 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     CHECK_LLVM_CONST(exce_id);
 
+#if 0
+    /* Seems no need to commit values since when dumping call stacks
+       after exception was thrown, we only need to know the ip (instruction
+       pointer) info. */
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             goto fail;
     }
+#endif
+    /* TODO: commit ip if needed when dumping call stacks after exception
+       was thrown */
 
     /* Create got_exception block if needed */
     if (!func_ctx->got_exception_block) {

+ 137 - 8
core/iwasm/compilation/aot_emit_function.c

@@ -513,9 +513,105 @@ aot_estimate_and_record_stack_usage_for_function_call(
     }
 }
 
+static bool
+commit_params_to_frame_of_import_func(AOTCompContext *comp_ctx,
+                                      AOTFuncContext *func_ctx,
+                                      AOTFuncType *func_type,
+                                      const LLVMValueRef *param_values)
+{
+    uint32 i, n;
+
+    for (i = 0, n = 0; i < func_type->param_count; i++, n++) {
+        switch (func_type->types[i]) {
+            case VALUE_TYPE_I32:
+                if (!aot_frame_store_value(
+                        comp_ctx, param_values[i], VALUE_TYPE_I32,
+                        func_ctx->cur_frame,
+                        offset_of_local_in_outs_area(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_I64:
+                if (!aot_frame_store_value(
+                        comp_ctx, param_values[i], VALUE_TYPE_I64,
+                        func_ctx->cur_frame,
+                        offset_of_local_in_outs_area(comp_ctx, n)))
+                    return false;
+                n++;
+                break;
+            case VALUE_TYPE_F32:
+                if (!aot_frame_store_value(
+                        comp_ctx, param_values[i], VALUE_TYPE_F32,
+                        func_ctx->cur_frame,
+                        offset_of_local_in_outs_area(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_F64:
+                if (!aot_frame_store_value(
+                        comp_ctx, param_values[i], VALUE_TYPE_F64,
+                        func_ctx->cur_frame,
+                        offset_of_local_in_outs_area(comp_ctx, n)))
+                    return false;
+                n++;
+                break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                if (comp_ctx->enable_ref_types) {
+                    if (!aot_frame_store_value(
+                            comp_ctx, param_values[i], VALUE_TYPE_I32,
+                            func_ctx->cur_frame,
+                            offset_of_local_in_outs_area(comp_ctx, n)))
+                        return false;
+                }
+#if WASM_ENABLE_GC != 0
+                else if (comp_ctx->enable_gc) {
+                    if (!aot_frame_store_value(
+                            comp_ctx, param_values[i], VALUE_TYPE_GC_REF,
+                            func_ctx->cur_frame,
+                            offset_of_local_in_outs_area(comp_ctx, n)))
+                        return false;
+                    if (comp_ctx->pointer_size == sizeof(uint64))
+                        n++;
+                }
+#endif
+                else {
+                    bh_assert(0);
+                }
+                break;
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_NULLREF:
+            /* case REF_TYPE_FUNCREF: */
+            /* case REF_TYPE_EXTERNREF: */
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case VALUE_TYPE_GC_REF:
+                if (!aot_frame_store_value(
+                        comp_ctx, param_values[i], VALUE_TYPE_GC_REF,
+                        func_ctx->cur_frame,
+                        offset_of_local_in_outs_area(comp_ctx, n)))
+                    return false;
+                if (comp_ctx->pointer_size == sizeof(uint64))
+                    n++;
+                break;
+#endif
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
+
+    return true;
+}
+
 bool
 aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                    uint32 func_idx, bool tail_call, const uint8 *frame_ip)
+                    uint32 func_idx, bool tail_call, const uint8 *frame_ip_call)
 {
     uint32 import_func_count = comp_ctx->comp_data->import_func_count;
     AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs;
@@ -558,8 +654,9 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             return false;
+
         if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
-                                  frame_ip))
+                                  frame_ip_call))
             return false;
     }
 
@@ -653,6 +750,12 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     if (func_idx < import_func_count) {
+        if (comp_ctx->enable_aux_stack_frame
+            && !commit_params_to_frame_of_import_func(
+                comp_ctx, func_ctx, func_type, param_values + 1)) {
+            goto fail;
+        }
+
         if (!(import_func_idx = I32_CONST(func_idx))) {
             aot_set_last_error("llvm build inbounds gep failed.");
             goto fail;
@@ -1081,7 +1184,7 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 bool
 aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                              uint32 type_idx, uint32 tbl_idx,
-                             const uint8 *frame_ip)
+                             const uint8 *frame_ip_call_indirect)
 {
     AOTFuncType *func_type;
     LLVMValueRef tbl_idx_value, elem_idx, func_idx;
@@ -1132,8 +1235,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             return false;
+
         if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
-                                  frame_ip))
+                                  frame_ip_call_indirect))
             return false;
     }
 
@@ -1528,6 +1632,12 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Translate call import block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import);
 
+    if (comp_ctx->enable_aux_stack_frame
+        && !commit_params_to_frame_of_import_func(comp_ctx, func_ctx, func_type,
+                                                  param_values + 1)) {
+        goto fail;
+    }
+
     /* Allocate memory for result values */
     if (func_result_count > 0) {
         total_size = sizeof(LLVMValueRef) * (uint64)func_result_count;
@@ -1722,16 +1832,27 @@ fail:
 
 bool
 aot_compile_op_ref_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        uint32 func_idx)
+                        uint32 func_idx, const uint8 *frame_ip_ref_func)
 {
     LLVMValueRef ref_idx;
+#if WASM_ENABLE_GC != 0
+    LLVMValueRef gc_obj;
+#endif
+
     if (!(ref_idx = I32_CONST(func_idx))) {
         HANDLE_FAILURE("LLVMConstInt");
         goto fail;
     }
+
 #if WASM_ENABLE_GC != 0
-    LLVMValueRef gc_obj;
     if (comp_ctx->enable_gc) {
+        if (!aot_gen_commit_values(comp_ctx->aot_frame))
+            return false;
+
+        if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
+                                  frame_ip_ref_func))
+            return false;
+
         if (!aot_call_aot_create_func_obj(comp_ctx, func_ctx, ref_idx,
                                           &gc_obj)) {
             goto fail;
@@ -1753,7 +1874,8 @@ fail:
 #if WASM_ENABLE_GC != 0
 bool
 aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        uint32 type_idx, bool tail_call, const uint8 *frame_ip)
+                        uint32 type_idx, bool tail_call,
+                        const uint8 *frame_ip_call_ref)
 {
     AOTFuncType *func_type;
     LLVMValueRef func_obj, func_idx;
@@ -1789,8 +1911,9 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     if (comp_ctx->aot_frame) {
         if (!aot_gen_commit_values(comp_ctx->aot_frame))
             return false;
+
         if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
-                                  frame_ip))
+                                  frame_ip_call_ref))
             return false;
     }
 
@@ -2010,6 +2133,12 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Translate call import block */
     LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_import);
 
+    if (comp_ctx->enable_aux_stack_frame
+        && !commit_params_to_frame_of_import_func(comp_ctx, func_ctx, func_type,
+                                                  param_values + 1)) {
+        goto fail;
+    }
+
     /* Similar to opcode call_indirect, but for opcode ref.func needs to call
      * aot_invoke_native_func instead */
     if (!call_aot_invoke_native_func(comp_ctx, func_ctx, func_idx, func_type,

+ 6 - 4
core/iwasm/compilation/aot_emit_function.h

@@ -14,12 +14,13 @@ extern "C" {
 
 bool
 aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                    uint32 func_idx, bool tail_call, const uint8 *frame_ip);
+                    uint32 func_idx, bool tail_call,
+                    const uint8 *frame_ip_call);
 
 bool
 aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                              uint32 type_idx, uint32 tbl_idx,
-                             const uint8 *frame_ip);
+                             const uint8 *frame_ip_call_indirect);
 
 bool
 aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
@@ -29,12 +30,13 @@ aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
 
 bool
 aot_compile_op_ref_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        uint32 func_idx);
+                        uint32 func_idx, const uint8 *frame_ip_ref_func);
 
 #if WASM_ENABLE_GC != 0
 bool
 aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        uint32 type_idx, bool tail_call, const uint8 *frame_ip);
+                        uint32 type_idx, bool tail_call,
+                        const uint8 *frame_ip_call_ref);
 #endif
 
 #ifdef __cplusplus

+ 36 - 4
core/iwasm/compilation/aot_emit_gc.c

@@ -528,11 +528,19 @@ fail:
 
 bool
 aot_compile_op_struct_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                          uint32 type_index, bool init_with_default)
+                          uint32 type_index, bool init_with_default,
+                          const uint8 *frame_ip_struct_new)
 {
     LLVMValueRef rtt_type, struct_obj, cmp;
     LLVMBasicBlockRef check_rtt_type_succ, check_struct_obj_succ;
 
+    if (!aot_gen_commit_values(comp_ctx->aot_frame))
+        return false;
+
+    if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
+                              frame_ip_struct_new))
+        return false;
+
     /* Generate call wasm_rtt_type_new and check for exception */
     if (!aot_call_aot_rtt_type_new(comp_ctx, func_ctx, I32_CONST(type_index),
                                    &rtt_type))
@@ -1107,7 +1115,8 @@ fail:
 bool
 aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                          uint32 type_index, bool init_with_default,
-                         bool fixed_size, uint32 array_len)
+                         bool fixed_size, uint32 array_len,
+                         const uint8 *frame_ip_array_new)
 {
     LLVMValueRef array_length, array_elem = NULL, array_obj;
     LLVMValueRef rtt_type, cmp, elem_idx;
@@ -1118,6 +1127,13 @@ aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     uint8 array_elem_type = compile_time_array_type->elem_type;
     uint32 i;
 
+    if (!aot_gen_commit_values(comp_ctx->aot_frame))
+        return false;
+
+    if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
+                              frame_ip_array_new))
+        return false;
+
     /* Generate call aot_rtt_type_new and check for exception */
     if (!aot_call_aot_rtt_type_new(comp_ctx, func_ctx, I32_CONST(type_index),
                                    &rtt_type))
@@ -1224,7 +1240,8 @@ fail:
 bool
 aot_compile_op_array_new_data(AOTCompContext *comp_ctx,
                               AOTFuncContext *func_ctx, uint32 type_index,
-                              uint32 data_seg_index)
+                              uint32 data_seg_index,
+                              const uint8 *frame_ip_array_new_data)
 {
     LLVMValueRef array_length, data_seg_offset, rtt_type,
         elem_size = NULL, array_elem, array_obj, cmp;
@@ -1234,6 +1251,13 @@ aot_compile_op_array_new_data(AOTCompContext *comp_ctx,
         (WASMArrayType *)comp_ctx->comp_data->types[type_index];
     uint8 array_elem_type = compile_time_array_type->elem_type;
 
+    if (!aot_gen_commit_values(comp_ctx->aot_frame))
+        return false;
+
+    if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
+                              frame_ip_array_new_data))
+        return false;
+
     /* Generate call aot_rtt_type_new and check for exception */
     if (!aot_call_aot_rtt_type_new(comp_ctx, func_ctx, I32_CONST(type_index),
                                    &rtt_type))
@@ -1911,11 +1935,19 @@ fail:
 
 bool
 aot_compile_op_extern_externalize(AOTCompContext *comp_ctx,
-                                  AOTFuncContext *func_ctx)
+                                  AOTFuncContext *func_ctx,
+                                  const uint8 *frame_ip_extern_externalize)
 {
     LLVMValueRef gc_obj, cmp, external_obj_phi, externref_obj;
     LLVMBasicBlockRef block_curr, block_obj_non_null, block_end;
 
+    if (!aot_gen_commit_values(comp_ctx->aot_frame))
+        return false;
+
+    if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, comp_ctx->aot_frame->sp,
+                              frame_ip_extern_externalize))
+        return false;
+
     POP_GC_REF(gc_obj);
 
     block_curr = CURR_BLOCK();

+ 8 - 4
core/iwasm/compilation/aot_emit_gc.h

@@ -39,7 +39,8 @@ aot_compile_op_ref_as_non_null(AOTCompContext *comp_ctx,
 
 bool
 aot_compile_op_struct_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                          uint32 type_index, bool init_with_default);
+                          uint32 type_index, bool init_with_default,
+                          const uint8 *frame_ip_struct_new);
 
 bool
 aot_compile_op_struct_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@@ -52,12 +53,14 @@ aot_compile_op_struct_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 bool
 aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                          uint32 type_index, bool init_with_default,
-                         bool fixed_size, uint32 array_len);
+                         bool fixed_size, uint32 array_len,
+                         const uint8 *frame_ip_array_new);
 
 bool
 aot_compile_op_array_new_data(AOTCompContext *comp_ctx,
                               AOTFuncContext *func_ctx, uint32 type_index,
-                              uint32 data_seg_index);
+                              uint32 data_seg_index,
+                              const uint8 *frame_ip_array_new_data);
 
 bool
 aot_compile_op_array_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@@ -97,7 +100,8 @@ aot_compile_op_extern_internalize(AOTCompContext *comp_ctx,
 
 bool
 aot_compile_op_extern_externalize(AOTCompContext *comp_ctx,
-                                  AOTFuncContext *func_ctx);
+                                  AOTFuncContext *func_ctx,
+                                  const uint8 *frame_ip_extern_externalize);
 
 #endif
 

+ 17 - 24
core/iwasm/compilation/aot_emit_variable.c

@@ -66,9 +66,10 @@ fail:
     return false;
 }
 
-bool
-aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                         uint32 local_idx)
+static bool
+aot_compile_op_set_or_tee_local(AOTCompContext *comp_ctx,
+                                AOTFuncContext *func_ctx, uint32 local_idx,
+                                bool is_tee_local)
 {
     LLVMValueRef value;
     uint8 local_type;
@@ -122,6 +123,10 @@ aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         return false;
     }
 
+    if (is_tee_local) {
+        PUSH(value, local_type);
+    }
+
     aot_checked_addr_list_del(func_ctx, local_idx);
     return true;
 
@@ -130,30 +135,18 @@ fail:
 }
 
 bool
-aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                          uint32 local_idx)
 {
-    LLVMValueRef value;
-    uint8 type;
-
-    CHECK_LOCAL(local_idx);
-
-    type = get_local_type(comp_ctx, func_ctx, local_idx);
-
-    POP(value, type);
-
-    if (!LLVMBuildStore(comp_ctx->builder, value,
-                        func_ctx->locals[local_idx])) {
-        aot_set_last_error("llvm build store fail");
-        return false;
-    }
-
-    PUSH(value, type);
-    aot_checked_addr_list_del(func_ctx, local_idx);
-    return true;
+    return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx,
+                                           false);
+}
 
-fail:
-    return false;
+bool
+aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                         uint32 local_idx)
+{
+    return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx, true);
 }
 
 static bool

+ 1 - 1
core/iwasm/compilation/aot_llvm.h

@@ -106,7 +106,7 @@ typedef struct AOTValueSlot {
     uint32 ref : 1;
 
     /* Committed reference flag:
-         0: unknown, 1: not-reference, 2: reference */
+         0: uncommitted, 1: not-reference, 2: reference */
     uint32 committed_ref : 2;
 } AOTValueSlot;
 

+ 5 - 0
core/iwasm/interpreter/wasm_interp.h

@@ -79,7 +79,12 @@ wasm_interp_interp_frame_size(unsigned all_cell_num)
     unsigned frame_size;
 
 #if WASM_ENABLE_FAST_INTERP == 0
+#if WASM_ENABLE_GC == 0
     frame_size = (uint32)offsetof(WASMInterpFrame, lp) + all_cell_num * 4;
+#else
+    frame_size =
+        (uint32)offsetof(WASMInterpFrame, lp) + align_uint(all_cell_num * 5, 4);
+#endif
 #else
     frame_size = (uint32)offsetof(WASMInterpFrame, operand) + all_cell_num * 4;
 #endif

+ 12 - 10
core/iwasm/interpreter/wasm_interp_classic.c

@@ -341,8 +341,14 @@ get_frame_ref(WASMInterpFrame *frame)
         return (uint8 *)(frame->lp + all_cell_num);
     }
     else {
+#if WASM_ENABLE_JIT == 0
         /* it's a wasm bytecode function frame */
         return (uint8 *)frame->csp_boundary;
+#else
+        return (uint8 *)(frame->lp + cur_func->param_cell_num
+                         + cur_func->local_cell_num
+                         + cur_func->u.func->max_stack_cell_num);
+#endif
     }
 }
 
@@ -361,11 +367,9 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
             frame_ref[j++] = 1;
 #endif
         }
-        else if (func->param_types[i] == VALUE_TYPE_I32
-                 || func->param_types[i] == VALUE_TYPE_F32)
-            j++;
-        else
-            j += 2;
+        else {
+            j += wasm_value_type_cell_num(func->param_types[i]);
+        }
     }
 
     for (i = 0; i < func->local_count; i++) {
@@ -376,11 +380,9 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
             frame_ref[j++] = 1;
 #endif
         }
-        else if (func->local_types[i] == VALUE_TYPE_I32
-                 || func->local_types[i] == VALUE_TYPE_F32)
-            j++;
-        else
-            j += 2;
+        else {
+            j += wasm_value_type_cell_num(func->local_types[i]);
+        }
     }
 }
 

+ 6 - 10
core/iwasm/interpreter/wasm_interp_fast.c

@@ -324,11 +324,9 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
             frame_ref[j++] = 1;
 #endif
         }
-        else if (func->param_types[i] == VALUE_TYPE_I32
-                 || func->param_types[i] == VALUE_TYPE_F32)
-            j++;
-        else
-            j += 2;
+        else {
+            j += wasm_value_type_cell_num(func->param_types[i]);
+        }
     }
 
     for (i = 0; i < func->local_count; i++) {
@@ -339,11 +337,9 @@ init_frame_refs(uint8 *frame_ref, uint32 cell_num, WASMFunctionInstance *func)
             frame_ref[j++] = 1;
 #endif
         }
-        else if (func->local_types[i] == VALUE_TYPE_I32
-                 || func->local_types[i] == VALUE_TYPE_F32)
-            j++;
-        else
-            j += 2;
+        else {
+            j += wasm_value_type_cell_num(func->local_types[i]);
+        }
     }
 }
 

+ 29 - 0
core/iwasm/interpreter/wasm_runtime.c

@@ -3800,6 +3800,35 @@ llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
     frame->time_started = os_time_get_boot_microsecond();
 #endif
     frame->prev_frame = wasm_exec_env_get_cur_frame(exec_env);
+
+#if WASM_ENABLE_GC != 0
+    /* Initialize frame ref flags for import function */
+    if (func_index < module->import_function_count) {
+        WASMFunctionImport *func =
+            &((module->import_functions + func_index)->u.function);
+        WASMFuncType *func_type = func->func_type;
+        /* native function doesn't have operand stack and label stack */
+        uint8 *frame_ref = (uint8 *)frame->sp;
+        uint32 i, j, k, value_type_cell_num;
+
+        for (i = 0, j = 0; i < func_type->param_count; i++) {
+            if (wasm_is_type_reftype(func_type->types[i])
+                && !wasm_is_reftype_i31ref(func_type->types[i])) {
+                frame_ref[j++] = 1;
+#if UINTPTR_MAX == UINT64_MAX
+                frame_ref[j++] = 1;
+#endif
+            }
+            else {
+                value_type_cell_num =
+                    wasm_value_type_cell_num(func_type->types[i]);
+                for (k = 0; k < value_type_cell_num; k++)
+                    frame_ref[j++] = 0;
+            }
+        }
+    }
+#endif
+
     wasm_exec_env_set_cur_frame(exec_env, frame);
 
     return true;

+ 7 - 6
core/shared/mem-alloc/ems/ems_gc.c

@@ -2,7 +2,8 @@
  * Copyright (C) 2022 Tencent Corporation.  All rights reserved.
  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  */
-#include "ems/ems_gc.h"
+
+#include "ems_gc.h"
 #include "ems_gc_internal.h"
 
 #define GB (1 << 30UL)
@@ -218,7 +219,7 @@ gc_add_root(void *heap_p, gc_object_t obj)
     }
 
     if (hmu_get_ut(hmu) != HMU_WO) {
-        LOG_ERROR("Given objecti s not wo");
+        LOG_ERROR("Given object is not wo");
         return GC_ERROR;
     }
 
@@ -378,8 +379,8 @@ reclaim_instance_heap(gc_heap_t *heap)
                     offset = ref_start_offset + j * sizeof(void *);
                     bh_assert(offset + sizeof(void *) < size);
                     ref = *(gc_object_t *)(((gc_uint8 *)obj) + offset);
-                    if (ref == NULL_REF)
-                        continue; /* NULL REF */
+                    if (ref == NULL_REF || ((uintptr_t)ref & 1))
+                        continue; /* null object or i31 object */
                     if (add_wo_to_expand(heap, ref) == GC_ERROR) {
                         LOG_ERROR("add_wo_to_expand failed");
                         break;
@@ -394,8 +395,8 @@ reclaim_instance_heap(gc_heap_t *heap)
                     bh_assert(offset + sizeof(void *) < size);
 
                     ref = *(gc_object_t *)(((gc_uint8 *)obj) + offset);
-                    if (ref == NULL_REF)
-                        continue; /* NULL REF */
+                    if (ref == NULL_REF || ((uintptr_t)ref & 1))
+                        continue; /* null object or i31 object */
                     if (add_wo_to_expand(heap, ref) == GC_ERROR) {
                         LOG_ERROR("mark process failed");
                         break;

+ 28 - 28
core/shared/mem-alloc/ems/ems_gc.h

@@ -199,34 +199,6 @@ gc_alloc_wo(void *heap, gc_size_t size);
 
 void
 gc_free_wo(void *vheap, void *ptr);
-
-extra_info_node_t *
-gc_search_extra_info_node(gc_handle_t handle, gc_object_t obj,
-                          gc_size_t *p_index);
-
-/**
- * Set finalizer to the given object, if another finalizer is set to the same
- * object, the previous one will be cancelled
- *
- * @param handle handle of the heap
- * @param obj object to set finalizer
- * @param cb finalizer function to be called before this object is freed
- * @param data custom data to be passed to finalizer function
- *
- * @return true if success, false otherwise
- */
-bool
-gc_set_finalizer(gc_handle_t handle, gc_object_t obj, gc_finalizer_t cb,
-                 void *data);
-
-/**
- * Unset finalizer to the given object
- *
- * @param handle handle of the heap
- * @param obj object to unset finalizer
- */
-void
-gc_unset_finalizer(gc_handle_t handle, gc_object_t obj);
 #endif
 
 #else /* else of BH_ENABLE_GC_VERIFY */
@@ -285,6 +257,34 @@ gc_add_root(void *heap, gc_object_t obj);
 int
 gci_gc_heap(void *heap);
 
+extra_info_node_t *
+gc_search_extra_info_node(gc_handle_t handle, gc_object_t obj,
+                          gc_size_t *p_index);
+
+/**
+ * Set finalizer to the given object, if another finalizer is set to the same
+ * object, the previous one will be cancelled
+ *
+ * @param handle handle of the heap
+ * @param obj object to set finalizer
+ * @param cb finalizer function to be called before this object is freed
+ * @param data custom data to be passed to finalizer function
+ *
+ * @return true if success, false otherwise
+ */
+bool
+gc_set_finalizer(gc_handle_t handle, gc_object_t obj, gc_finalizer_t cb,
+                 void *data);
+
+/**
+ * Unset finalizer to the given object
+ *
+ * @param handle handle of the heap
+ * @param obj object to unset finalizer
+ */
+void
+gc_unset_finalizer(gc_handle_t handle, gc_object_t obj);
+
 #if WASM_ENABLE_THREAD_MGR == 0
 bool
 wasm_runtime_traverse_gc_rootset(void *exec_env, void *heap);