Browse Source

Enhance AOT stack frame dump (#2541)

Add cmake varaible WAMR_BUILD_AOT_STACK_FRAME and auto enable it for
dump-call-stack and perf-profiling features. Extend WASMCApiFrame and
commit more data to it in dump-call-stack.

Commit stack pointer and instruction pointer when calling functions.
Enable setting callback when exception is thrown for debug purpose.
Wenyong Huang 2 năm trước cách đây
mục cha
commit
fd5862fbe0

+ 12 - 0
build-scripts/config_common.cmake

@@ -281,12 +281,22 @@ if (WAMR_BUILD_SIMD EQUAL 1)
     message ("     SIMD disabled due to not supported on target RISCV64")
     message ("     SIMD disabled due to not supported on target RISCV64")
   endif ()
   endif ()
 endif ()
 endif ()
+if (WAMR_BUILD_AOT_STACK_FRAME EQUAL 1)
+  add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1)
+  message ("     AOT stack frame enabled")
+endif ()
+if (WAMR_BUILD_JIT_STACK_FRAME EQUAL 1)
+  add_definitions (-DWASM_ENABLE_JIT_STACK_FRAME=1)
+  message ("     JIT stack frame enabled")
+endif ()
 if (WAMR_BUILD_MEMORY_PROFILING EQUAL 1)
 if (WAMR_BUILD_MEMORY_PROFILING EQUAL 1)
   add_definitions (-DWASM_ENABLE_MEMORY_PROFILING=1)
   add_definitions (-DWASM_ENABLE_MEMORY_PROFILING=1)
   message ("     Memory profiling enabled")
   message ("     Memory profiling enabled")
 endif ()
 endif ()
 if (WAMR_BUILD_PERF_PROFILING EQUAL 1)
 if (WAMR_BUILD_PERF_PROFILING EQUAL 1)
   add_definitions (-DWASM_ENABLE_PERF_PROFILING=1)
   add_definitions (-DWASM_ENABLE_PERF_PROFILING=1)
+  add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1)
+  add_definitions (-DWASM_ENABLE_JIT_STACK_FRAME=1)
   message ("     Performance profiling enabled")
   message ("     Performance profiling enabled")
 endif ()
 endif ()
 if (DEFINED WAMR_APP_THREAD_STACK_SIZE_MAX)
 if (DEFINED WAMR_APP_THREAD_STACK_SIZE_MAX)
@@ -298,6 +308,8 @@ if (WAMR_BUILD_CUSTOM_NAME_SECTION EQUAL 1)
 endif ()
 endif ()
 if (WAMR_BUILD_DUMP_CALL_STACK EQUAL 1)
 if (WAMR_BUILD_DUMP_CALL_STACK EQUAL 1)
   add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1)
   add_definitions (-DWASM_ENABLE_DUMP_CALL_STACK=1)
+  add_definitions (-DWASM_ENABLE_AOT_STACK_FRAME=1)
+  add_definitions (-DWASM_ENABLE_JIT_STACK_FRAME=1)
   message ("     Dump call stack enabled")
   message ("     Dump call stack enabled")
 endif ()
 endif ()
 if (WAMR_BUILD_TAIL_CALL EQUAL 1)
 if (WAMR_BUILD_TAIL_CALL EQUAL 1)

+ 10 - 0
core/config.h

@@ -310,6 +310,16 @@
 #define WASM_ENABLE_DUMP_CALL_STACK 0
 #define WASM_ENABLE_DUMP_CALL_STACK 0
 #endif
 #endif
 
 
+/* AOT stack frame */
+#ifndef WASM_ENABLE_AOT_STACK_FRAME
+#define WASM_ENABLE_AOT_STACK_FRAME 0
+#endif
+
+/* JIT stack frame */
+#ifndef WASM_ENABLE_JIT_STACK_FRAME
+#define WASM_ENABLE_JIT_STACK_FRAME 0
+#endif
+
 /* Heap verification */
 /* Heap verification */
 #ifndef BH_ENABLE_GC_VERIFY
 #ifndef BH_ENABLE_GC_VERIFY
 #define BH_ENABLE_GC_VERIFY 0
 #define BH_ENABLE_GC_VERIFY 0

