From 1d54f5cac93be2ab32594863470217e125870a7e Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 4 Apr 2026 22:15:47 +0900 Subject: [PATCH 1/2] gh-148083: Prevent constant folding when lhs is container types --- Include/internal/pycore_optimizer.h | 1 + Python/optimizer_analysis.c | 1 + Python/optimizer_bytecodes.c | 6 ++++-- Python/optimizer_cases.c.h | 6 ++++-- Python/optimizer_symbols.c | 15 +++++++++++++++ 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 2986afb142b5d1..984ddb4f01f231 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -394,6 +394,7 @@ extern JitOptRef _Py_uop_sym_new_type( extern JitOptRef _Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val); extern JitOptRef _Py_uop_sym_new_const_steal(JitOptContext *ctx, PyObject *const_val); bool _Py_uop_sym_is_safe_const(JitOptContext *ctx, JitOptRef sym); +bool _Py_uop_sym_is_container(JitOptRef sym); _PyStackRef _Py_uop_sym_get_const_as_stackref(JitOptContext *ctx, JitOptRef sym); extern JitOptRef _Py_uop_sym_new_null(JitOptContext *ctx); extern bool _Py_uop_sym_has_type(JitOptRef sym); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 2953311b392600..cc1a7be0c43f85 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -252,6 +252,7 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_is_not_null _Py_uop_sym_is_not_null #define sym_is_const _Py_uop_sym_is_const #define sym_is_safe_const _Py_uop_sym_is_safe_const +#define sym_is_container _Py_uop_sym_is_container #define sym_get_const _Py_uop_sym_get_const #define sym_new_const_steal _Py_uop_sym_new_const_steal #define sym_get_const_as_stackref _Py_uop_sym_get_const_as_stackref diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 6e9a34384ba531..2eb8a4e181b8b3 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -515,7 +515,8 @@ dummy_func(void) { res = sym_new_not_null(ctx); ds = dict_st; ss = sub_st; - if (sym_matches_type(dict_st, &PyFrozenDict_Type)) { + if (!sym_is_container(sub_st) && + sym_matches_type(dict_st, &PyFrozenDict_Type)) { REPLACE_OPCODE_IF_EVALUATES_PURE(dict_st, sub_st, res); } } @@ -706,7 +707,8 @@ dummy_func(void) { b = sym_new_type(ctx, &PyBool_Type); l = left; r = right; - if (sym_matches_type(right, &PyFrozenSet_Type)) { + if (!sym_is_container(left) && + sym_matches_type(right, &PyFrozenSet_Type)) { REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, b); } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index dc00b6bc1397f5..725c4087ef8d95 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1462,7 +1462,8 @@ res = sym_new_not_null(ctx); ds = dict_st; ss = sub_st; - if (sym_matches_type(dict_st, &PyFrozenDict_Type)) { + if (!sym_is_container(sub_st) && + sym_matches_type(dict_st, &PyFrozenDict_Type)) { if ( sym_is_safe_const(ctx, dict_st) && sym_is_safe_const(ctx, sub_st) @@ -2993,7 +2994,8 @@ b = sym_new_type(ctx, &PyBool_Type); l = left; r = right; - if (sym_matches_type(right, &PyFrozenSet_Type)) { + if (!sym_is_container(left) && + sym_matches_type(right, &PyFrozenSet_Type)) { if ( sym_is_safe_const(ctx, left) && sym_is_safe_const(ctx, right) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 2614bcd430a2c5..1154a3852145b4 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -287,6 +287,21 @@ _Py_uop_sym_is_safe_const(JitOptContext *ctx, JitOptRef sym) (typ == &PyFrozenSet_Type); } +bool +_Py_uop_sym_is_container(JitOptRef sym) +{ + PyTypeObject *typ = _Py_uop_sym_get_type(sym); + if (typ == NULL) { + return false; + } + return (typ == &PyFrozenSet_Type) || + (typ == &PyFrozenDict_Type) || + (typ == &PySet_Type) || + (typ == &PyDict_Type) || + (typ == &PyList_Type) || + (typ == &PyTuple_Type); +} + void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ) { From 561daaf1c5babf1ffa076107c960991d9d3c2c42 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 4 Apr 2026 23:05:35 +0900 Subject: [PATCH 2/2] Address code review --- Include/internal/pycore_optimizer.h | 2 +- Python/optimizer_analysis.c | 2 +- Python/optimizer_bytecodes.c | 4 ++-- Python/optimizer_cases.c.h | 4 ++-- Python/optimizer_symbols.c | 13 ++++++------- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 984ddb4f01f231..cf01c620476ff7 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -394,7 +394,7 @@ extern JitOptRef _Py_uop_sym_new_type( extern JitOptRef _Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val); extern JitOptRef _Py_uop_sym_new_const_steal(JitOptContext *ctx, PyObject *const_val); bool _Py_uop_sym_is_safe_const(JitOptContext *ctx, JitOptRef sym); -bool _Py_uop_sym_is_container(JitOptRef sym); +bool _Py_uop_sym_is_not_container(JitOptRef sym); _PyStackRef _Py_uop_sym_get_const_as_stackref(JitOptContext *ctx, JitOptRef sym); extern JitOptRef _Py_uop_sym_new_null(JitOptContext *ctx); extern bool _Py_uop_sym_has_type(JitOptRef sym); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index cc1a7be0c43f85..92e1c081d524db 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -252,7 +252,7 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_is_not_null _Py_uop_sym_is_not_null #define sym_is_const _Py_uop_sym_is_const #define sym_is_safe_const _Py_uop_sym_is_safe_const -#define sym_is_container _Py_uop_sym_is_container +#define sym_is_not_container _Py_uop_sym_is_not_container #define sym_get_const _Py_uop_sym_get_const #define sym_new_const_steal _Py_uop_sym_new_const_steal #define sym_get_const_as_stackref _Py_uop_sym_get_const_as_stackref diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 2eb8a4e181b8b3..f2645553513f3d 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -515,7 +515,7 @@ dummy_func(void) { res = sym_new_not_null(ctx); ds = dict_st; ss = sub_st; - if (!sym_is_container(sub_st) && + if (sym_is_not_container(sub_st) && sym_matches_type(dict_st, &PyFrozenDict_Type)) { REPLACE_OPCODE_IF_EVALUATES_PURE(dict_st, sub_st, res); } @@ -707,7 +707,7 @@ dummy_func(void) { b = sym_new_type(ctx, &PyBool_Type); l = left; r = right; - if (!sym_is_container(left) && + if (sym_is_not_container(left) && sym_matches_type(right, &PyFrozenSet_Type)) { REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, b); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 725c4087ef8d95..fb3ec39a42eabc 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1462,7 +1462,7 @@ res = sym_new_not_null(ctx); ds = dict_st; ss = sub_st; - if (!sym_is_container(sub_st) && + if (sym_is_not_container(sub_st) && sym_matches_type(dict_st, &PyFrozenDict_Type)) { if ( sym_is_safe_const(ctx, dict_st) && @@ -2994,7 +2994,7 @@ b = sym_new_type(ctx, &PyBool_Type); l = left; r = right; - if (!sym_is_container(left) && + if (sym_is_not_container(left) && sym_matches_type(right, &PyFrozenSet_Type)) { if ( sym_is_safe_const(ctx, left) && diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 1154a3852145b4..6230b8948697e2 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -288,18 +288,17 @@ _Py_uop_sym_is_safe_const(JitOptContext *ctx, JitOptRef sym) } bool -_Py_uop_sym_is_container(JitOptRef sym) +_Py_uop_sym_is_not_container(JitOptRef sym) { PyTypeObject *typ = _Py_uop_sym_get_type(sym); if (typ == NULL) { return false; } - return (typ == &PyFrozenSet_Type) || - (typ == &PyFrozenDict_Type) || - (typ == &PySet_Type) || - (typ == &PyDict_Type) || - (typ == &PyList_Type) || - (typ == &PyTuple_Type); + return (typ == &PyLong_Type) || + (typ == &PyFloat_Type) || + (typ == &PyUnicode_Type) || + (typ == &_PyNone_Type) || + (typ == &PyBool_Type); } void