Explorar o código

Enhance LLVM AOT/JIT stack frame dump (#2350)

Implement a full LLVM AOT/JIT stack frame dump:
commit the function arguments, locals, stack operands from LLVM values to the stack frame,
which is required by the GC AOT/JIT feature, and may be required by the AOT debugger,
AOT snapshot and other features.

Refer to:
https://github.com/bytecodealliance/wasm-micro-runtime/issues/2144
https://github.com/bytecodealliance/wasm-micro-runtime/issues/2333
https://github.com/bytecodealliance/wasm-micro-runtime/issues/2506
Wenyong Huang %!s(int64=2) %!d(string=hai) anos
pai
achega
33ac031a3b

+ 35 - 0
core/iwasm/aot/aot_loader.c

@@ -1702,6 +1702,34 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module,
         }
     }
 
+    size = sizeof(uint32) * (uint64)module->func_count;
+
+    if (size > 0) {
+#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+        if (!(module->max_local_cell_nums =
+                  loader_malloc(size, error_buf, error_buf_size))) {
+            return false;
+        }
+
+        for (i = 0; i < module->func_count; i++) {
+            read_uint32(p, p_end, module->max_local_cell_nums[i]);
+        }
+
+        if (!(module->max_stack_cell_nums =
+                  loader_malloc(size, error_buf, error_buf_size))) {
+            return false;
+        }
+
+        for (i = 0; i < module->func_count; i++) {
+            read_uint32(p, p_end, module->max_stack_cell_nums[i]);
+        }
+#else
+        /* Ignore max_local_cell_num and max_stack_cell_num of each function */
+        CHECK_BUF(p, p_end, ((uint32)size * 2));
+        p += (uint32)size * 2;
+#endif
+    }
+
     if (p != buf_end) {
         set_error_buf(error_buf, error_buf_size,
                       "invalid function section size");
@@ -3196,6 +3224,13 @@ aot_unload(AOTModule *module)
     if (module->func_type_indexes)
         wasm_runtime_free(module->func_type_indexes);
 
+#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+    if (module->max_local_cell_nums)
+        wasm_runtime_free(module->max_local_cell_nums);
+    if (module->max_stack_cell_nums)
+        wasm_runtime_free(module->max_stack_cell_nums);
+#endif
+
     if (module->func_ptrs)
         wasm_runtime_free(module->func_ptrs);
 

+ 39 - 6
core/iwasm/aot/aot_runtime.c

@@ -20,6 +20,7 @@
  * AoT compilation code: aot_create_func_context, check_suspend_flags.
  */
 
+bh_static_assert(offsetof(WASMExecEnv, cur_frame) == 1 * sizeof(uintptr_t));
 bh_static_assert(offsetof(WASMExecEnv, module_inst) == 2 * sizeof(uintptr_t));
 bh_static_assert(offsetof(WASMExecEnv, argv_buf) == 3 * sizeof(uintptr_t));
 bh_static_assert(offsetof(WASMExecEnv, native_stack_boundary)
@@ -47,6 +48,11 @@ bh_static_assert(offsetof(AOTTableInstance, elems) == 8);
 
 bh_static_assert(offsetof(AOTModuleInstanceExtra, stack_sizes) == 0);
 
+bh_static_assert(offsetof(AOTFrame, ip_offset) == sizeof(uintptr_t) * 4);
+bh_static_assert(offsetof(AOTFrame, sp) == sizeof(uintptr_t) * 5);
+bh_static_assert(offsetof(AOTFrame, frame_ref) == sizeof(uintptr_t) * 6);
+bh_static_assert(offsetof(AOTFrame, lp) == sizeof(uintptr_t) * 7);
+
 static void
 set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
 {
@@ -2638,24 +2644,51 @@ get_func_name_from_index(const AOTModuleInstance *module_inst,
 bool
 aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
 {
-    AOTFrame *frame =
-        wasm_exec_env_alloc_wasm_frame(exec_env, sizeof(AOTFrame));
-#if WASM_ENABLE_PERF_PROFILING != 0
     AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
+    AOTModule *module = (AOTModule *)module_inst->module;
+#if WASM_ENABLE_PERF_PROFILING != 0
     AOTFuncPerfProfInfo *func_perf_prof =
         module_inst->func_perf_profilings + func_index;
 #endif
+    AOTFrame *frame;
+    uint32 max_local_cell_num, max_stack_cell_num, all_cell_num;
+    uint32 aot_func_idx, frame_size;
+
+    if (func_index >= module->import_func_count) {
+        aot_func_idx = 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[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
+    frame_size = (uint32)offsetof(AOTFrame, lp) + all_cell_num * 4;
+#else
+    frame_size =
+        (uint32)offsetof(AOTFrame, lp) + align_uint(all_cell_num * 5, 4);
+#endif
+    frame = wasm_exec_env_alloc_wasm_frame(exec_env, frame_size);
 
     if (!frame) {
         aot_set_exception((AOTModuleInstance *)exec_env->module_inst,
-                          "auxiliary call stack overflow");
+                          "wasm operand stack overflow");
         return false;
     }
 
 #if WASM_ENABLE_PERF_PROFILING != 0
-    frame->time_started = os_time_get_boot_microsecond();
+    frame->time_started = (uintptr_t)os_time_get_boot_microsecond();
     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 = frame->sp + max_stack_cell_num;
+#endif
 
     frame->prev_frame = (AOTFrame *)exec_env->cur_frame;
     exec_env->cur_frame = (struct WASMInterpFrame *)frame;
@@ -2672,7 +2705,7 @@ aot_free_frame(WASMExecEnv *exec_env)
 
 #if WASM_ENABLE_PERF_PROFILING != 0
     cur_frame->func_perf_prof_info->total_exec_time +=
-        os_time_get_boot_microsecond() - cur_frame->time_started;
+        (uintptr_t)os_time_get_boot_microsecond() - cur_frame->time_started;
     cur_frame->func_perf_prof_info->total_exec_cnt++;
 #endif
 

+ 33 - 4
core/iwasm/aot/aot_runtime.h

@@ -154,6 +154,12 @@ typedef struct AOTModule {
     void **func_ptrs;
     /* func type indexes of AOTed (un-imported) functions */
     uint32 *func_type_indexes;
+#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0
+    /* max local cell nums of AOTed (un-imported) functions */
+    uint32 *max_local_cell_nums;
+    /* max stack cell nums of AOTed (un-imported) functions */
+    uint32 *max_stack_cell_nums;
+#endif
 
     /* export info */
     uint32 export_count;
@@ -276,12 +282,35 @@ typedef struct AOTFuncPerfProfInfo {
 
 /* AOT auxiliary call stack */
 typedef struct AOTFrame {
+    /* The frame of the caller which is calling current function */
     struct AOTFrame *prev_frame;
-    uint32 func_index;
-#if WASM_ENABLE_PERF_PROFILING != 0
-    uint64 time_started;
+
+    /* The non-imported function index of current function */
+    uintptr_t func_index;
+
+    /* Used when performance profiling is enabled */
+    uintptr_t time_started;
+
+    /* Used when performance profiling is enabled */
     AOTFuncPerfProfInfo *func_perf_prof_info;
-#endif
+
+    /* Instruction pointer: offset to the bytecode array */
+    uintptr_t ip_offset;
+
+    /* Operand stack top pointer of the current frame */
+    uint32 *sp;
+
+    /* Frame ref flags (GC only) */
+    uint8 *frame_ref;
+
+    /**
+     * Frame data, the layout is:
+     *  local area: parameters and local variables
+     *  stack area: wasm operand stack
+     *  frame ref flags (GC only):
+     *      whether each cell in local and stack area is a GC obj
+     */
+    uint32 lp[1];
 } AOTFrame;
 
 #if WASM_ENABLE_STATIC_PGO != 0

+ 2 - 5
core/iwasm/common/wasm_exec_env.h

@@ -38,8 +38,8 @@ typedef struct WASMExecEnv {
     /* Next thread's exec env of a WASM module instance. */
     struct WASMExecEnv *next;
 
-    /* Previous thread's exec env of a WASM module instance. */
-    struct WASMExecEnv *prev;
+    /* Current interpreter/AOT frame of current thread */
+    struct WASMInterpFrame *cur_frame;
 
     /* Note: field module_inst, argv_buf, native_stack_boundary,
        suspend_flags, aux_stack_boundary, aux_stack_bottom, and
@@ -125,9 +125,6 @@ typedef struct WASMExecEnv {
 
     void *user_data;
 
-    /* Current interpreter frame of current thread */
-    struct WASMInterpFrame *cur_frame;
-
     /* The native thread handle of current thread */
     korp_tid handle;
 

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

@@ -355,6 +355,7 @@ aot_create_funcs(const WASMModule *module)
         funcs[i]->local_types = func->local_types;
         funcs[i]->param_cell_num = func->param_cell_num;
         funcs[i]->local_cell_num = func->local_cell_num;
+        funcs[i]->max_stack_cell_num = func->max_stack_cell_num;
         funcs[i]->code = func->code;
         funcs[i]->code_size = func->code_size;
     }

+ 1 - 0
core/iwasm/compilation/aot.h

@@ -213,6 +213,7 @@ typedef struct AOTFunc {
     uint8 *local_types;
     uint16 param_cell_num;
     uint16 local_cell_num;
+    uint32 max_stack_cell_num;
     uint32 code_size;
     uint8 *code;
 } AOTFunc;

+ 384 - 0
core/iwasm/compilation/aot_compiler.c

@@ -160,6 +160,384 @@ aot_validate_wasm(AOTCompContext *comp_ctx)
         OP_ATOMIC_##OP : bin_op = LLVMAtomicRMWBinOp##OP; \
         goto build_atomic_rmw;
 
+static bool
+store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type,
+            LLVMValueRef cur_frame, uint32 offset)
+{
+    LLVMValueRef value_offset, value_addr, value_ptr = NULL, res;
+    LLVMTypeRef value_ptr_type;
+
+    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 (value_type) {
+        case VALUE_TYPE_I32:
+            value_ptr_type = INT32_PTR_TYPE;
+            break;
+        case VALUE_TYPE_I64:
+            value_ptr_type = INT64_PTR_TYPE;
+            break;
+        case VALUE_TYPE_F32:
+            value_ptr_type = F32_PTR_TYPE;
+            break;
+        case VALUE_TYPE_F64:
+            value_ptr_type = F64_PTR_TYPE;
+            break;
+        case VALUE_TYPE_V128:
+            value_ptr_type = V128_PTR_TYPE;
+            break;
+        default:
+            bh_assert(0);
+            break;
+    }
+
+    if (!(value_ptr = LLVMBuildBitCast(comp_ctx->builder, value_addr,
+                                       value_ptr_type, "value_ptr"))) {
+        aot_set_last_error("llvm build bit cast failed");
+        return false;
+    }
+
+    if (!(res = LLVMBuildStore(comp_ctx->builder, value, value_ptr))) {
+        aot_set_last_error("llvm build store failed");
+        return false;
+    }
+
+    LLVMSetAlignment(res, 1);
+
+    return true;
+}
+
+bool
+aot_gen_commit_values(AOTCompFrame *frame)
+{
+    AOTCompContext *comp_ctx = frame->comp_ctx;
+    AOTFuncContext *func_ctx = frame->func_ctx;
+    AOTValueSlot *p;
+    LLVMValueRef value;
+    uint32 n;
+
+    for (p = frame->lp; p < frame->sp; p++) {
+        if (!p->dirty)
+            continue;
+
+        p->dirty = 0;
+        n = p - frame->lp;
+
+        switch (p->type) {
+            case VALUE_TYPE_I32:
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                if (!store_value(comp_ctx, p->value, VALUE_TYPE_I32,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_I64:
+                (++p)->dirty = 0;
+                if (!store_value(comp_ctx, p->value, VALUE_TYPE_I64,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_F32:
+                if (!store_value(comp_ctx, p->value, VALUE_TYPE_F32,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_F64:
+                (++p)->dirty = 0;
+                if (!store_value(comp_ctx, p->value, VALUE_TYPE_F64,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_V128:
+                (++p)->dirty = 0;
+                (++p)->dirty = 0;
+                (++p)->dirty = 0;
+                if (!store_value(comp_ctx, p->value, VALUE_TYPE_V128,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+            case VALUE_TYPE_I1:
+                if (!(value = LLVMBuildZExt(comp_ctx->builder, p->value,
+                                            I32_TYPE, "i32_val"))) {
+                    aot_set_last_error("llvm build bit cast failed");
+                    return false;
+                }
+                if (!store_value(comp_ctx, value, VALUE_TYPE_I32,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
+
+    return true;
+}
+
+bool
+aot_gen_commit_sp_ip(AOTCompFrame *frame, AOTValueSlot *sp, uint8 *ip)
+{
+    AOTCompContext *comp_ctx = frame->comp_ctx;
+    AOTFuncContext *func_ctx = frame->func_ctx;
+    LLVMValueRef cur_frame = func_ctx->cur_frame;
+    LLVMValueRef value_offset, value_addr, value_ptr, value;
+    LLVMTypeRef int8_ptr_ptr_type;
+    uint32 offset_ip, offset_sp, n;
+    bool is_64bit = (comp_ctx->pointer_size == sizeof(uint64)) ? true : false;
+
+    if (!comp_ctx->is_jit_mode) {
+        offset_ip = (uint32)sizeof(uintptr_t) * 4;
+        offset_sp = (uint32)sizeof(uintptr_t) * 5;
+    }
+    else {
+        offset_ip = offsetof(WASMInterpFrame, ip);
+        offset_sp = offsetof(WASMInterpFrame, sp);
+    }
+
+    /* commit ip */
+
+    if (!(value_offset = I32_CONST(offset_ip))) {
+        aot_set_last_error("llvm build const failed");
+        return false;
+    }
+
+    if (!(value_addr =
+              LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
+                                    &value_offset, 1, "ip_addr"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    if (!(value_ptr = LLVMBuildBitCast(
+              comp_ctx->builder, value_addr,
+              is_64bit ? INT64_PTR_TYPE : INT32_PTR_TYPE, "ip_ptr"))) {
+        aot_set_last_error("llvm build bit cast failed");
+        return false;
+    }
+
+    if (!comp_ctx->is_jit_mode) {
+        if (is_64bit)
+            value =
+                I64_CONST((uint64)(uintptr_t)(ip - func_ctx->aot_func->code));
+        else
+            value =
+                I32_CONST((uint32)(uintptr_t)(ip - func_ctx->aot_func->code));
+    }
+    else {
+        if (is_64bit)
+            value = I64_CONST((uint64)(uintptr_t)ip);
+        else
+            value = I32_CONST((uint32)(uintptr_t)ip);
+    }
+
+    if (!value) {
+        aot_set_last_error("llvm build const failed");
+        return false;
+    }
+
+    if (!LLVMBuildStore(comp_ctx->builder, value, value_ptr)) {
+        aot_set_last_error("llvm build store failed");
+        return false;
+    }
+
+    /* commit sp */
+
+    n = sp - frame->lp;
+    value = I32_CONST(offset_of_local(comp_ctx, n));
+    if (!value) {
+        aot_set_last_error("llvm build const failed");
+        return false;
+    }
+
+    if (!(value = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
+                                        &value, 1, "sp"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    if (!(value_offset = I32_CONST(offset_sp))) {
+        aot_set_last_error("llvm build const failed");
+        return false;
+    }
+
+    if (!(value_addr =
+              LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, cur_frame,
+                                    &value_offset, 1, "sp_addr"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    if (!(int8_ptr_ptr_type = LLVMPointerType(INT8_PTR_TYPE, 0))) {
+        aot_set_last_error("llvm build pointer type failed");
+        return false;
+    }
+
+    if (!(value_ptr = LLVMBuildBitCast(comp_ctx->builder, value_addr,
+                                       int8_ptr_ptr_type, "sp_ptr"))) {
+        aot_set_last_error("llvm build bit cast failed");
+        return false;
+    }
+
+    if (!LLVMBuildStore(comp_ctx->builder, value, value_ptr)) {
+        aot_set_last_error("llvm build store failed");
+        return false;
+    }
+
+    /* commit sp */
+    return true;
+}
+
+static bool
+init_comp_frame(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                uint32 func_idx)
+{
+    AOTCompFrame *aot_frame;
+    WASMModule *wasm_module = comp_ctx->comp_data->wasm_module;
+    AOTFunc *aot_func = func_ctx->aot_func;
+    AOTFuncType *func_type = aot_func->func_type;
+    AOTBlock *block = func_ctx->block_stack.block_list_end;
+    LLVMValueRef local_value;
+    uint32 max_local_cell_num =
+        aot_func->param_cell_num + aot_func->local_cell_num;
+    uint32 max_stack_cell_num = aot_func->max_stack_cell_num;
+    uint32 all_cell_num = max_local_cell_num + max_stack_cell_num;
+    uint32 i, n;
+    uint64 total_size;
+    uint8 local_type;
+
+    /* Free aot_frame if it was allocated previously for
+       compiling other functions */
+    if (comp_ctx->aot_frame) {
+        wasm_runtime_free(comp_ctx->aot_frame);
+        comp_ctx->aot_frame = NULL;
+    }
+
+    /* Allocate extra 2 cells since some operations may push more
+       operands than the number calculated in wasm loader, such as
+       PUSH_F64(F64_CONST(1.0)) in aot_compile_op_f64_promote_f32 */
+    all_cell_num += 2;
+    total_size = offsetof(AOTCompFrame, lp)
+                 + (uint64)sizeof(AOTValueSlot) * all_cell_num;
+
+    if (total_size > UINT32_MAX
+        || !(comp_ctx->aot_frame = aot_frame =
+                 wasm_runtime_malloc((uint32)total_size))) {
+        aot_set_last_error("allocate memory failed.");
+        return false;
+    }
+    memset(aot_frame, 0, (uint32)total_size);
+
+    aot_frame->cur_wasm_module = wasm_module;
+    aot_frame->cur_wasm_func = wasm_module->functions[func_idx];
+    aot_frame->cur_wasm_func_idx =
+        func_idx + wasm_module->import_function_count;
+    aot_frame->comp_ctx = comp_ctx;
+    aot_frame->func_ctx = func_ctx;
+
+    aot_frame->max_local_cell_num = max_local_cell_num;
+    aot_frame->max_stack_cell_num = max_stack_cell_num;
+
+    aot_frame->sp = aot_frame->lp + max_local_cell_num;
+
+    /* Init the frame_sp_begin of the function block */
+    block->frame_sp_begin = aot_frame->sp;
+
+    n = 0;
+
+    /* Set all params dirty since they were set to llvm value but
+       haven't been committed to the AOT/JIT stack frame */
+    for (i = 0; i < func_type->param_count; i++) {
+        local_type = func_type->types[i];
+        local_value = LLVMGetParam(func_ctx->func, i + 1);
+
+        switch (local_type) {
+            case VALUE_TYPE_I32:
+                set_local_i32(comp_ctx->aot_frame, n, local_value);
+                n++;
+                break;
+            case VALUE_TYPE_I64:
+                set_local_i64(comp_ctx->aot_frame, n, local_value);
+                n += 2;
+                break;
+            case VALUE_TYPE_F32:
+                set_local_f32(comp_ctx->aot_frame, n, local_value);
+                n++;
+                break;
+            case VALUE_TYPE_F64:
+                set_local_f64(comp_ctx->aot_frame, n, local_value);
+                n += 2;
+                break;
+            case VALUE_TYPE_V128:
+                set_local_v128(comp_ctx->aot_frame, n, local_value);
+                n += 4;
+                break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                set_local_ref(comp_ctx->aot_frame, n, local_value, local_type);
+                n++;
+                break;
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
+
+    /* 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++) {
+        local_type = aot_func->local_types[i];
+
+        switch (local_type) {
+            case VALUE_TYPE_I32:
+                set_local_i32(comp_ctx->aot_frame, n, I32_ZERO);
+                n++;
+                break;
+            case VALUE_TYPE_I64:
+                set_local_i64(comp_ctx->aot_frame, n, I64_ZERO);
+                n += 2;
+                break;
+            case VALUE_TYPE_F32:
+                set_local_f32(comp_ctx->aot_frame, n, F32_ZERO);
+                n++;
+                break;
+            case VALUE_TYPE_F64:
+                set_local_f64(comp_ctx->aot_frame, n, F64_ZERO);
+                n += 2;
+                break;
+            case VALUE_TYPE_V128:
+                set_local_v128(comp_ctx->aot_frame, n, V128_f64x2_ZERO);
+                n += 4;
+                break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                set_local_ref(comp_ctx->aot_frame, n, I32_ZERO, local_type);
+                n++;
+                break;
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
+
+    return true;
+}
+
 static bool
 aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 {
@@ -185,6 +563,12 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
     LLVMMetadataRef location;
 #endif
 
+    if (comp_ctx->enable_aux_stack_frame) {
+        if (!init_comp_frame(comp_ctx, func_ctx, func_index)) {
+            return false;
+        }
+    }
+
     /* Start to translate the opcodes */
     LLVMPositionBuilderAtEnd(
         comp_ctx->builder,

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

@@ -8,6 +8,7 @@
 
 #include "aot.h"
 #include "aot_llvm.h"
+#include "../interpreter/wasm_interp.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -106,6 +107,247 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
     return false;
 }
 
+/**
+ * Operations for AOTCompFrame
+ */
+
+/**
+ * Get the offset from frame pointer to the n-th local variable slot.
+ *
+ * @param n the index to the local variable array
+ *
+ * @return the offset from frame pointer to the local variable slot
+ */
+static inline uint32
+offset_of_local(AOTCompContext *comp_ctx, unsigned n)
+{
+    if (!comp_ctx->is_jit_mode)
+        return comp_ctx->pointer_size * 7 + sizeof(uint32) * n;
+    else
+        return offsetof(WASMInterpFrame, lp) + sizeof(uint32) * n;
+}
+
+/**
+ * Get the offset from frame pointer to the n-th local variable's
+ * reference flag slot.
+ *
+ * @param n the index to the local variable array
+ *
+ * @return the offset from frame pointer to the local variable slot
+ */
+static inline unsigned
+offset_of_ref(AOTCompContext *comp_ctx, unsigned n)
+{
+    AOTCompFrame *frame = comp_ctx->aot_frame;
+    uint32 all_cell_num = frame->max_local_cell_num + frame->max_stack_cell_num;
+    return offset_of_local(comp_ctx, all_cell_num) + n;
+}
+
+/**
+ * Generate instructions to commit computation result to the frame.
+ * The general principle is to only commit values that will be used
+ * through the frame.
+ *
+ * @param frame the frame information
+ */
+bool
+aot_gen_commit_values(AOTCompFrame *frame);
+
+/**
+ * Generate instructions to commit SP and IP pointers to the frame.
+ *
+ * @param frame the frame information
+ */
+bool
+aot_gen_commit_sp_ip(AOTCompFrame *frame, AOTValueSlot *sp, uint8 *ip);
+
+static inline void
+push_32bit(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    frame->sp->value = aot_value->value;
+    frame->sp->type = aot_value->type;
+    frame->sp->dirty = 1;
+    frame->sp++;
+}
+
+static inline void
+push_64bit(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    push_32bit(frame, aot_value);
+    push_32bit(frame, aot_value);
+}
+
+static inline void
+push_i32(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(aot_value->type == VALUE_TYPE_I32
+              || aot_value->type == VALUE_TYPE_I1);
+    push_32bit(frame, aot_value);
+}
+
+static inline void
+push_i64(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(aot_value->type == VALUE_TYPE_I64);
+    push_64bit(frame, aot_value);
+}
+
+static inline void
+push_f32(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(aot_value->type == VALUE_TYPE_F32);
+    push_32bit(frame, aot_value);
+}
+
+static inline void
+push_f64(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(aot_value->type == VALUE_TYPE_F64);
+    push_64bit(frame, aot_value);
+}
+
+static inline void
+push_v128(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(aot_value->type == VALUE_TYPE_V128);
+    push_64bit(frame, aot_value);
+    push_64bit(frame, aot_value);
+}
+
+static inline void
+push_ref(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(frame->comp_ctx->enable_ref_types);
+    push_32bit(frame, aot_value);
+}
+
+static inline void
+pop_i32(AOTCompFrame *frame)
+{
+    bh_assert(frame->sp - frame->lp >= 1);
+    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));
+}
+
+static inline void
+pop_i64(AOTCompFrame *frame)
+{
+    bh_assert(frame->sp - frame->lp >= 2);
+    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);
+}
+
+static inline void
+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));
+}
+
+static inline void
+pop_f64(AOTCompFrame *frame)
+{
+    bh_assert(frame->sp - frame->lp >= 2);
+    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);
+}
+
+static inline void
+pop_v128(AOTCompFrame *frame)
+{
+    bh_assert(frame->sp - frame->lp >= 4);
+    bh_assert((frame->sp - 1)->type == VALUE_TYPE_V128
+              && (frame->sp - 2)->type == VALUE_TYPE_V128
+              && (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);
+}
+
+static inline void
+pop_ref(AOTCompFrame *frame)
+{
+    bh_assert(frame->sp - frame->lp >= 1);
+    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);
+}
+
+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)
+{
+    frame->lp[n].value = value;
+    frame->lp[n].type = VALUE_TYPE_I32;
+    frame->lp[n].dirty = 1;
+}
+
+static inline void
+set_local_i64(AOTCompFrame *frame, int n, LLVMValueRef value)
+{
+    frame->lp[n].value = value;
+    frame->lp[n].type = VALUE_TYPE_I64;
+    frame->lp[n].dirty = 1;
+    frame->lp[n + 1].value = value;
+    frame->lp[n + 1].type = VALUE_TYPE_I64;
+    frame->lp[n + 1].dirty = 1;
+}
+
+static inline void
+set_local_f32(AOTCompFrame *frame, int n, LLVMValueRef value)
+{
+    frame->lp[n].value = value;
+    frame->lp[n].type = VALUE_TYPE_F32;
+    frame->lp[n].dirty = 1;
+}
+
+static inline void
+set_local_f64(AOTCompFrame *frame, int n, LLVMValueRef value)
+{
+    frame->lp[n].value = value;
+    frame->lp[n].type = VALUE_TYPE_F64;
+    frame->lp[n].dirty = 1;
+    frame->lp[n + 1].value = value;
+    frame->lp[n + 1].type = VALUE_TYPE_F64;
+    frame->lp[n + 1].dirty = 1;
+}
+
+static inline void
+set_local_v128(AOTCompFrame *frame, int n, LLVMValueRef value)
+{
+    uint32 i;
+    for (i = 0; i < 4; i++) {
+        frame->lp[n + i].value = value;
+        frame->lp[n + i].type = VALUE_TYPE_V128;
+        frame->lp[n + i].dirty = 1;
+    }
+}
+
+static inline void
+set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
+{
+    bh_assert(frame->comp_ctx->enable_ref_types);
+    frame->lp[n].value = value;
+    frame->lp[n].type = ref_type;
+    frame->lp[n].dirty = 1;
+}
+
 #define CHECK_STACK()                                          \
     do {                                                       \
         if (!func_ctx->block_stack.block_list_end) {           \
@@ -124,7 +366,7 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
         AOTValue *aot_value;                                                 \
         CHECK_STACK();                                                       \
         aot_value = aot_value_stack_pop(                                     \
-            &func_ctx->block_stack.block_list_end->value_stack);             \
+            comp_ctx, &func_ctx->block_stack.block_list_end->value_stack);   \
         if (!check_type_compatible(aot_value->type, value_type)) {           \
             aot_set_last_error("invalid WASM stack data type.");             \
             wasm_runtime_free(aot_value);                                    \
@@ -169,7 +411,7 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
         AOTValue *aot_value;                                                   \
         CHECK_STACK();                                                         \
         aot_value = aot_value_stack_pop(                                       \
-            &func_ctx->block_stack.block_list_end->value_stack);               \
+            comp_ctx, &func_ctx->block_stack.block_list_end->value_stack);     \
         if (aot_value->type != VALUE_TYPE_I1                                   \
             && aot_value->type != VALUE_TYPE_I32) {                            \
             aot_set_last_error("invalid WASM stack data type.");               \
@@ -190,23 +432,24 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
         wasm_runtime_free(aot_value);                                          \
     } while (0)
 
-#define PUSH(llvm_value, value_type)                                        \
-    do {                                                                    \
-        AOTValue *aot_value;                                                \
-        if (!func_ctx->block_stack.block_list_end) {                        \
-            aot_set_last_error("WASM block stack underflow.");              \
-            goto fail;                                                      \
-        }                                                                   \
-        aot_value = wasm_runtime_malloc(sizeof(AOTValue));                  \
-        if (!aot_value) {                                                   \
-            aot_set_last_error("allocate memory failed.");                  \
-            goto fail;                                                      \
-        }                                                                   \
-        memset(aot_value, 0, sizeof(AOTValue));                             \
-        aot_value->type = value_type;                                       \
-        aot_value->value = llvm_value;                                      \
-        aot_value_stack_push(                                               \
-            &func_ctx->block_stack.block_list_end->value_stack, aot_value); \
+#define PUSH(llvm_value, value_type)                                      \
+    do {                                                                  \
+        AOTValue *aot_value;                                              \
+        if (!func_ctx->block_stack.block_list_end) {                      \
+            aot_set_last_error("WASM block stack underflow.");            \
+            goto fail;                                                    \
+        }                                                                 \
+        aot_value = wasm_runtime_malloc(sizeof(AOTValue));                \
+        if (!aot_value) {                                                 \
+            aot_set_last_error("allocate memory failed.");                \
+            goto fail;                                                    \
+        }                                                                 \
+        memset(aot_value, 0, sizeof(AOTValue));                           \
+        aot_value->type = value_type;                                     \
+        aot_value->value = llvm_value;                                    \
+        aot_value_stack_push(                                             \
+            comp_ctx, &func_ctx->block_stack.block_list_end->value_stack, \
+            aot_value);                                                   \
     } while (0)
 
 #define PUSH_I32(v) PUSH(v, VALUE_TYPE_I32)

+ 17 - 1
core/iwasm/compilation/aot_emit_aot_file.c

@@ -582,14 +582,21 @@ get_text_section_size(AOTObjectData *obj_data)
 static uint32
 get_func_section_size(AOTCompData *comp_data, AOTObjectData *obj_data)
 {
-    /* text offsets + function type indexs */
     uint32 size = 0;
 
+    /* text offsets */
     if (is_32bit_binary(obj_data))
         size = (uint32)sizeof(uint32) * comp_data->func_count;
     else
         size = (uint32)sizeof(uint64) * comp_data->func_count;
 
+    /* function type indexes */
+    size += (uint32)sizeof(uint32) * comp_data->func_count;
+
+    /* max_local_cell_nums */
+    size += (uint32)sizeof(uint32) * comp_data->func_count;
+
+    /* max_stack_cell_nums */
     size += (uint32)sizeof(uint32) * comp_data->func_count;
     return size;
 }
@@ -1890,6 +1897,15 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
     for (i = 0; i < comp_data->func_count; i++)
         EMIT_U32(funcs[i]->func_type_index);
 
+    for (i = 0; i < comp_data->func_count; i++) {
+        uint32 max_local_cell_num =
+            funcs[i]->param_cell_num + funcs[i]->local_cell_num;
+        EMIT_U32(max_local_cell_num);
+    }
+
+    for (i = 0; i < comp_data->func_count; i++)
+        EMIT_U32(funcs[i]->max_stack_cell_num);
+
     if (offset - *p_offset != section_size + sizeof(uint32) * 2) {
         aot_set_last_error("emit function section failed.");
         return false;

+ 158 - 28
core/iwasm/compilation/aot_emit_control.c

@@ -154,12 +154,38 @@ get_target_block(AOTFuncContext *func_ctx, uint32 br_depth)
     return block;
 }
 
+static void
+clear_frame_locals(AOTCompFrame *aot_frame)
+{
+    uint32 i;
+
+    for (i = 0; i < aot_frame->max_local_cell_num; i++) {
+        aot_frame->lp[i].dirty = 0;
+        aot_frame->lp[i].value = NULL;
+    }
+}
+
+static void
+restore_frame_sp(AOTBlock *block, AOTCompFrame *aot_frame)
+{
+    uint32 stack_cell_num;
+
+    bh_assert(aot_frame->sp >= block->frame_sp_begin);
+
+    stack_cell_num = aot_frame->sp - block->frame_sp_begin;
+    if (stack_cell_num > 0) {
+        memset(block->frame_sp_begin, 0, sizeof(AOTValueSlot) * stack_cell_num);
+    }
+    aot_frame->sp = block->frame_sp_begin;
+}
+
 static bool
 handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                             uint8 **p_frame_ip)
 {
     AOTBlock *block = func_ctx->block_stack.block_list_end;
     AOTBlock *block_prev;
+    AOTCompFrame *aot_frame = comp_ctx->aot_frame;
     uint8 *frame_ip = NULL;
     uint32 i;
     AOTFuncType *func_type;
@@ -176,10 +202,22 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         comp_ctx, func_ctx,
         (*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code);
 #endif
+
+    if (aot_frame) {
+        /* Clear frame local variables since they have been committed */
+        clear_frame_locals(aot_frame);
+    }
+
     if (block->label_type == LABEL_TYPE_IF && block->llvm_else_block
         && *p_frame_ip <= block->wasm_code_else) {
         /* Clear value stack and start to translate else branch */
-        aot_value_stack_destroy(&block->value_stack);
+        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]);
@@ -192,11 +230,16 @@ 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(&block->value_stack);
+                aot_value_stack_destroy(comp_ctx, &block->value_stack);
                 SET_BUILDER_POS(block->llvm_else_block);
                 *p_frame_ip = block->wasm_code_else + 1;
                 /* Push back the block */
@@ -211,7 +254,7 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
 
         frame_ip = block->wasm_code_end;
-        aot_block_destroy(block);
+        aot_block_destroy(comp_ctx, block);
         block = block_prev;
     }
 
@@ -225,6 +268,12 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     /* Pop block, push its return value, and destroy the block */
     block = aot_block_stack_pop(&func_ctx->block_stack);
+
+    if (aot_frame) {
+        /* Restore the frame sp */
+        restore_frame_sp(block, aot_frame);
+    }
+
     func_type = func_ctx->aot_func->func_type;
     for (i = 0; i < block->result_count; i++) {
         bh_assert(block->result_phis[i]);
@@ -266,7 +315,7 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 #endif
         }
     }
-    aot_block_destroy(block);
+    aot_block_destroy(comp_ctx, block);
     return true;
 fail:
     return false;
@@ -353,6 +402,9 @@ push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx,
 
     /* Push the new block to block stack */
     aot_block_stack_push(&func_ctx->block_stack, block);
+    if (comp_ctx->aot_frame) {
+        block->frame_sp_begin = comp_ctx->aot_frame->sp;
+    }
 
     /* Push param phis to the new block */
     for (i = 0; i < block->param_count; i++) {
@@ -435,6 +487,13 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     block->block_index = func_ctx->block_stack.block_index[label_type];
     func_ctx->block_stack.block_index[label_type]++;
 
+    if (comp_ctx->aot_frame) {
+        if (label_type != LABEL_TYPE_BLOCK
+            && !aot_gen_commit_values(comp_ctx->aot_frame)) {
+            goto fail;
+        }
+    }
+
     if (label_type == LABEL_TYPE_BLOCK || label_type == LABEL_TYPE_LOOP) {
         /* Create block */
         format_block_name(name, sizeof(name), block->block_index, label_type,
@@ -462,7 +521,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                                      false, NULL, NULL))) {
                 goto fail;
             }
-            aot_block_destroy(block);
+            aot_block_destroy(comp_ctx, block);
             return aot_handle_next_reachable_block(comp_ctx, func_ctx,
                                                    p_frame_ip);
         }
@@ -542,7 +601,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                 }
                 else {
                     /* skip the block */
-                    aot_block_destroy(block);
+                    aot_block_destroy(comp_ctx, block);
                     *p_frame_ip = end_addr + 1;
                 }
             }
@@ -555,7 +614,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     return true;
 fail:
-    aot_block_destroy(block);
+    aot_block_destroy(comp_ctx, block);
     return false;
 }
 
@@ -565,6 +624,7 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     AOTBlock *block = func_ctx->block_stack.block_list_end;
     LLVMValueRef value;
+    AOTCompFrame *aot_frame = comp_ctx->aot_frame;
     char name[32];
     uint32 i, result_index;
 
@@ -600,14 +660,27 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         ADD_TO_RESULT_PHIS(block, value, result_index);
     }
 
+    if (aot_frame) {
+        bh_assert(block->frame_sp_begin == aot_frame->sp);
+        aot_gen_commit_values(aot_frame);
+    }
+
     /* Jump to end block */
     BUILD_BR(block->llvm_end_block);
 
     if (!block->skip_wasm_code_else && block->llvm_else_block) {
         /* Clear value stack, recover param values
-         * and start to translate else branch.
-         */
-        aot_value_stack_destroy(&block->value_stack);
+           and start to translate else branch. */
+        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;
+            }
+        }
+
         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);
@@ -647,6 +720,13 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             MOVE_BLOCK_BEFORE(block->llvm_end_block, next_llvm_end_block);
     }
 
+    if (comp_ctx->aot_frame) {
+        if (block->label_type != LABEL_TYPE_FUNCTION
+            && !aot_gen_commit_values(comp_ctx->aot_frame)) {
+            return false;
+        }
+    }
+
     /* Handle block result values */
     CREATE_RESULT_VALUE_PHIS(block);
     for (i = 0; i < block->result_count; i++) {
@@ -657,6 +737,10 @@ aot_compile_op_end(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         ADD_TO_RESULT_PHIS(block, value, result_index);
     }
 
+    if (comp_ctx->aot_frame) {
+        restore_frame_sp(block, comp_ctx->aot_frame);
+    }
+
     /* Jump to the end block */
     BUILD_BR(block->llvm_end_block);
 
@@ -668,7 +752,8 @@ fail:
 
 #if WASM_ENABLE_THREAD_MGR != 0
 bool
-check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
+check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                    bool check_terminate_and_suspend)
 {
     LLVMValueRef terminate_addr, terminate_flags, flag, offset, res;
     LLVMBasicBlockRef terminate_block, non_terminate_block;
@@ -748,17 +833,28 @@ aot_compile_op_br(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     char name[32];
     uint32 i, param_index, result_index;
 
-#if WASM_ENABLE_THREAD_MGR != 0
-    /* Insert suspend check point */
-    if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx))
+    if (!(block_dst = get_target_block(func_ctx, br_depth))) {
+        return false;
+    }
+
+    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))
+                return false;
+        }
     }
-#endif
 
-    if (!(block_dst = get_target_block(func_ctx, br_depth))) {
-        return false;
+#if WASM_ENABLE_THREAD_MGR != 0
+    /* Terminate or suspend current thread only when this is a backward jump */
+    if (comp_ctx->enable_thread_mgr
+        && block_dst->label_type == LABEL_TYPE_LOOP) {
+        if (!check_suspend_flags(comp_ctx, func_ctx, true))
+            return false;
     }
+#endif
 
     if (block_dst->label_type == LABEL_TYPE_LOOP) {
         /* Dest block is Loop block */
@@ -811,13 +907,19 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     uint32 i, param_index, result_index;
     uint64 size;
 
-#if WASM_ENABLE_THREAD_MGR != 0
-    /* Insert suspend check point */
-    if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx))
+    if (!(block_dst = get_target_block(func_ctx, br_depth))) {
+        return false;
+    }
+
+    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))
+                return false;
+        }
     }
-#endif
 
     POP_COND(value_cmp);
 
@@ -839,6 +941,16 @@ aot_compile_op_br_if(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             return false;
         }
 
+#if WASM_ENABLE_THREAD_MGR != 0
+        /* Terminate or suspend current thread only when this is
+           a backward jump */
+        if (comp_ctx->enable_thread_mgr
+            && block_dst->label_type == LABEL_TYPE_LOOP) {
+            if (!check_suspend_flags(comp_ctx, func_ctx, true))
+                return false;
+        }
+#endif
+
         /* Create llvm else block */
         CREATE_BLOCK(llvm_else_block, "br_if_else");
         MOVE_BLOCK_AFTER_CURR(llvm_else_block);
@@ -948,13 +1060,13 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     uint64 size;
     char name[32];
 
-#if WASM_ENABLE_THREAD_MGR != 0
-    /* Insert suspend check point */
-    if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, 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))
             return false;
     }
-#endif
 
     POP_I32(value_cmp);
 
@@ -971,6 +1083,23 @@ aot_compile_op_br_table(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     if (!LLVMIsConstant(value_cmp)) {
+#if WASM_ENABLE_THREAD_MGR != 0
+        if (comp_ctx->enable_thread_mgr) {
+            for (i = 0; i <= br_count; i++) {
+                target_block = get_target_block(func_ctx, br_depths[i]);
+                if (!target_block)
+                    return false;
+                /* Terminate or suspend current thread only when this is a
+                   backward jump */
+                if (target_block->label_type == LABEL_TYPE_LOOP) {
+                    if (!check_suspend_flags(comp_ctx, func_ctx, true))
+                        return false;
+                    break;
+                }
+            }
+        }
+#endif
+
         /* Compare value is not constant, create switch IR */
         for (i = 0; i <= br_count; i++) {
             target_block = get_target_block(func_ctx, br_depths[i]);
@@ -1099,6 +1228,7 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         comp_ctx, func_ctx,
         (*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code);
 #endif
+
     if (block_func->result_count) {
         /* Store extra result values to function parameters */
         for (i = 0; i < block_func->result_count - 1; i++) {

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

@@ -52,7 +52,8 @@ aot_handle_next_reachable_block(AOTCompContext *comp_ctx,
 
 #if WASM_ENABLE_THREAD_MGR != 0
 bool
-check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
+check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                    bool check_terminate_and_suspend);
 #endif
 
 #ifdef __cplusplus

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

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

+ 12 - 4
core/iwasm/compilation/aot_emit_function.c

@@ -531,10 +531,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     bool ret = false;
     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))
+        if (!check_suspend_flags(comp_ctx, func_ctx, true))
             return false;
     }
 #endif
@@ -892,7 +896,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 #if WASM_ENABLE_THREAD_MGR != 0
     /* Insert suspend check point */
     if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx))
+        if (!check_suspend_flags(comp_ctx, func_ctx, false))
             goto fail;
     }
 #endif
@@ -1088,6 +1092,10 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     char buf[32];
     bool ret = false;
 
+    if (comp_ctx->aot_frame && !aot_gen_commit_values(comp_ctx->aot_frame)) {
+        return false;
+    }
+
     /* Check function type index */
     if (type_idx >= comp_ctx->comp_data->func_type_count) {
         aot_set_last_error("function type index out of range");
@@ -1344,7 +1352,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 #if WASM_ENABLE_THREAD_MGR != 0
     /* Insert suspend check point */
     if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx))