+ 2 - 2
core/iwasm/aot/aot_loader.c

@@ -1705,7 +1705,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
     size = sizeof(uint32) * (uint64)module->func_count;
     size = sizeof(uint32) * (uint64)module->func_count;
 
 
     if (size > 0) {
     if (size > 0) {
-#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
         if (!(module->max_local_cell_nums =
         if (!(module->max_local_cell_nums =
                   loader_malloc(size, error_buf, error_buf_size))) {
                   loader_malloc(size, error_buf, error_buf_size))) {
             return false;
             return false;
@@ -3224,7 +3224,7 @@ aot_unload(AOTModule *module)
     if (module->func_type_indexes)
     if (module->func_type_indexes)
         wasm_runtime_free(module->func_type_indexes);
         wasm_runtime_free(module->func_type_indexes);
 
 
-#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
     if (module->max_local_cell_nums)
     if (module->max_local_cell_nums)
         wasm_runtime_free(module->max_local_cell_nums);
         wasm_runtime_free(module->max_local_cell_nums);
     if (module->max_stack_cell_nums)
     if (module->max_stack_cell_nums)

+ 1 - 1
core/iwasm/aot/aot_reloc.h

@@ -49,7 +49,7 @@ typedef struct {
 #define REG_REF_TYPES_SYM()
 #define REG_REF_TYPES_SYM()
 #endif
 #endif
 
 
-#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
 #define REG_AOT_TRACE_SYM()               \
 #define REG_AOT_TRACE_SYM()               \
     REG_SYM(aot_alloc_frame),             \
     REG_SYM(aot_alloc_frame),             \
     REG_SYM(aot_free_frame),
     REG_SYM(aot_free_frame),

+ 106 - 19
core/iwasm/aot/aot_runtime.c

@@ -1237,6 +1237,29 @@ fail:
     return NULL;
     return NULL;
 }
 }
 
 
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+static void
+destroy_c_api_frames(Vector *frames)
+{
+    WASMCApiFrame frame = { 0 };
+    uint32 i, total_frames, ret;
+
+    total_frames = (uint32)bh_vector_size(frames);
+
+    for (i = 0; i < total_frames; i++) {
+        ret = bh_vector_get(frames, i, &frame);
+        bh_assert(ret);
+
+        if (frame.lp)
+            wasm_runtime_free(frame.lp);
+    }
+
+    ret = bh_vector_destroy(frames);
+    bh_assert(ret);
+    (void)ret;
+}
+#endif
+
 void
 void
 aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 {
 {
@@ -1256,7 +1279,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 
 
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
     if (module_inst->frames) {
     if (module_inst->frames) {
-        bh_vector_destroy(module_inst->frames);
+        destroy_c_api_frames(module_inst->frames);
         wasm_runtime_free(module_inst->frames);
         wasm_runtime_free(module_inst->frames);
         module_inst->frames = NULL;
         module_inst->frames = NULL;
     }
     }
@@ -1412,6 +1435,18 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
 #define invoke_native_internal wasm_runtime_invoke_native
 #define invoke_native_internal wasm_runtime_invoke_native
 #endif /* end of OS_ENABLE_HW_BOUND_CHECK */
 #endif /* end of OS_ENABLE_HW_BOUND_CHECK */
 
 
+#ifdef AOT_STACK_FRAME_DEBUG
+typedef void (*stack_frame_callback_t)(struct WASMExecEnv *exec_env);
+static stack_frame_callback_t aot_stack_frame_callback;
+
+/* set the callback, only for debug purpose */
+void
+aot_set_stack_frame_callback(stack_frame_callback_t callback)
+{
+    aot_stack_frame_callback = callback;
+}
+#endif
+
 bool
 bool
 aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
 aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
                   unsigned argc, uint32 argv[])
                   unsigned argc, uint32 argv[])
@@ -1485,7 +1520,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
             cell_num += wasm_value_type_cell_num(ext_ret_types[i]);
             cell_num += wasm_value_type_cell_num(ext_ret_types[i]);
         }
         }
 
 
-#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
         if (!aot_alloc_frame(exec_env, function->func_index)) {
         if (!aot_alloc_frame(exec_env, function->func_index)) {
             if (argv1 != argv1_buf)
             if (argv1 != argv1_buf)
                 wasm_runtime_free(argv1);
                 wasm_runtime_free(argv1);
@@ -1496,15 +1531,20 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv1, argc, argv);
                                      func_type, NULL, NULL, argv1, argc, argv);
 
 
-#if WASM_ENABLE_DUMP_CALL_STACK != 0
         if (!ret) {
         if (!ret) {
+#ifdef AOT_STACK_FRAME_DEBUG
+            if (aot_stack_frame_callback) {
+                aot_stack_frame_callback(exec_env);
+            }
+#endif
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
             if (aot_create_call_stack(exec_env)) {
             if (aot_create_call_stack(exec_env)) {
                 aot_dump_call_stack(exec_env, true, NULL, 0);
                 aot_dump_call_stack(exec_env, true, NULL, 0);
             }
             }
-        }
 #endif
 #endif
+        }
 
 
-#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
         aot_free_frame(exec_env);
         aot_free_frame(exec_env);
 #endif
 #endif
         if (!ret) {
         if (!ret) {
@@ -1546,7 +1586,7 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         return true;
         return true;
     }
     }
     else {
     else {
-#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
         if (!aot_alloc_frame(exec_env, function->func_index)) {
         if (!aot_alloc_frame(exec_env, function->func_index)) {
             return false;
             return false;
         }
         }
@@ -1555,15 +1595,20 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
         ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
                                      func_type, NULL, NULL, argv, argc, argv);
                                      func_type, NULL, NULL, argv, argc, argv);
 
 
-#if WASM_ENABLE_DUMP_CALL_STACK != 0
         if (aot_copy_exception(module_inst, NULL)) {
         if (aot_copy_exception(module_inst, NULL)) {
+#ifdef AOT_STACK_FRAME_DEBUG
+            if (aot_stack_frame_callback) {
+                aot_stack_frame_callback(exec_env);
+            }
+#endif
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
             if (aot_create_call_stack(exec_env)) {
             if (aot_create_call_stack(exec_env)) {
                 aot_dump_call_stack(exec_env, true, NULL, 0);
                 aot_dump_call_stack(exec_env, true, NULL, 0);
             }
             }
-        }
 #endif
 #endif
+        }
 
 
-#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
         aot_free_frame(exec_env);
         aot_free_frame(exec_env);
 #endif
 #endif
 
 
@@ -2582,7 +2627,8 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx,
 }
 }
 #endif /* WASM_ENABLE_REF_TYPES != 0 */
 #endif /* WASM_ENABLE_REF_TYPES != 0 */
 
 
