@@ -890,6 +890,138 @@ def testfunc(n):
890890 self .assertLessEqual (len (guard_nos_unicode_count ), 1 )
891891 self .assertIn ("_COMPARE_OP_STR" , uops )
892892
893+ def test_compare_int_eq_narrows_to_constant (self ):
894+ def f (n ):
895+ def return_1 ():
896+ return 1
897+
898+ hits = 0
899+ v = return_1 ()
900+ for _ in range (n ):
901+ if v == 1 :
902+ if v == 1 :
903+ hits += 1
904+ return hits
905+
906+ res , ex = self ._run_with_optimizer (f , TIER2_THRESHOLD )
907+ self .assertEqual (res , TIER2_THRESHOLD )
908+ self .assertIsNotNone (ex )
909+ uops = get_opnames (ex )
910+
911+ # Constant narrowing allows constant folding for second comparison
912+ self .assertLessEqual (count_ops (ex , "_COMPARE_OP_INT" ), 1 )
913+
914+ def test_compare_int_ne_narrows_to_constant (self ):
915+ def f (n ):
916+ def return_1 ():
917+ return 1
918+
919+ hits = 0
920+ v = return_1 ()
921+ for _ in range (n ):
922+ if v != 1 :
923+ hits += 1000
924+ else :
925+ if v == 1 :
926+ hits += v + 1
927+ return hits
928+
929+ res , ex = self ._run_with_optimizer (f , TIER2_THRESHOLD )
930+ self .assertEqual (res , TIER2_THRESHOLD * 2 )
931+ self .assertIsNotNone (ex )
932+ uops = get_opnames (ex )
933+
934+ # Constant narrowing allows constant folding for second comparison
935+ self .assertLessEqual (count_ops (ex , "_COMPARE_OP_INT" ), 1 )
936+
937+ def test_compare_float_eq_narrows_to_constant (self ):
938+ def f (n ):
939+ def return_tenth ():
940+ return 0.1
941+
942+ hits = 0
943+ v = return_tenth ()
944+ for _ in range (n ):
945+ if v == 0.1 :
946+ if v == 0.1 :
947+ hits += 1
948+ return hits
949+
950+ res , ex = self ._run_with_optimizer (f , TIER2_THRESHOLD )
951+ self .assertEqual (res , TIER2_THRESHOLD )
952+ self .assertIsNotNone (ex )
953+ uops = get_opnames (ex )
954+
955+ # Constant narrowing allows constant folding for second comparison
956+ self .assertLessEqual (count_ops (ex , "_COMPARE_OP_FLOAT" ), 1 )
957+
958+ def test_compare_float_ne_narrows_to_constant (self ):
959+ def f (n ):
960+ def return_tenth ():
961+ return 0.1
962+
963+ hits = 0
964+ v = return_tenth ()
965+ for _ in range (n ):
966+ if v != 0.1 :
967+ hits += 1000
968+ else :
969+ if v == 0.1 :
970+ hits += 1
971+ return hits
972+
973+ res , ex = self ._run_with_optimizer (f , TIER2_THRESHOLD )
974+ self .assertEqual (res , TIER2_THRESHOLD )
975+ self .assertIsNotNone (ex )
976+ uops = get_opnames (ex )
977+
978+ # Constant narrowing allows constant folding for second comparison
979+ self .assertLessEqual (count_ops (ex , "_COMPARE_OP_FLOAT" ), 1 )
980+
981+ def test_compare_str_eq_narrows_to_constant (self ):
982+ def f (n ):
983+ def return_hello ():
984+ return "hello"
985+
986+ hits = 0
987+ v = return_hello ()
988+ for _ in range (n ):
989+ if v == "hello" :
990+ if v == "hello" :
991+ hits += 1
992+ return hits
993+
994+ res , ex = self ._run_with_optimizer (f , TIER2_THRESHOLD )
995+ self .assertEqual (res , TIER2_THRESHOLD )
996+ self .assertIsNotNone (ex )
997+ uops = get_opnames (ex )
998+
999+ # Constant narrowing allows constant folding for second comparison
1000+ self .assertLessEqual (count_ops (ex , "_COMPARE_OP_STR" ), 1 )
1001+
1002+ def test_compare_str_ne_narrows_to_constant (self ):
1003+ def f (n ):
1004+ def return_hello ():
1005+ return "hello"
1006+
1007+ hits = 0
1008+ v = return_hello ()
1009+ for _ in range (n ):
1010+ if v != "hello" :
1011+ hits += 1000
1012+ else :
1013+ if v == "hello" :
1014+ hits += 1
1015+ return hits
1016+
1017+ res , ex = self ._run_with_optimizer (f , TIER2_THRESHOLD )
1018+ self .assertEqual (res , TIER2_THRESHOLD )
1019+ self .assertIsNotNone (ex )
1020+ uops = get_opnames (ex )
1021+
1022+ # Constant narrowing allows constant folding for second comparison
1023+ self .assertLessEqual (count_ops (ex , "_COMPARE_OP_STR" ), 1 )
1024+
8931025 @unittest .skip ("gh-139109 WIP" )
8941026 def test_combine_stack_space_checks_sequential (self ):
8951027 def dummy12 (x ):
@@ -2897,6 +3029,29 @@ def testfunc(n):
28973029 self .assertIn ("_POP_TOP_NOP" , uops )
28983030 self .assertLessEqual (count_ops (ex , "_POP_TOP" ), 2 )
28993031
3032+ def test_binary_op_refcount_elimination (self ):
3033+ class CustomAdder :
3034+ def __init__ (self , val ):
3035+ self .val = val
3036+ def __add__ (self , other ):
3037+ return CustomAdder (self .val + other .val )
3038+
3039+ def testfunc (n ):
3040+ a = CustomAdder (1 )
3041+ b = CustomAdder (2 )
3042+ res = None
3043+ for _ in range (n ):
3044+ res = a + b
3045+ return res .val if res else 0
3046+
3047+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
3048+ self .assertEqual (res , 3 )
3049+ self .assertIsNotNone (ex )
3050+ uops = get_opnames (ex )
3051+ self .assertIn ("_BINARY_OP" , uops )
3052+ self .assertIn ("_POP_TOP_NOP" , uops )
3053+ self .assertLessEqual (count_ops (ex , "_POP_TOP" ), 2 )
3054+
29003055 def test_binary_op_extend_float_long_add_refcount_elimination (self ):
29013056 def testfunc (n ):
29023057 a = 1.5
@@ -3866,6 +4021,29 @@ def __next__(self):
38664021 """ ), PYTHON_JIT = "1" , PYTHON_JIT_STRESS = "1" )
38674022 self .assertEqual (result [0 ].rc , 0 , result )
38684023
4024+ def test_144068_daemon_thread_jit_cleanup (self ):
4025+ result = script_helper .run_python_until_end ('-c' , textwrap .dedent ("""
4026+ import threading
4027+ import time
4028+
4029+ def hot_loop():
4030+ end = time.time() + 5.0
4031+ while time.time() < end:
4032+ pass
4033+
4034+ # Create a daemon thread that will be abandoned at shutdown
4035+ t = threading.Thread(target=hot_loop, daemon=True)
4036+ t.start()
4037+
4038+ time.sleep(0.1)
4039+ """ ), PYTHON_JIT = "1" , ASAN_OPTIONS = "detect_leaks=1" )
4040+ self .assertEqual (result [0 ].rc , 0 , result )
4041+ stderr = result [0 ].err .decode ('utf-8' , errors = 'replace' )
4042+ self .assertNotIn ('LeakSanitizer' , stderr ,
4043+ f"Memory leak detected by ASan:\n { stderr } " )
4044+ self .assertNotIn ('_PyJit_TryInitializeTracing' , stderr ,
4045+ f"JIT tracer memory leak detected:\n { stderr } " )
4046+
38694047def global_identity (x ):
38704048 return x
38714049
0 commit comments