+        if (!check_suspend_flags(comp_ctx, func_ctx, true))
             goto fail;
     }
 #endif
@@ -1541,7 +1549,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 #if WASM_ENABLE_THREAD_MGR != 0
     /* Insert suspend check point */
     if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx))
+        if (!check_suspend_flags(comp_ctx, func_ctx, false))
             goto fail;
     }
 #endif

+ 1 - 1
core/iwasm/compilation/aot_emit_memory.c

@@ -1508,7 +1508,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 #if WASM_ENABLE_THREAD_MGR != 0
     /* Insert suspend check point */
     if (comp_ctx->enable_thread_mgr) {
-        if (!check_suspend_flags(comp_ctx, func_ctx))
+        if (!check_suspend_flags(comp_ctx, func_ctx, false))
             return false;
     }
 #endif

+ 2 - 2
core/iwasm/compilation/aot_emit_parametric.c

@@ -21,8 +21,8 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         return false;
     }
 
-    aot_value =
-        aot_value_stack_pop(&func_ctx->block_stack.block_list_end->value_stack);
+    aot_value = aot_value_stack_pop(
+        comp_ctx, &func_ctx->block_stack.block_list_end->value_stack);
     type = aot_value->type;
 
     if (aot_value->type == VALUE_TYPE_I1) {

+ 36 - 1
core/iwasm/compilation/aot_emit_variable.c

@@ -63,10 +63,45 @@ aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                          uint32 local_idx)
 {
     LLVMValueRef value;
+    uint8 local_type;
+    uint32 n;
 
     CHECK_LOCAL(local_idx);
 
-    POP(value, get_local_type(func_ctx, local_idx));
+    local_type = get_local_type(func_ctx, local_idx);
+
+    POP(value, local_type);
+
+    if (comp_ctx->aot_frame) {
+        /* Get the slot index */
+        n = comp_ctx->aot_frame->cur_wasm_func->local_offsets[local_idx];
+        bh_assert(comp_ctx->aot_frame->lp[n].type == local_type);
+
+        switch (local_type) {
+            case VALUE_TYPE_I32:
+                set_local_i32(comp_ctx->aot_frame, n, value);
+                break;
+            case VALUE_TYPE_I64:
+                set_local_i64(comp_ctx->aot_frame, n, value);
+                break;
+            case VALUE_TYPE_F32:
+                set_local_f32(comp_ctx->aot_frame, n, value);
+                break;
+            case VALUE_TYPE_F64:
+                set_local_f64(comp_ctx->aot_frame, n, value);
+                break;
+            case VALUE_TYPE_V128:
+                set_local_v128(comp_ctx->aot_frame, n, value);
+                break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                set_local_ref(comp_ctx->aot_frame, n, value, local_type);
+                break;
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
 
     if (!LLVMBuildStore(comp_ctx->builder, value,
                         func_ctx->locals[local_idx])) {

+ 106 - 13
core/iwasm/compilation/aot_llvm.c

@@ -902,6 +902,27 @@ create_aux_stack_info(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
     return true;
 }
 
+static bool
+create_aux_stack_frame(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
+{
+    LLVMValueRef offset = I32_ONE, cur_frame_addr;
+
+    if (!(cur_frame_addr = LLVMBuildInBoundsGEP2(
+              comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1,
+              "cur_frame_addr"))) {
+        aot_set_last_error("llvm build in bounds gep failed");
+        return false;
+    }
+
+    if (!(func_ctx->cur_frame = LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE,
+                                               cur_frame_addr, "cur_frame"))) {
+        aot_set_last_error("llvm build load failed");
+        return false;
+    }
+
+    return true;
+}
+
 static bool
 create_native_symbol(const AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
@@ -1578,6 +1599,11 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
         goto fail;
     }
 
+    if (comp_ctx->enable_aux_stack_frame
+        && !create_aux_stack_frame(comp_ctx, func_ctx)) {
+        goto fail;
+    }
+
     /* Create local variables */
     if (!create_local_variables(comp_data, comp_ctx, func_ctx, func)) {
         goto fail;
@@ -1615,13 +1641,14 @@ aot_create_func_context(const AOTCompData *comp_data, AOTCompContext *comp_ctx,
 fail:
     if (func_ctx->mem_info)
         wasm_runtime_free(func_ctx->mem_info);
-    aot_block_stack_destroy(&func_ctx->block_stack);
+    aot_block_stack_destroy(comp_ctx, &func_ctx->block_stack);
     wasm_runtime_free(func_ctx);
     return NULL;
 }
 
 static void
-aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count)
+aot_destroy_func_contexts(AOTCompContext *comp_ctx, AOTFuncContext **func_ctxes,
+                          uint32 count)
 {
     uint32 i;
 
@@ -1629,7 +1656,7 @@ aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count)
         if (func_ctxes[i]) {
             if (func_ctxes[i]->mem_info)
                 wasm_runtime_free(func_ctxes[i]->mem_info);
-            aot_block_stack_destroy(&func_ctxes[i]->block_stack);
+            aot_block_stack_destroy(comp_ctx, &func_ctxes[i]->block_stack);
             aot_checked_addr_list_destroy(func_ctxes[i]);
             wasm_runtime_free(func_ctxes[i]);
         }
@@ -1666,7 +1693,8 @@ aot_create_func_contexts(const AOTCompData *comp_data, AOTCompContext *comp_ctx)
         AOTFunc *func = comp_data->funcs[i];
         if (!(func_ctxes[i] =
                   aot_create_func_context(comp_data, comp_ctx, func, i))) {
-            aot_destroy_func_contexts(func_ctxes, comp_data->func_count);
+            aot_destroy_func_contexts(comp_ctx, func_ctxes,
+                                      comp_data->func_count);
             return NULL;
         }
     }
@@ -2923,7 +2951,7 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
         LLVMOrcDisposeLLLazyJIT(comp_ctx->orc_jit);
 
     if (comp_ctx->func_ctxes)
-        aot_destroy_func_contexts(comp_ctx->func_ctxes,
+        aot_destroy_func_contexts(comp_ctx, comp_ctx->func_ctxes,
                                   comp_ctx->func_ctx_count);
 
     if (bh_list_length(&comp_ctx->native_symbols) > 0) {
@@ -2940,6 +2968,10 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx)
         wasm_runtime_free(comp_ctx->target_cpu);
     }
 
+    if (comp_ctx->aot_frame) {
+        wasm_runtime_free(comp_ctx->aot_frame);
+    }
+
     wasm_runtime_free(comp_ctx);
 }
 
@@ -3018,7 +3050,8 @@ aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol)
 }
 
 void