-#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
+#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
 #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
 #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
 static const char *
 static const char *
 lookup_func_name(const char **func_names, uint32 *func_indexes,
 lookup_func_name(const char **func_names, uint32 *func_indexes,
@@ -2641,6 +2687,8 @@ get_func_name_from_index(const AOTModuleInstance *module_inst,
 
 
     return func_name;
     return func_name;
 }
 }
+#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 || \
+          WASM_ENABLE_PERF_PROFILING != 0 */
 
 
 bool
 bool
 aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
 aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
@@ -2713,8 +2761,7 @@ aot_free_frame(WASMExecEnv *exec_env)
     wasm_exec_env_free_wasm_frame(exec_env, cur_frame);
     wasm_exec_env_free_wasm_frame(exec_env, cur_frame);
     exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame;
     exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame;
 }
 }
-#endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) \
-                 || (WASM_ENABLE_PERF_PROFILING != 0) */
+#endif /* end of WASM_ENABLE_AOT_STACK_FRAME != 0 */
 
 
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
 bool
 bool
@@ -2723,6 +2770,7 @@ aot_create_call_stack(struct WASMExecEnv *exec_env)
     AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame,
     AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame,
              *first_frame = cur_frame;
              *first_frame = cur_frame;
     AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
     AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
