From 6656ba04b2b5327fc01d7b639221af538ea4e8dc Mon Sep 17 00:00:00 2001 From: cocolato Date: Sat, 17 Jan 2026 19:40:00 +0800 Subject: [PATCH 1/6] show stack infos when set PYTHON_OPT_DEBUG>4 --- Python/optimizer_analysis.c | 36 ++++++++++++++++++++++++++++ Python/optimizer_symbols.c | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index e855df4977acf8..a8bf2eebbcb15a 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -39,6 +39,7 @@ #ifdef Py_DEBUG extern const char *_PyUOpName(int index); extern void _PyUOpPrint(const _PyUOpInstruction *uop); + extern void _PyUOpSymPrint(JitOptRef ref); static const char *const DEBUG_ENV = "PYTHON_OPT_DEBUG"; static inline int get_lltrace(void) { char *uop_debug = Py_GETENV(DEBUG_ENV); @@ -50,6 +51,38 @@ } #define DPRINTF(level, ...) \ if (get_lltrace() >= (level)) { printf(__VA_ARGS__); } + + + +static void +dump_abstract_stack(_Py_UOpsAbstractFrame *frame, JitOptRef *stack_pointer) +{ + JitOptRef *stack_base = frame->stack; + JitOptRef *locals_base = frame->locals; + printf(" locals=["); + for (JitOptRef *ptr = locals_base; ptr < stack_base; ptr++) { + if (ptr != locals_base) { + printf(", "); + } + _PyUOpSymPrint(*ptr); + } + printf("]\n"); + if (stack_pointer < stack_base) { + printf(" stack=%d\n", (int)(stack_pointer - stack_base)); + } + else { + printf(" stack=["); + for (JitOptRef *ptr = stack_base; ptr < stack_pointer; ptr++) { + if (ptr != stack_base) { + printf(", "); + } + _PyUOpSymPrint(*ptr); + } + printf("]\n"); + } + fflush(stdout); +} + #else #define DPRINTF(level, ...) #endif @@ -381,6 +414,9 @@ optimize_uops( #ifdef Py_DEBUG if (get_lltrace() >= 3) { + if (get_lltrace() >= 5 && !CURRENT_FRAME_IS_INIT_SHIM()) { + dump_abstract_stack(ctx->frame, stack_pointer); + } printf("%4d abs: ", (int)(this_instr - trace)); _PyUOpPrint(this_instr); printf(" "); diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index c6b54b9b58b795..f9e60d7e3996cc 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -68,6 +68,53 @@ static inline int get_lltrace(void) { } #define DPRINTF(level, ...) \ if (get_lltrace() >= (level)) { printf(__VA_ARGS__); } + +void +_PyUOpSymPrint(JitOptRef ref) +{ + if (PyJitRef_IsNull(ref)) { + printf(""); + return; + } + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + switch (sym->tag) { + case JIT_SYM_UNKNOWN_TAG: + printf("", (void *)sym); + break; + case JIT_SYM_NULL_TAG: + printf("", (void *)sym); + break; + case JIT_SYM_NON_NULL_TAG: + printf("", (void *)sym); + break; + case JIT_SYM_BOTTOM_TAG: + printf("", (void *)sym); + break; + case JIT_SYM_TYPE_VERSION_TAG: + printf("", sym->version.version, (void *)sym); + break; + case JIT_SYM_KNOWN_CLASS_TAG: + printf("<%s at %p>", sym->cls.type->tp_name, (void *)sym); + break; + case JIT_SYM_KNOWN_VALUE_TAG: + printf("<%s val=%p at %p>", Py_TYPE(sym->value.value)->tp_name, + (void *)sym->value.value, (void *)sym); + break; + case JIT_SYM_TUPLE_TAG: + printf("", sym->tuple.length, (void *)sym); + break; + case JIT_SYM_TRUTHINESS_TAG: + printf("", sym->truthiness.invert ? "!" : "", (void *)sym); + break; + case JIT_SYM_COMPACT_INT: + printf("", (void *)sym); + break; + default: + printf("", sym->tag, (void *)sym); + break; + } +} + #else #define DPRINTF(level, ...) #endif From a9add64de062308826505cc5ba9b7584892323d0 Mon Sep 17 00:00:00 2001 From: cocolato Date: Sat, 17 Jan 2026 19:44:25 +0800 Subject: [PATCH 2/6] show stack infos when set PYTHON_OPT_DEBUG>4 --- Python/optimizer_analysis.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index a8bf2eebbcb15a..cd3b79a2c13140 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -414,12 +414,12 @@ optimize_uops( #ifdef Py_DEBUG if (get_lltrace() >= 3) { + printf("%4d abs: ", (int)(this_instr - trace)); + _PyUOpPrint(this_instr); + printf(" \n"); if (get_lltrace() >= 5 && !CURRENT_FRAME_IS_INIT_SHIM()) { dump_abstract_stack(ctx->frame, stack_pointer); } - printf("%4d abs: ", (int)(this_instr - trace)); - _PyUOpPrint(this_instr); - printf(" "); } #endif From b52ce1eb4b9c924f02c3edf97a0aa4b49beb42f0 Mon Sep 17 00:00:00 2001 From: cocolato Date: Sat, 17 Jan 2026 21:01:31 +0800 Subject: [PATCH 3/6] simple the debug ouput --- Python/optimizer_symbols.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index f9e60d7e3996cc..c64c916769ed46 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -79,7 +79,7 @@ _PyUOpSymPrint(JitOptRef ref) JitOptSymbol *sym = PyJitRef_Unwrap(ref); switch (sym->tag) { case JIT_SYM_UNKNOWN_TAG: - printf("", (void *)sym); + printf("", (void *)sym); break; case JIT_SYM_NULL_TAG: printf("", (void *)sym); From 210275ab48c18aa0348524837f82e9f4af1f2d6c Mon Sep 17 00:00:00 2001 From: cocolato Date: Sat, 17 Jan 2026 22:04:52 +0800 Subject: [PATCH 4/6] add INVALID_TAG for abstract frame --- Include/internal/pycore_optimizer_types.h | 3 +++ Python/optimizer_symbols.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index 0a193268c4d618..6c4fe7bc994fe7 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -39,6 +39,8 @@ typedef enum _JitSymType { JIT_SYM_TUPLE_TAG = 8, JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, + + JIT_SYM_INVALID_TAG = 255, // for non-symbol values on abstract stack } JitSymType; typedef struct _jit_opt_known_class { @@ -91,6 +93,7 @@ typedef union { } JitOptRef; typedef struct _Py_UOpsAbstractFrame { + uint8_t tag; bool globals_watched; // The version number of the globals dicts, once checked. 0 if unchecked. uint32_t globals_checked_version; diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index c64c916769ed46..15e86742fff6e3 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -109,6 +109,9 @@ _PyUOpSymPrint(JitOptRef ref) case JIT_SYM_COMPACT_INT: printf("", (void *)sym); break; + case JIT_SYM_INVALID_TAG: + printf("", (void *)sym); + break; default: printf("", sym->tag, (void *)sym); break; @@ -871,6 +874,7 @@ _Py_uop_frame_new( return NULL; } _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; + frame->tag = JIT_SYM_INVALID_TAG; frame->code = co; frame->stack_len = co->co_stacksize; frame->locals_len = co->co_nlocalsplus; From c565bbb4853c775397dbb4c883ad1a52c918d516 Mon Sep 17 00:00:00 2001 From: cocolato Date: Sat, 17 Jan 2026 22:06:38 +0800 Subject: [PATCH 5/6] fix lint --- Include/internal/pycore_optimizer_types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index 6c4fe7bc994fe7..1406c557f14532 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -39,7 +39,6 @@ typedef enum _JitSymType { JIT_SYM_TUPLE_TAG = 8, JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, - JIT_SYM_INVALID_TAG = 255, // for non-symbol values on abstract stack } JitSymType; From 8508af7a7744ec561c113eb996bdb002a3090731 Mon Sep 17 00:00:00 2001 From: cocolato Date: Sat, 17 Jan 2026 22:40:03 +0800 Subject: [PATCH 6/6] add INVALID tag for abstract frame --- Include/internal/pycore_optimizer.h | 16 +++++++++++++++- Include/internal/pycore_optimizer_types.h | 2 -- Python/optimizer_bytecodes.c | 20 ++++++++++---------- Python/optimizer_cases.c.h | 20 ++++++++++---------- Python/optimizer_symbols.c | 8 ++++---- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 5f92a86f813aae..0592221f15226e 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -115,8 +115,10 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst) #define REF_IS_BORROWED 1 +#define REF_IS_INVALID 2 +#define REF_TAG_BITS 3 -#define JIT_BITS_TO_PTR_MASKED(REF) ((JitOptSymbol *)(((REF).bits) & (~REF_IS_BORROWED))) +#define JIT_BITS_TO_PTR_MASKED(REF) ((JitOptSymbol *)(((REF).bits) & (~REF_TAG_BITS))) static inline JitOptSymbol * PyJitRef_Unwrap(JitOptRef ref) @@ -133,6 +135,18 @@ PyJitRef_Wrap(JitOptSymbol *sym) return (JitOptRef){.bits=(uintptr_t)sym}; } +static inline JitOptRef +PyJitRef_WrapInvalid(void *ptr) +{ + return (JitOptRef){.bits=(uintptr_t)ptr | REF_IS_INVALID}; +} + +static inline bool +PyJitRef_IsInvalid(JitOptRef ref) +{ + return (ref.bits & REF_IS_INVALID) == REF_IS_INVALID; +} + static inline JitOptRef PyJitRef_StripReferenceInfo(JitOptRef ref) { diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index ee8c3c75b21a5d..10828d1027dd09 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -40,7 +40,6 @@ typedef enum _JitSymType { JIT_SYM_TUPLE_TAG = 8, JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, - JIT_SYM_INVALID_TAG = 255, // for non-symbol values on abstract stack } JitSymType; typedef struct _jit_opt_known_class { @@ -93,7 +92,6 @@ typedef union { } JitOptRef; typedef struct _Py_UOpsAbstractFrame { - uint8_t tag; bool globals_watched; // The version number of the globals dicts, once checked. 0 if unchecked. uint32_t globals_checked_version; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 1a64810b50a3a4..8fae031e11b4b0 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -340,7 +340,7 @@ dummy_func(void) { } f->locals[0] = container; f->locals[1] = sub; - new_frame = PyJitRef_Wrap((JitOptSymbol *)f); + new_frame = PyJitRef_WrapInvalid(f); } op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res, s, i)) { @@ -784,7 +784,7 @@ dummy_func(void) { break; } f->locals[0] = owner; - new_frame = PyJitRef_Wrap((JitOptSymbol *)f); + new_frame = PyJitRef_WrapInvalid(f); } op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { @@ -848,9 +848,9 @@ dummy_func(void) { } if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) { - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, args, argcount)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args, argcount)); } else { - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); } } @@ -868,7 +868,7 @@ dummy_func(void) { break; } - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); } op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame)) { @@ -879,7 +879,7 @@ dummy_func(void) { break; } - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); } op(_PY_FRAME_EX, (func_st, null, callargs_st, kwargs_st -- ex_frame)) { @@ -890,7 +890,7 @@ dummy_func(void) { break; } - ex_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + ex_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); } op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { @@ -914,7 +914,7 @@ dummy_func(void) { ctx->curr_frame_depth++; assert((this_instr + 1)->opcode == _PUSH_FRAME); PyCodeObject *co = get_code_with_logging((this_instr + 1)); - init_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, args-1, oparg+1)); + init_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args-1, oparg+1)); } op(_RETURN_VALUE, (retval -- res)) { @@ -1007,7 +1007,7 @@ dummy_func(void) { break; } new_frame->stack[0] = sym_new_const(ctx, Py_None); - gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame); + gen_frame = PyJitRef_WrapInvalid(new_frame); } op(_SEND_GEN_FRAME, (unused, v -- unused, gen_frame)) { @@ -1023,7 +1023,7 @@ dummy_func(void) { break; } new_frame->stack[0] = PyJitRef_StripReferenceInfo(v); - gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame); + gen_frame = PyJitRef_WrapInvalid(new_frame); } op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index f3bc7213fcce3f..e737a0b8800b2c 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1131,7 +1131,7 @@ } f->locals[0] = container; f->locals[1] = sub; - new_frame = PyJitRef_Wrap((JitOptSymbol *)f); + new_frame = PyJitRef_WrapInvalid(f); CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = new_frame; stack_pointer += -2; @@ -1295,7 +1295,7 @@ break; } new_frame->stack[0] = PyJitRef_StripReferenceInfo(v); - gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame); + gen_frame = PyJitRef_WrapInvalid(new_frame); stack_pointer[-1] = gen_frame; break; } @@ -1977,7 +1977,7 @@ break; } f->locals[0] = owner; - new_frame = PyJitRef_Wrap((JitOptSymbol *)f); + new_frame = PyJitRef_WrapInvalid(f); stack_pointer[-1] = new_frame; break; } @@ -2662,7 +2662,7 @@ break; } new_frame->stack[0] = sym_new_const(ctx, Py_None); - gen_frame = PyJitRef_Wrap((JitOptSymbol *)new_frame); + gen_frame = PyJitRef_WrapInvalid(new_frame); CHECK_STACK_BOUNDS(1); stack_pointer[0] = gen_frame; stack_pointer += 1; @@ -2846,7 +2846,7 @@ ctx->done = true; break; } - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = new_frame; stack_pointer += -1 - oparg; @@ -2978,9 +2978,9 @@ argcount++; } if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) { - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, args, argcount)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args, argcount)); } else { - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); } CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = new_frame; @@ -3175,7 +3175,7 @@ ctx->curr_frame_depth++; assert((this_instr + 1)->opcode == _PUSH_FRAME); PyCodeObject *co = get_code_with_logging((this_instr + 1)); - init_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, args-1, oparg+1)); + init_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args-1, oparg+1)); CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = init_frame; stack_pointer += -1 - oparg; @@ -3441,7 +3441,7 @@ ctx->done = true; break; } - new_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); CHECK_STACK_BOUNDS(-2 - oparg); stack_pointer[-3 - oparg] = new_frame; stack_pointer += -2 - oparg; @@ -3493,7 +3493,7 @@ ctx->done = true; break; } - ex_frame = PyJitRef_Wrap((JitOptSymbol *)frame_new(ctx, co, 0, NULL, 0)); + ex_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); CHECK_STACK_BOUNDS(-3); stack_pointer[-4] = ex_frame; stack_pointer += -3; diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 15e86742fff6e3..5f5086d33b5c4c 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -76,6 +76,10 @@ _PyUOpSymPrint(JitOptRef ref) printf(""); return; } + if (PyJitRef_IsInvalid(ref)) { + printf("", (void *)PyJitRef_Unwrap(ref)); + return; + } JitOptSymbol *sym = PyJitRef_Unwrap(ref); switch (sym->tag) { case JIT_SYM_UNKNOWN_TAG: @@ -109,9 +113,6 @@ _PyUOpSymPrint(JitOptRef ref) case JIT_SYM_COMPACT_INT: printf("", (void *)sym); break; - case JIT_SYM_INVALID_TAG: - printf("", (void *)sym); - break; default: printf("", sym->tag, (void *)sym); break; @@ -874,7 +875,6 @@ _Py_uop_frame_new( return NULL; } _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; - frame->tag = JIT_SYM_INVALID_TAG; frame->code = co; frame->stack_len = co->co_stacksize; frame->locals_len = co->co_nlocalsplus;