-aot_value_stack_push(AOTValueStack *stack, AOTValue *value)
+aot_value_stack_push(const AOTCompContext *comp_ctx, AOTValueStack *stack,
+                     AOTValue *value)
 {
     if (!stack->value_list_head)
         stack->value_list_head = stack->value_list_end = value;
@@ -3027,10 +3060,38 @@ aot_value_stack_push(AOTValueStack *stack, AOTValue *value)
         value->prev = stack->value_list_end;
         stack->value_list_end = value;
     }
+
+    if (comp_ctx->aot_frame) {
+        switch (value->type) {
+            case VALUE_TYPE_I32:
+            case VALUE_TYPE_I1:
+                push_i32(comp_ctx->aot_frame, value);
+                break;
+            case VALUE_TYPE_I64:
+                push_i64(comp_ctx->aot_frame, value);
+                break;
+            case VALUE_TYPE_F32:
+                push_f32(comp_ctx->aot_frame, value);
+                break;
+            case VALUE_TYPE_F64:
+                push_f64(comp_ctx->aot_frame, value);
+                break;
+            case VALUE_TYPE_V128:
+                push_v128(comp_ctx->aot_frame, value);
+                break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                push_ref(comp_ctx->aot_frame, value);
+                break;
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
 }
 
 AOTValue *
-aot_value_stack_pop(AOTValueStack *stack)
+aot_value_stack_pop(const AOTCompContext *comp_ctx, AOTValueStack *stack)
 {
     AOTValue *value = stack->value_list_end;
 
@@ -3044,11 +3105,43 @@ aot_value_stack_pop(AOTValueStack *stack)
         value->prev = NULL;
     }
 
+    if (comp_ctx->aot_frame) {
+        bh_assert(value);
+        bh_assert(value->value == (comp_ctx->aot_frame->sp - 1)->value);
+        bh_assert(value->type == (comp_ctx->aot_frame->sp - 1)->type);
+
+        switch (value->type) {
+            case VALUE_TYPE_I32:
+            case VALUE_TYPE_I1:
+                pop_i32(comp_ctx->aot_frame);
+                break;
+            case VALUE_TYPE_I64:
+                pop_i64(comp_ctx->aot_frame);
+                break;
+            case VALUE_TYPE_F32:
+                pop_f32(comp_ctx->aot_frame);
+                break;
+            case VALUE_TYPE_F64:
+                pop_f64(comp_ctx->aot_frame);
+                break;
+            case VALUE_TYPE_V128:
+                pop_v128(comp_ctx->aot_frame);
+                break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                pop_ref(comp_ctx->aot_frame);
+                break;
+            default:
+                bh_assert(0);
+                break;
+        }
+    }
+
     return value;
 }
 
 void