+    AOTModule *module = (AOTModule *)module_inst->module;
     uint32 n = 0;
     uint32 n = 0;
 
 
     while (cur_frame) {
     while (cur_frame) {
@@ -2731,24 +2779,63 @@ aot_create_call_stack(struct WASMExecEnv *exec_env)
     }
     }
 
 
     /* release previous stack frames and create new ones */
     /* release previous stack frames and create new ones */
-    if (!bh_vector_destroy(module_inst->frames)
-        || !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame),
-                           false)) {
+    destroy_c_api_frames(module_inst->frames);
+    if (!bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame), false)) {
         return false;
         return false;
     }
     }
 
 
     cur_frame = first_frame;
     cur_frame = first_frame;
     while (cur_frame) {
     while (cur_frame) {
         WASMCApiFrame frame = { 0 };
         WASMCApiFrame frame = { 0 };
+        uint32 max_local_cell_num, max_stack_cell_num;
+        uint32 all_cell_num, lp_size;
+
         frame.instance = module_inst;
         frame.instance = module_inst;
         frame.module_offset = 0;
         frame.module_offset = 0;
         frame.func_index = cur_frame->func_index;
         frame.func_index = cur_frame->func_index;
-        frame.func_offset = 0;
+        frame.func_offset = cur_frame->ip_offset;
         frame.func_name_wp =
         frame.func_name_wp =
             get_func_name_from_index(module_inst, cur_frame->func_index);
             get_func_name_from_index(module_inst, cur_frame->func_index);
 
 
+        if (cur_frame->func_index >= module->import_func_count) {
+            uint32 aot_func_idx =
+                cur_frame->func_index - module->import_func_count;
+            max_local_cell_num = module->max_local_cell_nums[aot_func_idx];
+            max_stack_cell_num = module->max_stack_cell_nums[aot_func_idx];
+        }
+        else {
+            AOTFuncType *func_type =
+                module->import_funcs[cur_frame->func_index].func_type;
+            max_local_cell_num =
+                func_type->param_cell_num > 2 ? func_type->param_cell_num : 2;
+            max_stack_cell_num = 0;
+        }
+
+        all_cell_num = max_local_cell_num + max_stack_cell_num;
+#if WASM_ENABLE_GC == 0
+        lp_size = all_cell_num * 4;
+#else
+        lp_size = align_uint(all_cell_num * 5, 4);
+#endif
+        if (lp_size > 0) {
+            if (!(frame.lp = wasm_runtime_malloc(lp_size))) {
+                destroy_c_api_frames(module_inst->frames);
+                return false;
+            }
+            bh_memcpy_s(frame.lp, lp_size, cur_frame->lp, lp_size);
+
+            /* Only save frame sp when fast-interpr isn't enabled */
+            frame.sp = frame.lp + (cur_frame->sp - cur_frame->lp);
+#if WASM_ENABLE_GC != 0
+            frame.frame_ref = (uint8 *)frame.lp
+                              + (cur_frame->frame_ref - (uint8 *)cur_frame->lp);
+#endif
+        }
+
         if (!bh_vector_append(module_inst->frames, &frame)) {
         if (!bh_vector_append(module_inst->frames, &frame)) {
-            bh_vector_destroy(module_inst->frames);
+            if (frame.lp)
+                wasm_runtime_free(frame.lp);
+            destroy_c_api_frames(module_inst->frames);
             return false;
             return false;
         }
         }
 
 
@@ -2826,7 +2913,7 @@ aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len)
 
 
     return total_len + 1;
     return total_len + 1;
 }
 }
-#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */
+#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 */
 
 
 #if WASM_ENABLE_PERF_PROFILING != 0
 #if WASM_ENABLE_PERF_PROFILING != 0
 void
 void
@@ -2854,7 +2941,7 @@ aot_dump_perf_profiling(const AOTModuleInstance *module_inst)
                       perf_prof->total_exec_cnt);
                       perf_prof->total_exec_cnt);
     }
     }
 }
 }
-#endif /* end of WASM_ENABLE_PERF_PROFILING */
+#endif /* end of WASM_ENABLE_PERF_PROFILING != 0 */
 
 
 #if WASM_ENABLE_STATIC_PGO != 0
 #if WASM_ENABLE_STATIC_PGO != 0
 
 

