diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index bb6cf100a..78b7da88d 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -337,6 +337,10 @@ aot_gen_commit_values(AOTCompFrame *frame) LLVMValueRef value; uint32 n; + if (!frame->comp_ctx->call_stack_features.values) { + return true; + } + /* First, commit reference flags * For LLVM JIT, iterate all local and stack ref flags * For AOT, ignore local(params + locals) ref flags */ @@ -629,7 +633,7 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip) offset_sp = offsetof(WASMInterpFrame, sp); } - if (commit_ip) { + if (commit_ip && comp_ctx->call_stack_features.ip) { if (!comp_ctx->is_jit_mode) { WASMModule *module = comp_ctx->comp_data->wasm_module; if (is_64bit) @@ -654,7 +658,7 @@ aot_gen_commit_sp_ip(AOTCompFrame *frame, bool commit_sp, bool commit_ip) } } - if (commit_sp) { + if (commit_sp && comp_ctx->call_stack_features.values) { n = (uint32)(sp - frame->lp); value = I32_CONST(offset_of_local(comp_ctx, n)); if (!value) { diff --git a/core/iwasm/compilation/aot_emit_exception.c b/core/iwasm/compilation/aot_emit_exception.c index 968ee78b6..1527e83e5 100644 --- a/core/iwasm/compilation/aot_emit_exception.c +++ b/core/iwasm/compilation/aot_emit_exception.c @@ -41,7 +41,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - if (comp_ctx->aot_frame) { + if (comp_ctx->aot_frame && comp_ctx->call_stack_features.trap_ip) { /* Create exception ip phi */ if (!(func_ctx->exception_ip_phi = LLVMBuildPhi( comp_ctx->builder, is_64bit ? I64_TYPE : I32_TYPE, @@ -134,7 +134,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Add phi incoming value to got_exception block */ LLVMAddIncoming(func_ctx->exception_id_phi, &exce_id, &block_curr, 1); - if (comp_ctx->aot_frame) { + if (comp_ctx->aot_frame && comp_ctx->call_stack_features.trap_ip) { const uint8 *ip = comp_ctx->aot_frame->frame_ip; LLVMValueRef exce_ip = NULL; diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 8f6e3e456..1d565b6c0 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -682,24 +682,29 @@ alloc_frame_for_aot_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, new_frame = wasm_stack_top; - if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext( - comp_ctx->context, func_ctx->func, "check_wasm_stack_succ"))) { - aot_set_last_error("llvm add basic block failed."); - return false; - } + if (comp_ctx->call_stack_features.bounds_checks) { + if (!(check_wasm_stack_succ = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, + "check_wasm_stack_succ"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } - LLVMMoveBasicBlockAfter(check_wasm_stack_succ, - LLVMGetInsertBlock(comp_ctx->builder)); + LLVMMoveBasicBlockAfter(check_wasm_stack_succ, + LLVMGetInsertBlock(comp_ctx->builder)); - if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, wasm_stack_top_max, - wasm_stack_top_bound, "cmp"))) { - aot_set_last_error("llvm build icmp failed"); - return false; - } + if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, + wasm_stack_top_max, wasm_stack_top_bound, + "cmp"))) { + aot_set_last_error("llvm build icmp failed"); + return false; + } - if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_OPERAND_STACK_OVERFLOW, - true, cmp, check_wasm_stack_succ))) { - return false; + if (!(aot_emit_exception(comp_ctx, func_ctx, + EXCE_OPERAND_STACK_OVERFLOW, true, cmp, + check_wasm_stack_succ))) { + return false; + } } #if WASM_ENABLE_GC != 0 @@ -1285,6 +1290,10 @@ commit_params_to_frame_of_import_func(AOTCompContext *comp_ctx, { uint32 i, n; + if (!comp_ctx->call_stack_features.values) { + return true; + } + for (i = 0, n = 0; i < func_type->param_count; i++, n++) { switch (func_type->types[i]) { case VALUE_TYPE_I32: diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 39f64d81d..3346086a9 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -2580,6 +2580,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) if (option->enable_aux_stack_frame) comp_ctx->enable_aux_stack_frame = true; + comp_ctx->call_stack_features = option->call_stack_features; + if (option->enable_perf_profiling) comp_ctx->enable_perf_profiling = true; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index 270e5ae45..65debbaa3 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -412,6 +412,9 @@ typedef struct AOTCompContext { /* Generate auxiliary stack frame */ bool enable_aux_stack_frame; + /* Auxiliary call stack features */ + AOTCallStackFeatures call_stack_features; + /* Function performance profiling */ bool enable_perf_profiling; diff --git a/core/iwasm/include/aot_comp_option.h b/core/iwasm/include/aot_comp_option.h index 617b68f97..4ab2e6ab6 100644 --- a/core/iwasm/include/aot_comp_option.h +++ b/core/iwasm/include/aot_comp_option.h @@ -6,6 +6,23 @@ #ifndef __AOT_COMP_OPTION_H__ #define __AOT_COMP_OPTION_H__ +typedef struct { + /* Enables or disables bounds checks for stack frames. When enabled, the AOT + * compiler generates code to check if the stack pointer is within the + * bounds of the current stack frame (and if not, traps). */ + bool bounds_checks; + + /* Enables or disables instruction pointer (IP) tracking.*/ + bool ip; + + /* Enables or disables tracking instruction pointer of a trap. Only takes + * effect when `ip` is enabled.*/ + bool trap_ip; + + /* Enables or disables parameters, locals and stack operands. */ + bool values; +} AOTCallStackFeatures; + typedef struct AOTCompOption { bool is_jit_mode; bool is_indirect_mode; @@ -22,6 +39,7 @@ typedef struct AOTCompOption { bool enable_gc; bool enable_aux_stack_check; bool enable_aux_stack_frame; + AOTCallStackFeatures call_stack_features; bool enable_perf_profiling; bool enable_memory_profiling; bool disable_llvm_intrinsics; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 13947ac82..092e0d152 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -5407,6 +5407,7 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, #if WASM_ENABLE_PERF_PROFILING != 0 || WASM_ENABLE_DUMP_CALL_STACK != 0 \ || WASM_ENABLE_AOT_STACK_FRAME != 0 option.enable_aux_stack_frame = true; + memset(&option.call_stack_features, 1, sizeof(AOTCallStackFeatures)); #endif #if WASM_ENABLE_PERF_PROFILING != 0 option.enable_perf_profiling = true; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 8826f98db..a21f4490f 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -2149,6 +2149,7 @@ init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, #if WASM_ENABLE_PERF_PROFILING != 0 || WASM_ENABLE_DUMP_CALL_STACK != 0 \ || WASM_ENABLE_AOT_STACK_FRAME != 0 option.enable_aux_stack_frame = true; + memset(&option.call_stack_features, 1, sizeof(AOTCallStackFeatures)); #endif #if WASM_ENABLE_PERF_PROFILING != 0 option.enable_perf_profiling = true; diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index bd9e54353..3c7ef1f4d 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -162,6 +162,12 @@ print_help() printf(" GC is enabled\n"); printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); + printf(" --call-stack-features=\n"); + printf(" A comma-separated list of features when generating call stacks.\n"); + printf(" By default, all features are enabled. To disable all features,\n"); + printf(" provide an empty list (i.e. --call-stack-features=). This flag\n"); + printf(" only only takes effect when --enable-dump-call-stack is set.\n"); + printf(" Available features: bounds-checks, ip, trap-ip, values.\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); printf(" --enable-memory-profiling Enable memory usage profiling\n"); printf(" --xip A shorthand of --enable-indirect-mode --disable-llvm-intrinsics\n"); @@ -259,6 +265,48 @@ split_string(char *str, int *count, const char *delimer) return res; } +static bool +parse_call_stack_features(char *features_str, + AOTCallStackFeatures *out_features) +{ + int size = 0; + char **features; + bool ret = true; + + bh_assert(features_str); + bh_assert(out_features); + + /* non-empty feature list */ + features = split_string(features_str, &size, ","); + if (!features) { + return false; + } + + while (size--) { + if (!strcmp(features[size], "bounds-checks")) { + out_features->bounds_checks = true; + } + else if (!strcmp(features[size], "ip")) { + out_features->ip = true; + } + else if (!strcmp(features[size], "trap-ip")) { + out_features->trap_ip = true; + } + else if (!strcmp(features[size], "values")) { + out_features->values = true; + } + else { + ret = false; + printf("Unsupported feature %s\n", features[size]); + goto finish; + } + } + +finish: + free(features); + return ret; +} + static uint32 resolve_segue_flags(char *str_flags) { @@ -356,6 +404,9 @@ main(int argc, char *argv[]) option.enable_ref_types = true; option.enable_gc = false; + /* Set all the features to true by default */ + memset(&option.call_stack_features, 1, sizeof(AOTCallStackFeatures)); + /* Process options */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-o")) { @@ -470,6 +521,19 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-dump-call-stack")) { option.enable_aux_stack_frame = true; } + else if (!strncmp(argv[0], "--call-stack-features=", 22)) { + /* Reset all the features, only enable the user-defined ones */ + memset(&option.call_stack_features, 0, + sizeof(AOTCallStackFeatures)); + + if (argv[0][22] != '\0') { + if (!parse_call_stack_features(argv[0] + 22, + &option.call_stack_features)) { + printf("Failed to parse call-stack-features\n"); + PRINT_HELP_AND_EXIT(); + } + } + } else if (!strcmp(argv[0], "--enable-perf-profiling")) { option.enable_aux_stack_frame = true; option.enable_perf_profiling = true; @@ -608,6 +672,12 @@ main(int argc, char *argv[]) #endif } + if (option.enable_gc && !option.call_stack_features.values) { + LOG_WARNING("Call stack feature 'values' must be enabled for GC. The " + "feature will be enabled automatically."); + option.call_stack_features.values = true; + } + if (sgx_mode) { option.size_level = 1; option.is_sgx_platform = true;