-aot_value_stack_destroy(AOTValueStack *stack)
+aot_value_stack_destroy(AOTCompContext *comp_ctx, AOTValueStack *stack)
 {
     AOTValue *value = stack->value_list_head, *p;
 
@@ -3093,14 +3186,14 @@ aot_block_stack_pop(AOTBlockStack *stack)
 }
 
 void
-aot_block_stack_destroy(AOTBlockStack *stack)
+aot_block_stack_destroy(AOTCompContext *comp_ctx, AOTBlockStack *stack)
 {
     AOTBlock *block = stack->block_list_head, *p;
 
     while (block) {
         p = block->next;
-        aot_value_stack_destroy(&block->value_stack);
-        aot_block_destroy(block);
+        aot_value_stack_destroy(comp_ctx, &block->value_stack);
+        aot_block_destroy(comp_ctx, block);
         block = p;
     }
 
@@ -3109,9 +3202,9 @@ aot_block_stack_destroy(AOTBlockStack *stack)
 }
 
 void
-aot_block_destroy(AOTBlock *block)
+aot_block_destroy(AOTCompContext *comp_ctx, AOTBlock *block)
 {
-    aot_value_stack_destroy(&block->value_stack);
+    aot_value_stack_destroy(comp_ctx, &block->value_stack);
     if (block->param_types)
         wasm_runtime_free(block->param_types);
     if (block->param_phis)

+ 64 - 6
core/iwasm/compilation/aot_llvm.h

@@ -60,6 +60,8 @@ extern "C" {
 #undef DUMP_MODULE
 #endif
 
+struct AOTValueSlot;
+
 /**
  * Value in the WASM operation stack, each stack element
  * is an LLVM value
@@ -82,6 +84,54 @@ typedef struct AOTValueStack {
     AOTValue *value_list_end;
 } AOTValueStack;
 
+/* Record information of a value slot of local variable or stack
+   during translation */
+typedef struct AOTValueSlot {
+    /* The LLVM value of this slot */
+    LLVMValueRef value;
+
+    /* The value type of this slot */
+    uint8 type;
+
+    /* The dirty bit of the value slot. It's set if the value in
+       register is newer than the value in memory. */
+    uint32 dirty : 1;
+
+    /* Whether the new value in register is a reference, which is valid
+       only when the dirty bit is set. */
+    uint32 ref : 1;
+
+    /* Committed reference flag:
+         0: unknown, 1: not-reference, 2: reference */
+    uint32 committed_ref : 2;
+} AOTValueSlot;
+
+/* Frame information for translation */
+typedef struct AOTCompFrame {
+    /* The current wasm module */
+    WASMModule *cur_wasm_module;
+    /* The current wasm function */
+    WASMFunction *cur_wasm_func;
+    /* The current wasm function index */
+    uint32 cur_wasm_func_idx;
+    /* The current compilation context */
+    struct AOTCompContext *comp_ctx;
+    /* The current function context */
+    struct AOTFuncContext *func_ctx;
+
+    /* Max local slot number */
+    uint32 max_local_cell_num;
+
+    /* Max operand stack slot number */
+    uint32 max_stack_cell_num;
+
+    /* Stack top pointer */
+    AOTValueSlot *sp;
+
+    /* Local variables + stack operands */
+    AOTValueSlot lp[1];
+} AOTCompFrame;
+
 typedef struct AOTBlock {
     struct AOTBlock *next;
     struct AOTBlock *prev;
@@ -120,6 +170,9 @@ typedef struct AOTBlock {
     uint32 result_count;
     uint8 *result_types;
     LLVMValueRef *result_phis;
+
+    /* The begin frame stack pointer of this block */
+    AOTValueSlot *frame_sp_begin;
 } AOTBlock;
 
 /**
@@ -172,6 +225,8 @@ typedef struct AOTFuncContext {
 
     LLVMValueRef cur_exception;
 
+    LLVMValueRef cur_frame;
+
     bool mem_space_unchanged;
     AOTCheckedAddrList checked_addr_list;
 
@@ -395,7 +450,6 @@ typedef struct AOTCompContext {
     AOTLLVMConsts llvm_consts;
 
     /* Function contexts */
-    /* TODO: */
     AOTFuncContext **func_ctxes;
     uint32 func_ctx_count;
     char **custom_sections_wp;
@@ -419,6 +473,9 @@ typedef struct AOTCompContext {
     char stack_usage_temp_file[64];
     const char *llvm_passes;
     const char *builtin_intrinsics;
+
+    /* Current frame information for translation */
+    AOTCompFrame *aot_frame;
 } AOTCompContext;
 
 enum {
@@ -486,13 +543,14 @@ void
 aot_destroy_elf_file(uint8 *elf_file);
 
 void
-aot_value_stack_push(AOTValueStack *stack, AOTValue *value);
+aot_value_stack_push(const AOTCompContext *comp_ctx, AOTValueStack *stack,
+                     AOTValue *value);
 
 AOTValue *
-aot_value_stack_pop(AOTValueStack *stack);
+aot_value_stack_pop(const AOTCompContext *comp_ctx, AOTValueStack *stack);
 
 void
-aot_value_stack_destroy(AOTValueStack *stack);
+aot_value_stack_destroy(AOTCompContext *comp_ctx, AOTValueStack *stack);
 
 void
 aot_block_stack_push(AOTBlockStack *stack, AOTBlock *block);
@@ -501,10 +559,10 @@ AOTBlock *
 aot_block_stack_pop(AOTBlockStack *stack);
 
 void
-aot_block_stack_destroy(AOTBlockStack *stack);
+aot_block_stack_destroy(AOTCompContext *comp_ctx, AOTBlockStack *stack);
 
 void
-aot_block_destroy(AOTBlock *block);
+aot_block_destroy(AOTCompContext *comp_ctx, AOTBlock *block);
 
 LLVMTypeRef
 wasm_type_to_llvm_type(const AOTLLVMTypes *llvm_types, uint8 wasm_type);

+ 0 - 74
core/iwasm/fast-jit/jit_frontend.c

@@ -2311,77 +2311,3 @@ jit_frontend_get_jitted_return_addr_offset()
 {
     return (uint32)offsetof(WASMInterpFrame, jitted_return_addr);
 }
-
-#if 0
-#if WASM_ENABLE_THREAD_MGR != 0
-bool
-check_suspend_flags(JitCompContext *cc, JITFuncContext *func_ctx)
-{
-    LLVMValueRef terminate_addr, terminate_flags, flag, offset, res;
-    JitBasicBlock *terminate_check_block, non_terminate_block;
-    JITFuncType *jit_func_type = func_ctx->jit_func->func_type;
-    JitBasicBlock *terminate_block;
-
-    /* Offset of suspend_flags */
-    offset = I32_FIVE;
-
-    if (!(terminate_addr = LLVMBuildInBoundsGEP(
-              cc->builder, func_ctx->exec_env, &offset, 1, "terminate_addr"))) {
-        jit_set_last_error("llvm build in bounds gep failed");
-        return false;
-    }
-    if (!(terminate_addr =
-              LLVMBuildBitCast(cc->builder, terminate_addr, INT32_PTR_TYPE,
-                               "terminate_addr_ptr"))) {
-        jit_set_last_error("llvm build bit cast failed");
-        return false;
-    }
-
-    if (!(terminate_flags =
-              LLVMBuildLoad(cc->builder, terminate_addr, "terminate_flags"))) {
-        jit_set_last_error("llvm build bit cast failed");
-        return false;
-    }
-    /* Set terminate_flags memory accecc to volatile, so that the value
-        will always be loaded from memory rather than register */
-    LLVMSetVolatile(terminate_flags, true);
-
-    CREATE_BASIC_BLOCK(terminate_check_block, "terminate_check");
-    MOVE_BASIC_BLOCK_AFTER_CURR(terminate_check_block);
-
-    CREATE_BASIC_BLOCK(non_terminate_block, "non_terminate");
-    MOVE_BASIC_BLOCK_AFTER_CURR(non_terminate_block);
-
-    BUILD_ICMP(LLVMIntSGT, terminate_flags, I32_ZERO, res, "need_terminate");
-    BUILD_COND_BR(res, terminate_check_block, non_terminate_block);
-
-    /* Move builder to terminate check block */
-    SET_BUILDER_POS(terminate_check_block);
-
-    CREATE_BASIC_BLOCK(terminate_block, "terminate");
-    MOVE_BASIC_BLOCK_AFTER_CURR(terminate_block);
-
-    if (!(flag = LLVMBuildAnd(cc->builder, terminate_flags, I32_ONE,
-                              "termination_flag"))) {
-        jit_set_last_error("llvm build AND failed");
-        return false;
-    }
-
-    BUILD_ICMP(LLVMIntSGT, flag, I32_ZERO, res, "need_terminate");
-    BUILD_COND_BR(res, terminate_block, non_terminate_block);
-
-    /* Move builder to terminate block */
-    SET_BUILDER_POS(terminate_block);
-    if (!jit_build_zero_function_ret(cc, func_ctx, jit_func_type)) {
-        goto fail;
-    }
-
-    /* Move builder to terminate block */
-    SET_BUILDER_POS(non_terminate_block);
-    return true;
-
-fail:
-    return false;
-}
-#endif /* End of WASM_ENABLE_THREAD_MGR */
-#endif

+ 24 - 3
core/iwasm/interpreter/wasm_runtime.c

@@ -3380,13 +3380,34 @@ bool
 llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
 {
     WASMModuleInstance *module_inst;
+    WASMModule *module;
     WASMInterpFrame *frame;
-    uint32 size;
+    uint32 size, max_local_cell_num, max_stack_cell_num;
 
     bh_assert(exec_env->module_inst->module_type == Wasm_Module_Bytecode);
 
     module_inst = (WASMModuleInstance *)exec_env->module_inst;
-    size = wasm_interp_interp_frame_size(0);
+    module = module_inst->module;
+
+    if (func_index >= func_index - module->import_function_count) {
+        WASMFunction *func =
+            module->functions[func_index - module->import_function_count];
+
+        max_local_cell_num = func->param_cell_num + func->local_cell_num;
+        max_stack_cell_num = func->max_stack_cell_num;
+    }
+    else {
+        WASMFunctionImport *func =
+            &((module->import_functions + func_index)->u.function);
+
+        max_local_cell_num = func->func_type->param_cell_num > 2
+                                 ? func->func_type->param_cell_num
+                                 : 2;
+        max_stack_cell_num = 0;
+    }
+
+    size =
+        wasm_interp_interp_frame_size(max_local_cell_num + max_stack_cell_num);
 
     frame = wasm_exec_env_alloc_wasm_frame(exec_env, size);
     if (!frame) {
@@ -3396,7 +3417,7 @@ llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
 
     frame->function = module_inst->e->functions + func_index;
     frame->ip = NULL;
-    frame->sp = frame->lp;
+    frame->sp = frame->lp + max_local_cell_num;
 #if WASM_ENABLE_PERF_PROFILING != 0
     frame->time_started = os_time_get_boot_microsecond();
 #endif

+ 0 - 1
product-mini/platforms/linux/CMakeLists.txt

@@ -91,7 +91,6 @@ if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS)
   set (WAMR_BUILD_LIB_WASI_THREADS 0)
 endif()
 
-
 if (NOT DEFINED WAMR_BUILD_MINI_LOADER)
   # Disable wasm mini loader by default
   set (WAMR_BUILD_MINI_LOADER 0)