+ 1 - 1
core/iwasm/aot/aot_runtime.h

@@ -154,7 +154,7 @@ typedef struct AOTModule {
     void **func_ptrs;
     void **func_ptrs;
     /* func type indexes of AOTed (un-imported) functions */
     /* func type indexes of AOTed (un-imported) functions */
     uint32 *func_type_indexes;
     uint32 *func_type_indexes;
-#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+#if WASM_ENABLE_AOT_STACK_FRAME != 0
     /* max local cell nums of AOTed (un-imported) functions */
     /* max local cell nums of AOTed (un-imported) functions */
     uint32 *max_local_cell_nums;
     uint32 *max_local_cell_nums;
     /* max stack cell nums of AOTed (un-imported) functions */
     /* max stack cell nums of AOTed (un-imported) functions */

+ 4 - 0
core/iwasm/common/wasm_runtime_common.h

@@ -414,6 +414,10 @@ typedef struct wasm_frame_t {
     uint32 func_index;
     uint32 func_index;
     uint32 func_offset;
     uint32 func_offset;
     const char *func_name_wp;
     const char *func_name_wp;
+
+    uint32 *sp;
+    uint8 *frame_ref;
+    uint32 *lp;
 } WASMCApiFrame;
 } WASMCApiFrame;
 
 
 #ifdef WASM_ENABLE_JIT
 #ifdef WASM_ENABLE_JIT

+ 18 - 5
core/iwasm/compilation/aot_compiler.c

@@ -291,7 +291,8 @@ aot_gen_commit_values(AOTCompFrame *frame)
 }
 }
 
 
 bool
 bool
-aot_gen_commit_sp_ip(AOTCompFrame *frame, AOTValueSlot *sp, uint8 *ip)
+aot_gen_commit_sp_ip(AOTCompFrame *frame, const AOTValueSlot *sp,
+                     const uint8 *ip)
 {
 {
     AOTCompContext *comp_ctx = frame->comp_ctx;
     AOTCompContext *comp_ctx = frame->comp_ctx;
     AOTFuncContext *func_ctx = frame->func_ctx;
     AOTFuncContext *func_ctx = frame->func_ctx;
@@ -732,13 +733,19 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 break;
                 break;
 
 
             case WASM_OP_CALL:
             case WASM_OP_CALL:
+            {
+                uint8 *frame_ip_org = frame_ip;
+
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
-                if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false))
+                if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, false,
+                                         frame_ip_org))
                     return false;
                     return false;
                 break;
                 break;
+            }
 
 
             case WASM_OP_CALL_INDIRECT:
             case WASM_OP_CALL_INDIRECT:
             {
             {
+                uint8 *frame_ip_org = frame_ip;
                 uint32 tbl_idx;
                 uint32 tbl_idx;
 
 
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
@@ -755,26 +762,32 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 }
                 }
 
 
                 if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
                 if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
-                                                  tbl_idx))
+                                                  tbl_idx, frame_ip_org))
                     return false;
                     return false;
                 break;
                 break;
             }
             }
 
 
 #if WASM_ENABLE_TAIL_CALL != 0
 #if WASM_ENABLE_TAIL_CALL != 0
             case WASM_OP_RETURN_CALL:
             case WASM_OP_RETURN_CALL:
+            {
+                uint8 *frame_ip_org = frame_ip;
+
                 if (!comp_ctx->enable_tail_call) {
                 if (!comp_ctx->enable_tail_call) {
                     aot_set_last_error("unsupported opcode");
                     aot_set_last_error("unsupported opcode");
                     return false;
                     return false;
                 }
                 }
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
-                if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, true))
+                if (!aot_compile_op_call(comp_ctx, func_ctx, func_idx, true,
+                                         frame_ip_org))
                     return false;
                     return false;
                 if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
                 if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
                     return false;
                     return false;
                 break;
                 break;
+            }
 
 
             case WASM_OP_RETURN_CALL_INDIRECT:
             case WASM_OP_RETURN_CALL_INDIRECT:
             {
             {
+                uint8 *frame_ip_org = frame_ip;
                 uint32 tbl_idx;
                 uint32 tbl_idx;
 
 
                 if (!comp_ctx->enable_tail_call) {
                 if (!comp_ctx->enable_tail_call) {
@@ -795,7 +808,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 }
                 }
 
 
                 if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
                 if (!aot_compile_op_call_indirect(comp_ctx, func_ctx, type_idx,
-                                                  tbl_idx))
+                                                  tbl_idx, frame_ip_org))
                     return false;
                     return false;
                 if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
                 if (!aot_compile_op_return(comp_ctx, func_ctx, &frame_ip))
                     return false;
                     return false;

+ 2 - 1
core/iwasm/compilation/aot_compiler.h

@@ -159,7 +159,8 @@ aot_gen_commit_values(AOTCompFrame *frame);
  * @param frame the frame information
  * @param frame the frame information
  */
  */
 bool
 bool
-aot_gen_commit_sp_ip(AOTCompFrame *frame, AOTValueSlot *sp, uint8 *ip);
+aot_gen_commit_sp_ip(AOTCompFrame *frame, const AOTValueSlot *sp,
+                     const uint8 *ip);
 
 
 static inline void
 static inline void
 push_32bit(AOTCompFrame *frame, AOTValue *aot_value)
 push_32bit(AOTCompFrame *frame, AOTValue *aot_value)

+ 3 - 2
core/iwasm/compilation/aot_emit_exception.c

@@ -21,8 +21,9 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
 
     CHECK_LLVM_CONST(exce_id);
     CHECK_LLVM_CONST(exce_id);
 
 
-    if (comp_ctx->aot_frame && !aot_gen_commit_values(comp_ctx->aot_frame)) {
-        goto fail;
+    if (comp_ctx->aot_frame) {
+        if (!aot_gen_commit_values(comp_ctx->aot_frame))
+            goto fail;
     }
     }
 
 
     /* Create got_exception block if needed */
     /* Create got_exception block if needed */

+ 29 - 18
core/iwasm/compilation/aot_emit_function.c

@@ -510,7 +510,7 @@ aot_estimate_and_record_stack_usage_for_function_call(
 
 
 bool
 bool
 aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                    uint32 func_idx, bool tail_call)
+                    uint32 func_idx, bool tail_call, const uint8 *frame_ip)
 {
 {
     uint32 import_func_count = comp_ctx->comp_data->import_func_count;
     uint32 import_func_count = comp_ctx->comp_data->import_func_count;
     AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs;
     AOTImportFunc *import_funcs = comp_ctx->comp_data->import_funcs;
@@ -531,18 +531,6 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     bool ret = false;
     bool ret = false;
     char buf[32];
     char buf[32];
 
 
-    if (comp_ctx->aot_frame && !aot_gen_commit_values(comp_ctx->aot_frame)) {
-        return false;
-    }
-
-#if WASM_ENABLE_THREAD_MGR != 0
-    /* Insert suspend check point */
-    if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx, true))
-            return false;
-    }
-#endif
-
     /* Check function index */
     /* Check function index */
     if (func_idx >= import_func_count + func_count) {
     if (func_idx >= import_func_count + func_count) {
         aot_set_last_error("Function index out of range.");
         aot_set_last_error("Function index out of range.");
@@ -564,6 +552,23 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* Get param cell number */
     /* Get param cell number */
     param_cell_num = func_type->param_cell_num;
     param_cell_num = func_type->param_cell_num;
 
 
+    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 - param_cell_num,
+                                  frame_ip))
+            return false;
+    }
+
+#if WASM_ENABLE_THREAD_MGR != 0
+    /* Insert suspend check point */
+    if (comp_ctx->enable_thread_mgr) {
+        if (!check_suspend_flags(comp_ctx, func_ctx, true))
+            return false;
+    }
+#endif
+
 #if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
 #if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
     if (comp_ctx->enable_aux_stack_frame) {
     if (comp_ctx->enable_aux_stack_frame) {
         LLVMValueRef func_idx_const;
         LLVMValueRef func_idx_const;
@@ -1068,7 +1073,8 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
 
 bool
 bool
 aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                             uint32 type_idx, uint32 tbl_idx)
+                             uint32 type_idx, uint32 tbl_idx,
+                             const uint8 *frame_ip)
 {
 {
     AOTFuncType *func_type;
     AOTFuncType *func_type;
     LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx;
     LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx;
@@ -1092,10 +1098,6 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     char buf[32];
     char buf[32];
     bool ret = false;
     bool ret = false;
 
 
-    if (comp_ctx->aot_frame && !aot_gen_commit_values(comp_ctx->aot_frame)) {
-        return false;
-    }
-
     /* Check function type index */
     /* Check function type index */
     if (type_idx >= comp_ctx->comp_data->func_type_count) {
     if (type_idx >= comp_ctx->comp_data->func_type_count) {
         aot_set_last_error("function type index out of range");
         aot_set_last_error("function type index out of range");
@@ -1120,6 +1122,15 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     func_param_count = func_type->param_count;
     func_param_count = func_type->param_count;
     func_result_count = func_type->result_count;
     func_result_count = func_type->result_count;
 
 
+    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 - func_type->param_cell_num, frame_ip))
+            return false;
+    }
+
     POP_I32(elem_idx);
     POP_I32(elem_idx);
 
 
     /* get the cur size of the table instance */
     /* get the cur size of the table instance */

+ 3 - 2
core/iwasm/compilation/aot_emit_function.h

@@ -14,11 +14,12 @@ extern "C" {
 
 
 bool
 bool
 aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                    uint32 func_idx, bool tail_call);
+                    uint32 func_idx, bool tail_call, const uint8 *frame_ip);
 
 
 bool
 bool
 aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                             uint32 type_idx, uint32 tbl_idx);
+                             uint32 type_idx, uint32 tbl_idx,
+                             const uint8 *frame_ip);
 
 
 bool
 bool
 aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
 aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);

+ 78 - 5
core/iwasm/interpreter/wasm_runtime.c

@@ -2134,6 +2134,29 @@ fail:
     return NULL;
     return NULL;
 }
 }
 
 
+#if WASM_ENABLE_DUMP_CALL_STACK != 0
+static void
+destroy_c_api_frames(Vector *frames)
+{
+    WASMCApiFrame frame = { 0 };
+    uint32 i, total_frames, ret;
+
+    total_frames = (uint32)bh_vector_size(frames);
+
+    for (i = 0; i < total_frames; i++) {
+        ret = bh_vector_get(frames, i, &frame);
+        bh_assert(ret);
+
+        if (frame.lp)
+            wasm_runtime_free(frame.lp);
+    }
+
+    ret = bh_vector_destroy(frames);
+    bh_assert(ret);
+    (void)ret;
+}
+#endif
+
 void
 void
 wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
 wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
 {
 {
@@ -2223,7 +2246,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
 
 
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
     if (module_inst->frames) {
     if (module_inst->frames) {
-        bh_vector_destroy(module_inst->frames);
+        destroy_c_api_frames(module_inst->frames);
         wasm_runtime_free(module_inst->frames);
         wasm_runtime_free(module_inst->frames);
         module_inst->frames = NULL;
         module_inst->frames = NULL;
     }
     }
@@ -2892,6 +2915,7 @@ wasm_interp_create_call_stack(struct WASMExecEnv *exec_env)
 {
 {
     WASMModuleInstance *module_inst =
     WASMModuleInstance *module_inst =
         (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env);
         (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env);
+    WASMModule *module = module_inst->module;
     WASMInterpFrame *first_frame,
     WASMInterpFrame *first_frame,
         *cur_frame = wasm_exec_env_get_cur_frame(exec_env);
         *cur_frame = wasm_exec_env_get_cur_frame(exec_env);
     uint32 n = 0;
     uint32 n = 0;
@@ -2906,9 +2930,8 @@ wasm_interp_create_call_stack(struct WASMExecEnv *exec_env)
     }
     }
 
 
     /* release previous stack frames and create new ones */
     /* release previous stack frames and create new ones */
-    if (!bh_vector_destroy(module_inst->frames)
-        || !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame),
-                           false)) {
+    destroy_c_api_frames(module_inst->frames);
+    if (!bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame), false)) {
         return false;
         return false;
     }
     }
 
 
@@ -2920,6 +2943,8 @@ wasm_interp_create_call_stack(struct WASMExecEnv *exec_env)
         WASMFunctionInstance *func_inst = cur_frame->function;
         WASMFunctionInstance *func_inst = cur_frame->function;
         const char *func_name = NULL;
         const char *func_name = NULL;
         const uint8 *func_code_base = NULL;
         const uint8 *func_code_base = NULL;
+        uint32 max_local_cell_num, max_stack_cell_num;
+        uint32 all_cell_num, lp_size;
 
 
         if (!func_inst) {
         if (!func_inst) {
             cur_frame = cur_frame->prev_frame;
             cur_frame = cur_frame->prev_frame;
@@ -2964,8 +2989,56 @@ wasm_interp_create_call_stack(struct WASMExecEnv *exec_env)
 
 
         frame.func_name_wp = func_name;
         frame.func_name_wp = func_name;
 
 
+        if (frame.func_index >= module->import_function_count) {
+            uint32 wasm_func_idx =
+                frame.func_index - module->import_function_count;
+            max_local_cell_num =
+                module->functions[wasm_func_idx]->param_cell_num
+                + module->functions[wasm_func_idx]->local_cell_num;
+            max_stack_cell_num =
+                module->functions[wasm_func_idx]->max_stack_cell_num;
+            all_cell_num = max_local_cell_num + max_stack_cell_num;
+#if WASM_ENABLE_FAST_INTERP != 0
+            all_cell_num += module->functions[wasm_func_idx]->const_cell_num;
+#endif
+        }
+        else {
+            WASMType *func_type =
+                module->import_functions[frame.func_index].u.function.func_type;
+            max_local_cell_num =
+                func_type->param_cell_num > 2 ? func_type->param_cell_num : 2;
+            max_stack_cell_num = 0;
+            all_cell_num = max_local_cell_num + max_stack_cell_num;
+        }
+
+#if WASM_ENABLE_GC == 0
+        lp_size = all_cell_num * 4;
+#else
+        lp_size = align_uint(all_cell_num * 5, 4);
+#endif
+        if (lp_size > 0) {
+            if (!(frame.lp = wasm_runtime_malloc(lp_size))) {
+                destroy_c_api_frames(module_inst->frames);
+                return false;
+            }
+            bh_memcpy_s(frame.lp, lp_size, cur_frame->lp, lp_size);
+
+#if WASM_ENABLE_FAST_INTERP == 0
+            frame.sp = frame.lp + (cur_frame->sp - cur_frame->lp);
+#else
+            /* for fast-interp, let frame sp point to the end of the frame */
+            frame.sp = frame.lp + all_cell_num;
+#endif
+#if WASM_ENABLE_GC != 0
+            frame.frame_ref = (uint8 *)frame.lp
+                              + (cur_frame->frame_ref - (uint8 *)cur_frame->lp);
+#endif
+        }
+
         if (!bh_vector_append(module_inst->frames, &frame)) {
         if (!bh_vector_append(module_inst->frames, &frame)) {
-            bh_vector_destroy(module_inst->frames);
+            if (frame.lp)
+                wasm_runtime_free(frame.lp);
+            destroy_c_api_frames(module_inst->frames);
             return false;
             return false;
         }
         }
 
 

+ 1 - 0
wamr-compiler/CMakeLists.txt

@@ -41,6 +41,7 @@ add_definitions(-DWASM_ENABLE_TAIL_CALL=1)
 add_definitions(-DWASM_ENABLE_SIMD=1)
 add_definitions(-DWASM_ENABLE_SIMD=1)
 add_definitions(-DWASM_ENABLE_REF_TYPES=1)
 add_definitions(-DWASM_ENABLE_REF_TYPES=1)
 add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
 add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
+add_definitions(-DWASM_ENABLE_AOT_STACK_FRAME=1)
 add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1)
 add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1)
 add_definitions(-DWASM_ENABLE_PERF_PROFILING=1)
 add_definitions(-DWASM_ENABLE_PERF_PROFILING=1)
 add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
 add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)