| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | import contextlib | 
					
						
							| 
									
										
										
										
											2025-01-07 17:25:48 -08:00
										 |  |  | import itertools | 
					
						
							| 
									
										
										
										
											2024-02-12 01:04:36 -08:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | import textwrap | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | import gc | 
					
						
							| 
									
										
										
										
											2024-02-24 02:43:52 +08:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-23 22:32:33 +00:00
										 |  |  | import _opcode | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-04 11:13:32 -08:00
										 |  |  | from test.support import (script_helper, requires_specialization, | 
					
						
							| 
									
										
										
										
											2025-01-31 02:50:54 -08:00
										 |  |  |                           import_helper, Py_GIL_DISABLED, requires_jit_enabled, | 
					
						
							|  |  |  |                           reset_code) | 
					
						
							| 
									
										
										
										
											2024-04-11 17:19:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | _testinternalcapi = import_helper.import_module("_testinternalcapi") | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-04 08:03:27 -07:00
										 |  |  | from _testinternalcapi import TIER2_THRESHOLD | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @contextlib.contextmanager | 
					
						
							|  |  |  | def clear_executors(func): | 
					
						
							|  |  |  |     # Clear executors in func before and after running a block | 
					
						
							| 
									
										
										
										
											2025-01-31 02:50:54 -08:00
										 |  |  |     reset_code(func) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |     try: | 
					
						
							|  |  |  |         yield | 
					
						
							|  |  |  |     finally: | 
					
						
							| 
									
										
										
										
											2025-01-31 02:50:54 -08:00
										 |  |  |         reset_code(func) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_first_executor(func): | 
					
						
							|  |  |  |     code = func.__code__ | 
					
						
							|  |  |  |     co_code = code.co_code | 
					
						
							|  |  |  |     for i in range(0, len(co_code), 2): | 
					
						
							| 
									
										
										
										
											2024-03-23 22:32:33 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             return _opcode.get_executor(code, i) | 
					
						
							|  |  |  |         except ValueError: | 
					
						
							|  |  |  |             pass | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  | def iter_opnames(ex): | 
					
						
							|  |  |  |     for item in ex: | 
					
						
							|  |  |  |         yield item[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_opnames(ex): | 
					
						
							| 
									
										
										
										
											2024-04-26 18:08:50 +01:00
										 |  |  |     return list(iter_opnames(ex)) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-29 18:53:32 -08:00
										 |  |  | @requires_specialization | 
					
						
							| 
									
										
										
										
											2024-11-04 11:13:32 -08:00
										 |  |  | @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  | @requires_jit_enabled | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | class TestExecutorInvalidation(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalidate_object(self): | 
					
						
							|  |  |  |         # Generate a new set of functions at each call | 
					
						
							|  |  |  |         ns = {} | 
					
						
							|  |  |  |         func_src = "\n".join( | 
					
						
							|  |  |  |             f"""
 | 
					
						
							|  |  |  |             def f{n}(): | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |                 for _ in range({TIER2_THRESHOLD}): | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |                     pass | 
					
						
							|  |  |  |             """ for n in range(5)
 | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         exec(textwrap.dedent(func_src), ns, ns) | 
					
						
							|  |  |  |         funcs = [ ns[f'f{n}'] for n in range(5)] | 
					
						
							|  |  |  |         objects = [object() for _ in range(5)] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         for f in funcs: | 
					
						
							|  |  |  |             f() | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         executors = [get_first_executor(f) for f in funcs] | 
					
						
							|  |  |  |         # Set things up so each executor depends on the objects | 
					
						
							|  |  |  |         # with an equal or lower index. | 
					
						
							|  |  |  |         for i, exe in enumerate(executors): | 
					
						
							|  |  |  |             self.assertTrue(exe.is_valid()) | 
					
						
							|  |  |  |             for obj in objects[:i+1]: | 
					
						
							|  |  |  |                 _testinternalcapi.add_executor_dependency(exe, obj) | 
					
						
							|  |  |  |             self.assertTrue(exe.is_valid()) | 
					
						
							|  |  |  |         # Assert that the correct executors are invalidated | 
					
						
							|  |  |  |         # and check that nothing crashes when we invalidate | 
					
						
							| 
									
										
										
										
											2024-08-12 12:16:41 +08:00
										 |  |  |         # an executor multiple times. | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         for i in (4,3,2,1,0): | 
					
						
							|  |  |  |             _testinternalcapi.invalidate_executors(objects[i]) | 
					
						
							|  |  |  |             for exe in executors[i:]: | 
					
						
							|  |  |  |                 self.assertFalse(exe.is_valid()) | 
					
						
							|  |  |  |             for exe in executors[:i]: | 
					
						
							|  |  |  |                 self.assertTrue(exe.is_valid()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_uop_optimizer_invalidation(self): | 
					
						
							|  |  |  |         # Generate a new function at each call | 
					
						
							|  |  |  |         ns = {} | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         exec(textwrap.dedent(f"""
 | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |             def f(): | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |                 for i in range({TIER2_THRESHOLD}): | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |                     pass | 
					
						
							|  |  |  |         """), ns, ns)
 | 
					
						
							|  |  |  |         f = ns['f'] | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         f() | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         exe = get_first_executor(f) | 
					
						
							| 
									
										
										
										
											2023-12-20 14:27:25 +00:00
										 |  |  |         self.assertIsNotNone(exe) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertTrue(exe.is_valid()) | 
					
						
							|  |  |  |         _testinternalcapi.invalidate_executors(f.__code__) | 
					
						
							|  |  |  |         self.assertFalse(exe.is_valid()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-12 01:04:36 -08:00
										 |  |  |     def test_sys__clear_internal_caches(self): | 
					
						
							|  |  |  |         def f(): | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |             for _ in range(TIER2_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2024-02-12 01:04:36 -08:00
										 |  |  |                 pass | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         f() | 
					
						
							| 
									
										
										
										
											2024-02-12 01:04:36 -08:00
										 |  |  |         exe = get_first_executor(f) | 
					
						
							|  |  |  |         self.assertIsNotNone(exe) | 
					
						
							|  |  |  |         self.assertTrue(exe.is_valid()) | 
					
						
							|  |  |  |         sys._clear_internal_caches() | 
					
						
							|  |  |  |         self.assertFalse(exe.is_valid()) | 
					
						
							|  |  |  |         exe = get_first_executor(f) | 
					
						
							|  |  |  |         self.assertIsNone(exe) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-29 18:53:32 -08:00
										 |  |  | @requires_specialization | 
					
						
							| 
									
										
										
										
											2024-11-04 11:13:32 -08:00
										 |  |  | @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  | @requires_jit_enabled | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  | @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | class TestUops(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_basic_loop(self): | 
					
						
							|  |  |  |         def testfunc(x): | 
					
						
							|  |  |  |             i = 0 | 
					
						
							|  |  |  |             while i < x: | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-04-24 14:41:30 +01:00
										 |  |  |         self.assertIn("_JUMP_TO_TOP", uops) | 
					
						
							| 
									
										
										
										
											2024-02-20 10:50:59 +00:00
										 |  |  |         self.assertIn("_LOAD_FAST_0", uops) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_extended_arg(self): | 
					
						
							|  |  |  |         "Check EXTENDED_ARG handling in superblock creation" | 
					
						
							|  |  |  |         ns = {} | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         exec(textwrap.dedent(f"""
 | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |             def many_vars(): | 
					
						
							|  |  |  |                 # 260 vars, so z9 should have index 259 | 
					
						
							|  |  |  |                 a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = 42 | 
					
						
							|  |  |  |                 b0 = b1 = b2 = b3 = b4 = b5 = b6 = b7 = b8 = b9 = 42 | 
					
						
							|  |  |  |                 c0 = c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = c9 = 42 | 
					
						
							|  |  |  |                 d0 = d1 = d2 = d3 = d4 = d5 = d6 = d7 = d8 = d9 = 42 | 
					
						
							|  |  |  |                 e0 = e1 = e2 = e3 = e4 = e5 = e6 = e7 = e8 = e9 = 42 | 
					
						
							|  |  |  |                 f0 = f1 = f2 = f3 = f4 = f5 = f6 = f7 = f8 = f9 = 42 | 
					
						
							|  |  |  |                 g0 = g1 = g2 = g3 = g4 = g5 = g6 = g7 = g8 = g9 = 42 | 
					
						
							|  |  |  |                 h0 = h1 = h2 = h3 = h4 = h5 = h6 = h7 = h8 = h9 = 42 | 
					
						
							|  |  |  |                 i0 = i1 = i2 = i3 = i4 = i5 = i6 = i7 = i8 = i9 = 42 | 
					
						
							|  |  |  |                 j0 = j1 = j2 = j3 = j4 = j5 = j6 = j7 = j8 = j9 = 42 | 
					
						
							|  |  |  |                 k0 = k1 = k2 = k3 = k4 = k5 = k6 = k7 = k8 = k9 = 42 | 
					
						
							|  |  |  |                 l0 = l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = 42 | 
					
						
							|  |  |  |                 m0 = m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = 42 | 
					
						
							|  |  |  |                 n0 = n1 = n2 = n3 = n4 = n5 = n6 = n7 = n8 = n9 = 42 | 
					
						
							|  |  |  |                 o0 = o1 = o2 = o3 = o4 = o5 = o6 = o7 = o8 = o9 = 42 | 
					
						
							|  |  |  |                 p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = p9 = 42 | 
					
						
							|  |  |  |                 q0 = q1 = q2 = q3 = q4 = q5 = q6 = q7 = q8 = q9 = 42 | 
					
						
							|  |  |  |                 r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = 42 | 
					
						
							|  |  |  |                 s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = 42 | 
					
						
							|  |  |  |                 t0 = t1 = t2 = t3 = t4 = t5 = t6 = t7 = t8 = t9 = 42 | 
					
						
							|  |  |  |                 u0 = u1 = u2 = u3 = u4 = u5 = u6 = u7 = u8 = u9 = 42 | 
					
						
							|  |  |  |                 v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8 = v9 = 42 | 
					
						
							|  |  |  |                 w0 = w1 = w2 = w3 = w4 = w5 = w6 = w7 = w8 = w9 = 42 | 
					
						
							|  |  |  |                 x0 = x1 = x2 = x3 = x4 = x5 = x6 = x7 = x8 = x9 = 42 | 
					
						
							|  |  |  |                 y0 = y1 = y2 = y3 = y4 = y5 = y6 = y7 = y8 = y9 = 42 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |                 z0 = z1 = z2 = z3 = z4 = z5 = z6 = z7 = z8 = z9 = {TIER2_THRESHOLD} | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |                 while z9 > 0: | 
					
						
							|  |  |  |                     z9 = z9 - 1 | 
					
						
							| 
									
										
										
										
											2024-08-13 10:25:44 +01:00
										 |  |  |                     +z9 | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         """), ns, ns)
 | 
					
						
							|  |  |  |         many_vars = ns["many_vars"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         ex = get_first_executor(many_vars) | 
					
						
							|  |  |  |         self.assertIsNone(ex) | 
					
						
							|  |  |  |         many_vars() | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(many_vars) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         self.assertTrue(any((opcode, oparg, operand) == ("_LOAD_FAST", 259, 0) | 
					
						
							|  |  |  |                             for opcode, oparg, _, operand in list(ex))) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_unspecialized_unpack(self): | 
					
						
							|  |  |  |         # An example of an unspecialized opcode | 
					
						
							|  |  |  |         def testfunc(x): | 
					
						
							|  |  |  |             i = 0 | 
					
						
							|  |  |  |             while i < x: | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  |                 a, b = {1: 2, 3: 3} | 
					
						
							|  |  |  |             assert a == 1 and b == 3 | 
					
						
							|  |  |  |             i = 0 | 
					
						
							|  |  |  |             while i < x: | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_UNPACK_SEQUENCE", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pop_jump_if_false(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             i = 0 | 
					
						
							|  |  |  |             while i < n: | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_GUARD_IS_TRUE_POP", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_pop_jump_if_none(self): | 
					
						
							|  |  |  |         def testfunc(a): | 
					
						
							|  |  |  |             for x in a: | 
					
						
							|  |  |  |                 if x is None: | 
					
						
							|  |  |  |                     x = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(range(TIER2_THRESHOLD)) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-03-05 15:06:00 +00:00
										 |  |  |         self.assertNotIn("_GUARD_IS_NONE_POP", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_pop_jump_if_not_none(self): | 
					
						
							|  |  |  |         def testfunc(a): | 
					
						
							|  |  |  |             for x in a: | 
					
						
							|  |  |  |                 x = None | 
					
						
							|  |  |  |                 if x is not None: | 
					
						
							|  |  |  |                     x = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(range(TIER2_THRESHOLD)) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-03-05 15:06:00 +00:00
										 |  |  |         self.assertNotIn("_GUARD_IS_NONE_POP", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_pop_jump_if_true(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             i = 0 | 
					
						
							|  |  |  |             while not i >= n: | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_GUARD_IS_FALSE_POP", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_jump_backward(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             i = 0 | 
					
						
							|  |  |  |             while i < n: | 
					
						
							|  |  |  |                 i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_JUMP_TO_TOP", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_jump_forward(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             while a < n: | 
					
						
							|  |  |  |                 if a < 0: | 
					
						
							|  |  |  |                     a = -a | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     a = +a | 
					
						
							|  |  |  |                 a += 1 | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         # Since there is no JUMP_FORWARD instruction, | 
					
						
							|  |  |  |         # look for indirect evidence: the += operator | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_ADD_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_for_iter_range(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             total = 0 | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 total += i | 
					
						
							|  |  |  |             return total | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         total = testfunc(TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(total, sum(range(TIER2_THRESHOLD))) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         # for i, (opname, oparg) in enumerate(ex): | 
					
						
							|  |  |  |         #     print(f"{i:4d}: {opname:<20s} {oparg:3d}") | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_GUARD_NOT_EXHAUSTED_RANGE", uops) | 
					
						
							|  |  |  |         # Verification that the jump goes past END_FOR | 
					
						
							|  |  |  |         # is done by manual inspection of the output | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_for_iter_list(self): | 
					
						
							|  |  |  |         def testfunc(a): | 
					
						
							|  |  |  |             total = 0 | 
					
						
							|  |  |  |             for i in a: | 
					
						
							|  |  |  |                 total += i | 
					
						
							|  |  |  |             return total | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         a = list(range(TIER2_THRESHOLD)) | 
					
						
							|  |  |  |         total = testfunc(a) | 
					
						
							|  |  |  |         self.assertEqual(total, sum(a)) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         # for i, (opname, oparg) in enumerate(ex): | 
					
						
							|  |  |  |         #     print(f"{i:4d}: {opname:<20s} {oparg:3d}") | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_GUARD_NOT_EXHAUSTED_LIST", uops) | 
					
						
							|  |  |  |         # Verification that the jump goes past END_FOR | 
					
						
							|  |  |  |         # is done by manual inspection of the output | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_for_iter_tuple(self): | 
					
						
							|  |  |  |         def testfunc(a): | 
					
						
							|  |  |  |             total = 0 | 
					
						
							|  |  |  |             for i in a: | 
					
						
							|  |  |  |                 total += i | 
					
						
							|  |  |  |             return total | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         a = tuple(range(TIER2_THRESHOLD)) | 
					
						
							|  |  |  |         total = testfunc(a) | 
					
						
							|  |  |  |         self.assertEqual(total, sum(a)) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         # for i, (opname, oparg) in enumerate(ex): | 
					
						
							|  |  |  |         #     print(f"{i:4d}: {opname:<20s} {oparg:3d}") | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_GUARD_NOT_EXHAUSTED_TUPLE", uops) | 
					
						
							|  |  |  |         # Verification that the jump goes past END_FOR | 
					
						
							|  |  |  |         # is done by manual inspection of the output | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_list_edge_case(self): | 
					
						
							|  |  |  |         def testfunc(it): | 
					
						
							|  |  |  |             for x in it: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         a = [1, 2, 3] | 
					
						
							|  |  |  |         it = iter(a) | 
					
						
							|  |  |  |         testfunc(it) | 
					
						
							|  |  |  |         a.append(4) | 
					
						
							|  |  |  |         with self.assertRaises(StopIteration): | 
					
						
							|  |  |  |             next(it) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_call_py_exact_args(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             def dummy(x): | 
					
						
							|  |  |  |                 return x+1 | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 dummy(i) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_PUSH_FRAME", uops) | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_ADD_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_branch_taken(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 if i < 0: | 
					
						
							|  |  |  |                     i = 0 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     i = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_GUARD_IS_FALSE_POP", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_for_iter_tier_two(self): | 
					
						
							|  |  |  |         class MyIter: | 
					
						
							|  |  |  |             def __init__(self, n): | 
					
						
							|  |  |  |                 self.n = n | 
					
						
							|  |  |  |             def __iter__(self): | 
					
						
							|  |  |  |                 return self | 
					
						
							|  |  |  |             def __next__(self): | 
					
						
							|  |  |  |                 self.n -= 1 | 
					
						
							|  |  |  |                 if self.n < 0: | 
					
						
							|  |  |  |                     raise StopIteration | 
					
						
							|  |  |  |                 return self.n | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def testfunc(n, m): | 
					
						
							|  |  |  |             x = 0 | 
					
						
							|  |  |  |             for i in range(m): | 
					
						
							|  |  |  |                 for j in MyIter(n): | 
					
						
							|  |  |  |                     x += 1000*i + j | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         x = testfunc(TIER2_THRESHOLD, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(x, sum(range(TIER2_THRESHOLD)) * TIER2_THRESHOLD * 1001) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         self.assertIn("_FOR_ITER_TIER_TWO", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_confidence_score(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             bits = 0 | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 if i & 0x01: | 
					
						
							|  |  |  |                     bits += 1 | 
					
						
							|  |  |  |                 if i & 0x02: | 
					
						
							|  |  |  |                     bits += 1 | 
					
						
							|  |  |  |                 if i&0x04: | 
					
						
							|  |  |  |                     bits += 1 | 
					
						
							|  |  |  |                 if i&0x08: | 
					
						
							|  |  |  |                     bits += 1 | 
					
						
							|  |  |  |                 if i&0x10: | 
					
						
							|  |  |  |                     bits += 1 | 
					
						
							|  |  |  |             return bits | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         x = testfunc(TIER2_THRESHOLD * 2) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(x, TIER2_THRESHOLD * 5) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         ops = list(iter_opnames(ex)) | 
					
						
							| 
									
										
										
										
											2024-02-20 18:50:31 +00:00
										 |  |  |         #Since branch is 50/50 the trace could go either way. | 
					
						
							|  |  |  |         count = ops.count("_GUARD_IS_TRUE_POP") + ops.count("_GUARD_IS_FALSE_POP") | 
					
						
							|  |  |  |         self.assertLessEqual(count, 2) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 02:43:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-29 18:53:32 -08:00
										 |  |  | @requires_specialization | 
					
						
							| 
									
										
										
										
											2024-11-04 11:13:32 -08:00
										 |  |  | @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  | @requires_jit_enabled | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  | @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | class TestUopsOptimization(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |     def _run_with_optimizer(self, testfunc, arg): | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         res = testfunc(arg) | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         return res, ex | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |     def test_int_type_propagation(self): | 
					
						
							|  |  |  |         def testfunc(loops): | 
					
						
							|  |  |  |             num = 0 | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |             for i in range(loops): | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |                 x = num + num | 
					
						
							|  |  |  |                 a = x + 1 | 
					
						
							|  |  |  |                 num += 1 | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(res, (TIER2_THRESHOLD - 1) * 2 + 1) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] | 
					
						
							|  |  |  |         guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertGreaterEqual(len(binop_count), 3) | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_both_int_count), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_int_type_propagation_through_frame(self): | 
					
						
							|  |  |  |         def double(x): | 
					
						
							|  |  |  |             return x + x | 
					
						
							|  |  |  |         def testfunc(loops): | 
					
						
							|  |  |  |             num = 0 | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |             for i in range(loops): | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |                 x = num + num | 
					
						
							|  |  |  |                 a = double(x) | 
					
						
							|  |  |  |                 num += 1 | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         res = testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(res, (TIER2_THRESHOLD - 1) * 4) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] | 
					
						
							|  |  |  |         guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertGreaterEqual(len(binop_count), 3) | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_both_int_count), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_int_type_propagation_from_frame(self): | 
					
						
							|  |  |  |         def double(x): | 
					
						
							|  |  |  |             return x + x | 
					
						
							|  |  |  |         def testfunc(loops): | 
					
						
							|  |  |  |             num = 0 | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |             for i in range(loops): | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |                 a = double(num) | 
					
						
							|  |  |  |                 x = a + a | 
					
						
							|  |  |  |                 num += 1 | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         res = testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(res, (TIER2_THRESHOLD - 1) * 4) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] | 
					
						
							|  |  |  |         guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertGreaterEqual(len(binop_count), 3) | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_both_int_count), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_int_impure_region(self): | 
					
						
							|  |  |  |         def testfunc(loops): | 
					
						
							|  |  |  |             num = 0 | 
					
						
							|  |  |  |             while num < loops: | 
					
						
							|  |  |  |                 x = num + num | 
					
						
							|  |  |  |                 y = 1 | 
					
						
							|  |  |  |                 x // 2 | 
					
						
							|  |  |  |                 a = x + y | 
					
						
							|  |  |  |                 num += 1 | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertGreaterEqual(len(binop_count), 3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_call_py_exact_args(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             def dummy(x): | 
					
						
							|  |  |  |                 return x+1 | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 dummy(i) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIn("_PUSH_FRAME", uops) | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_ADD_INT", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_CHECK_PEP_523", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_int_type_propagate_through_range(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 x = i + i | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, (TIER2_THRESHOLD - 1) * 2) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertNotIn("_GUARD_BOTH_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_int_value_numbering(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             y = 1 | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 x = y | 
					
						
							|  |  |  |                 z = x | 
					
						
							|  |  |  |                 a = z | 
					
						
							|  |  |  |                 b = a | 
					
						
							|  |  |  |                 res = x + z + a + b | 
					
						
							|  |  |  |             return res | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertEqual(res, 4) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIn("_GUARD_BOTH_INT", uops) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         guard_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertEqual(len(guard_count), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_comprehension(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 return [i for i in range(n)] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, list(range(TIER2_THRESHOLD))) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         self.assertNotIn("_BINARY_OP_ADD_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_call_py_exact_args_disappearing(self): | 
					
						
							|  |  |  |         def dummy(x): | 
					
						
							|  |  |  |             return x+1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 dummy(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Trigger specialization | 
					
						
							|  |  |  |         testfunc(8) | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         del dummy | 
					
						
							|  |  |  |         gc.collect() | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         def dummy(x): | 
					
						
							|  |  |  |             return x + 2 | 
					
						
							|  |  |  |         testfunc(32) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         # Honestly as long as it doesn't crash it's fine. | 
					
						
							|  |  |  |         # Whether we get an executor or not is non-deterministic, | 
					
						
							|  |  |  |         # because it's decided by when the function is freed. | 
					
						
							|  |  |  |         # This test is a little implementation specific. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_promote_globals_to_constants(self): | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         result = script_helper.run_python_until_end('-c', textwrap.dedent("""
 | 
					
						
							|  |  |  |         import _testinternalcapi | 
					
						
							|  |  |  |         import opcode | 
					
						
							| 
									
										
										
										
											2024-03-23 22:32:33 +00:00
										 |  |  |         import _opcode | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def get_first_executor(func): | 
					
						
							|  |  |  |             code = func.__code__ | 
					
						
							|  |  |  |             co_code = code.co_code | 
					
						
							|  |  |  |             for i in range(0, len(co_code), 2): | 
					
						
							| 
									
										
										
										
											2024-03-23 22:32:33 +00:00
										 |  |  |                 try: | 
					
						
							|  |  |  |                     return _opcode.get_executor(code, i) | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     pass | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         def get_opnames(ex): | 
					
						
							|  |  |  |             return {item[0] for item in ex} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 x = range(i) | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         testfunc(_testinternalcapi.TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  |         assert ex is not None | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  |         assert "_LOAD_GLOBAL_BUILTINS" not in uops | 
					
						
							| 
									
										
										
										
											2025-01-27 16:24:48 +00:00
										 |  |  |         assert "_LOAD_CONST_INLINE_BORROW" in uops | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         """), PYTHON_JIT="1")
 | 
					
						
							| 
									
										
										
										
											2024-02-14 19:12:52 +08:00
										 |  |  |         self.assertEqual(result[0].rc, 0, result) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |     def test_float_add_constant_propagation(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1.0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							| 
									
										
										
										
											2024-03-02 03:40:04 +08:00
										 |  |  |                 a = a + 0.25 | 
					
						
							|  |  |  |                 a = a + 0.25 | 
					
						
							|  |  |  |                 a = a + 0.25 | 
					
						
							|  |  |  |                 a = a + 0.25 | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertAlmostEqual(res, TIER2_THRESHOLD + 1) | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |         self.assertLessEqual(len(guard_both_float_count), 1) | 
					
						
							|  |  |  |         # TODO gh-115506: this assertion may change after propagating constants. | 
					
						
							|  |  |  |         # We'll also need to verify that propagation actually occurs. | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_ADD_FLOAT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_float_subtract_constant_propagation(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1.0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							| 
									
										
										
										
											2024-03-02 03:40:04 +08:00
										 |  |  |                 a = a - 0.25 | 
					
						
							|  |  |  |                 a = a - 0.25 | 
					
						
							|  |  |  |                 a = a - 0.25 | 
					
						
							|  |  |  |                 a = a - 0.25 | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertAlmostEqual(res, -TIER2_THRESHOLD + 1) | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |         self.assertLessEqual(len(guard_both_float_count), 1) | 
					
						
							|  |  |  |         # TODO gh-115506: this assertion may change after propagating constants. | 
					
						
							|  |  |  |         # We'll also need to verify that propagation actually occurs. | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_SUBTRACT_FLOAT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_float_multiply_constant_propagation(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1.0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							| 
									
										
										
										
											2024-03-02 03:40:04 +08:00
										 |  |  |                 a = a * 1.0 | 
					
						
							|  |  |  |                 a = a * 1.0 | 
					
						
							|  |  |  |                 a = a * 1.0 | 
					
						
							|  |  |  |                 a = a * 1.0 | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-03-02 03:40:04 +08:00
										 |  |  |         self.assertAlmostEqual(res, 1.0) | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] | 
					
						
							| 
									
										
										
										
											2024-02-16 10:02:48 -08:00
										 |  |  |         self.assertLessEqual(len(guard_both_float_count), 1) | 
					
						
							|  |  |  |         # TODO gh-115506: this assertion may change after propagating constants. | 
					
						
							|  |  |  |         # We'll also need to verify that propagation actually occurs. | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_MULTIPLY_FLOAT", uops) | 
					
						
							| 
									
										
										
										
											2024-02-13 21:24:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-02 03:40:04 +08:00
										 |  |  |     def test_add_unicode_propagation(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = "" | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 a + a | 
					
						
							|  |  |  |                 a + a | 
					
						
							|  |  |  |                 a + a | 
					
						
							|  |  |  |                 a + a | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-03-02 03:40:04 +08:00
										 |  |  |         self.assertEqual(res, "") | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_both_unicode_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_UNICODE"] | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_both_unicode_count), 1) | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_ADD_UNICODE", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |     def test_compare_op_type_propagation_float(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1.0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |         self.assertTrue(res) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |         self.assertLessEqual(len(guard_both_float_count), 1) | 
					
						
							|  |  |  |         self.assertIn("_COMPARE_OP_FLOAT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_compare_op_type_propagation_int(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |         self.assertTrue(res) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-04-22 13:34:06 +01:00
										 |  |  |         guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_both_int_count), 1) | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |         self.assertIn("_COMPARE_OP_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 13:34:06 +01:00
										 |  |  |     def test_compare_op_type_propagation_int_partial(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 if a > 2: | 
					
						
							|  |  |  |                     x = 0 | 
					
						
							|  |  |  |                 if a < 2: | 
					
						
							|  |  |  |                     x = 1 | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-04-22 13:34:06 +01:00
										 |  |  |         self.assertEqual(res, 1) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_left_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_NOS_INT"] | 
					
						
							|  |  |  |         guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_left_int_count), 1) | 
					
						
							|  |  |  |         self.assertEqual(len(guard_both_int_count), 0) | 
					
						
							|  |  |  |         self.assertIn("_COMPARE_OP_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_compare_op_type_propagation_float_partial(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 1.0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 if a > 2.0: | 
					
						
							|  |  |  |                     x = 0 | 
					
						
							|  |  |  |                 if a < 2.0: | 
					
						
							|  |  |  |                     x = 1 | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-04-22 13:34:06 +01:00
										 |  |  |         self.assertEqual(res, 1) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_left_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_NOS_FLOAT"] | 
					
						
							|  |  |  |         guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"] | 
					
						
							|  |  |  |         self.assertLessEqual(len(guard_left_float_count), 1) | 
					
						
							|  |  |  |         self.assertEqual(len(guard_both_float_count), 0) | 
					
						
							|  |  |  |         self.assertIn("_COMPARE_OP_FLOAT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |     def test_compare_op_type_propagation_unicode(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = "" | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |                 x = a == a | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |         self.assertTrue(res) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-20 12:24:35 -08:00
										 |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_UNICODE"] | 
					
						
							| 
									
										
										
										
											2024-02-20 19:30:49 +08:00
										 |  |  |         self.assertLessEqual(len(guard_both_float_count), 1) | 
					
						
							|  |  |  |         self.assertIn("_COMPARE_OP_STR", uops) | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  |     def test_type_inconsistency(self): | 
					
						
							| 
									
										
										
										
											2024-02-28 15:56:58 -08:00
										 |  |  |         ns = {} | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         src = textwrap.dedent("""
 | 
					
						
							| 
									
										
										
										
											2024-02-28 15:56:58 -08:00
										 |  |  |             def testfunc(n): | 
					
						
							|  |  |  |                 for i in range(n): | 
					
						
							|  |  |  |                     x = _test_global + _test_global | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         """)
 | 
					
						
							|  |  |  |         exec(src, ns, ns) | 
					
						
							| 
									
										
										
										
											2024-02-28 15:56:58 -08:00
										 |  |  |         testfunc = ns['testfunc'] | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         ns['_test_global'] = 0 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  |         self.assertIsNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         ns['_test_global'] = 1 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         uops = get_opnames(ex) | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         self.assertNotIn("_GUARD_BOTH_INT", uops) | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  |         self.assertIn("_BINARY_OP_ADD_INT", uops) | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         # Try again, but between the runs, set the global to a float. | 
					
						
							|  |  |  |         # This should result in no executor the second time. | 
					
						
							|  |  |  |         ns = {} | 
					
						
							|  |  |  |         exec(src, ns, ns) | 
					
						
							|  |  |  |         testfunc = ns['testfunc'] | 
					
						
							|  |  |  |         ns['_test_global'] = 0 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         self.assertIsNone(ex) | 
					
						
							|  |  |  |         ns['_test_global'] = 3.14 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD - 1) | 
					
						
							| 
									
										
										
										
											2024-02-29 10:55:29 -08:00
										 |  |  |         self.assertIsNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |     def test_combine_stack_space_checks_sequential(self): | 
					
						
							|  |  |  |         def dummy12(x): | 
					
						
							|  |  |  |             return x - 1 | 
					
						
							|  |  |  |         def dummy13(y): | 
					
						
							|  |  |  |             z = y + 2 | 
					
						
							|  |  |  |             return y, z | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 b = dummy12(7) | 
					
						
							|  |  |  |                 c, d = dummy13(9) | 
					
						
							|  |  |  |                 a += b + c + d | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 26) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) | 
					
						
							| 
									
										
										
										
											2024-06-17 14:40:11 +01:00
										 |  |  |         self.assertEqual(uop_names.count("_RETURN_VALUE"), 2) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  |         # sequential calls: max(12, 13) == 13 | 
					
						
							|  |  |  |         largest_stack = _testinternalcapi.get_co_framesize(dummy13.__code__) | 
					
						
							|  |  |  |         self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_combine_stack_space_checks_nested(self): | 
					
						
							|  |  |  |         def dummy12(x): | 
					
						
							|  |  |  |             return x + 3 | 
					
						
							|  |  |  |         def dummy15(y): | 
					
						
							|  |  |  |             z = dummy12(y) | 
					
						
							|  |  |  |             return y, z | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 b, c = dummy15(2) | 
					
						
							|  |  |  |                 a += b + c | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 7) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) | 
					
						
							| 
									
										
										
										
											2024-06-17 14:40:11 +01:00
										 |  |  |         self.assertEqual(uop_names.count("_RETURN_VALUE"), 2) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  |         # nested calls: 15 + 12 == 27 | 
					
						
							|  |  |  |         largest_stack = ( | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy15.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy12.__code__) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_combine_stack_space_checks_several_calls(self): | 
					
						
							|  |  |  |         def dummy12(x): | 
					
						
							|  |  |  |             return x + 3 | 
					
						
							|  |  |  |         def dummy13(y): | 
					
						
							|  |  |  |             z = y + 2 | 
					
						
							|  |  |  |             return y, z | 
					
						
							|  |  |  |         def dummy18(y): | 
					
						
							|  |  |  |             z = dummy12(y) | 
					
						
							|  |  |  |             x, w = dummy13(z) | 
					
						
							|  |  |  |             return z, x, w | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 b = dummy12(5) | 
					
						
							|  |  |  |                 c, d, e = dummy18(2) | 
					
						
							|  |  |  |                 a += b + c + d + e | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 25) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 4) | 
					
						
							| 
									
										
										
										
											2024-06-17 14:40:11 +01:00
										 |  |  |         self.assertEqual(uop_names.count("_RETURN_VALUE"), 4) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  |         # max(12, 18 + max(12, 13)) == 31 | 
					
						
							|  |  |  |         largest_stack = ( | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy18.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy13.__code__) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_combine_stack_space_checks_several_calls_different_order(self): | 
					
						
							|  |  |  |         # same as `several_calls` but with top-level calls reversed | 
					
						
							|  |  |  |         def dummy12(x): | 
					
						
							|  |  |  |             return x + 3 | 
					
						
							|  |  |  |         def dummy13(y): | 
					
						
							|  |  |  |             z = y + 2 | 
					
						
							|  |  |  |             return y, z | 
					
						
							|  |  |  |         def dummy18(y): | 
					
						
							|  |  |  |             z = dummy12(y) | 
					
						
							|  |  |  |             x, w = dummy13(z) | 
					
						
							|  |  |  |             return z, x, w | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 c, d, e = dummy18(2) | 
					
						
							|  |  |  |                 b = dummy12(5) | 
					
						
							|  |  |  |                 a += b + c + d + e | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 25) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 4) | 
					
						
							| 
									
										
										
										
											2024-06-17 14:40:11 +01:00
										 |  |  |         self.assertEqual(uop_names.count("_RETURN_VALUE"), 4) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  |         # max(18 + max(12, 13), 12) == 31 | 
					
						
							|  |  |  |         largest_stack = ( | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy18.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy13.__code__) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_combine_stack_space_complex(self): | 
					
						
							|  |  |  |         def dummy0(x): | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  |         def dummy1(x): | 
					
						
							|  |  |  |             return dummy0(x) | 
					
						
							|  |  |  |         def dummy2(x): | 
					
						
							|  |  |  |             return dummy1(x) | 
					
						
							|  |  |  |         def dummy3(x): | 
					
						
							|  |  |  |             return dummy0(x) | 
					
						
							|  |  |  |         def dummy4(x): | 
					
						
							|  |  |  |             y = dummy0(x) | 
					
						
							|  |  |  |             return dummy3(y) | 
					
						
							|  |  |  |         def dummy5(x): | 
					
						
							|  |  |  |             return dummy2(x) | 
					
						
							|  |  |  |         def dummy6(x): | 
					
						
							|  |  |  |             y = dummy5(x) | 
					
						
							|  |  |  |             z = dummy0(y) | 
					
						
							|  |  |  |             return dummy4(z) | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |                 b = dummy5(1) | 
					
						
							|  |  |  |                 c = dummy0(1) | 
					
						
							|  |  |  |                 d = dummy6(1) | 
					
						
							|  |  |  |                 a += b + c + d | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 3) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 15) | 
					
						
							| 
									
										
										
										
											2024-06-17 14:40:11 +01:00
										 |  |  |         self.assertEqual(uop_names.count("_RETURN_VALUE"), 15) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  |         largest_stack = ( | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy6.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy5.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy2.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy1.__code__) + | 
					
						
							|  |  |  |             _testinternalcapi.get_co_framesize(dummy0.__code__) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertIn( | 
					
						
							|  |  |  |             ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_combine_stack_space_checks_large_framesize(self): | 
					
						
							|  |  |  |         # Create a function with a large framesize. This ensures _CHECK_STACK_SPACE is | 
					
						
							|  |  |  |         # actually doing its job. Note that the resulting trace hits | 
					
						
							|  |  |  |         # UOP_MAX_TRACE_LENGTH, but since all _CHECK_STACK_SPACEs happen early, this | 
					
						
							|  |  |  |         # test is still meaningful. | 
					
						
							|  |  |  |         repetitions = 10000 | 
					
						
							|  |  |  |         ns = {} | 
					
						
							|  |  |  |         header = """
 | 
					
						
							|  |  |  |             def dummy_large(a0): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         body = "".join([f"""
 | 
					
						
							|  |  |  |                 a{n+1} = a{n} + 1 | 
					
						
							|  |  |  |         """ for n in range(repetitions)])
 | 
					
						
							|  |  |  |         return_ = f"""
 | 
					
						
							|  |  |  |                 return a{repetitions-1} | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         exec(textwrap.dedent(header + body + return_), ns, ns) | 
					
						
							|  |  |  |         dummy_large = ns['dummy_large'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # this is something like: | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # def dummy_large(a0): | 
					
						
							|  |  |  |         #     a1 = a0 + 1 | 
					
						
							|  |  |  |         #     a2 = a1 + 1 | 
					
						
							|  |  |  |         #     .... | 
					
						
							|  |  |  |         #     a9999 = a9998 + 1 | 
					
						
							|  |  |  |         #     return a9999 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def dummy15(z): | 
					
						
							|  |  |  |             y = dummy_large(z) | 
					
						
							|  |  |  |             return y + 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             b = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 b += dummy15(7) | 
					
						
							|  |  |  |             return b | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * (repetitions + 9)) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # this hits a different case during trace projection in refcount test runs only, | 
					
						
							|  |  |  |         # so we need to account for both possibilities | 
					
						
							|  |  |  |         self.assertIn(uop_names.count("_CHECK_STACK_SPACE"), [0, 1]) | 
					
						
							|  |  |  |         if uop_names.count("_CHECK_STACK_SPACE") == 0: | 
					
						
							|  |  |  |             largest_stack = ( | 
					
						
							|  |  |  |                 _testinternalcapi.get_co_framesize(dummy15.__code__) + | 
					
						
							|  |  |  |                 _testinternalcapi.get_co_framesize(dummy_large.__code__) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             largest_stack = _testinternalcapi.get_co_framesize(dummy15.__code__) | 
					
						
							|  |  |  |         self.assertIn( | 
					
						
							|  |  |  |             ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_combine_stack_space_checks_recursion(self): | 
					
						
							|  |  |  |         def dummy15(x): | 
					
						
							|  |  |  |             while x > 0: | 
					
						
							|  |  |  |                 return dummy15(x - 1) | 
					
						
							|  |  |  |             return 42 | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 a += dummy15(n) | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         recursion_limit = sys.getrecursionlimit() | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             sys.setrecursionlimit(TIER2_THRESHOLD + recursion_limit) | 
					
						
							|  |  |  |             res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             sys.setrecursionlimit(recursion_limit) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 42) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uops_and_operands = [(opcode, operand) for opcode, _, _, operand in ex] | 
					
						
							|  |  |  |         uop_names = [uop[0] for uop in uops_and_operands] | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) | 
					
						
							| 
									
										
										
										
											2024-06-17 14:40:11 +01:00
										 |  |  |         self.assertEqual(uop_names.count("_RETURN_VALUE"), 0) | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 1) | 
					
						
							|  |  |  |         self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) | 
					
						
							|  |  |  |         largest_stack = _testinternalcapi.get_co_framesize(dummy15.__code__) | 
					
						
							|  |  |  |         self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-24 06:19:17 +08:00
										 |  |  |     def test_many_nested(self): | 
					
						
							|  |  |  |         # overflow the trace_stack | 
					
						
							|  |  |  |         def dummy_a(x): | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  |         def dummy_b(x): | 
					
						
							|  |  |  |             return dummy_a(x) | 
					
						
							|  |  |  |         def dummy_c(x): | 
					
						
							|  |  |  |             return dummy_b(x) | 
					
						
							|  |  |  |         def dummy_d(x): | 
					
						
							|  |  |  |             return dummy_c(x) | 
					
						
							|  |  |  |         def dummy_e(x): | 
					
						
							|  |  |  |             return dummy_d(x) | 
					
						
							|  |  |  |         def dummy_f(x): | 
					
						
							|  |  |  |             return dummy_e(x) | 
					
						
							|  |  |  |         def dummy_g(x): | 
					
						
							|  |  |  |             return dummy_f(x) | 
					
						
							|  |  |  |         def dummy_h(x): | 
					
						
							|  |  |  |             return dummy_g(x) | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             a = 0 | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 a += dummy_h(n) | 
					
						
							|  |  |  |             return a | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 10:14:18 -07:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, 32) | 
					
						
							|  |  |  |         self.assertEqual(res, 32 * 32) | 
					
						
							|  |  |  |         self.assertIsNone(ex) | 
					
						
							| 
									
										
										
										
											2024-02-28 14:38:01 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-25 11:32:47 +01:00
										 |  |  |     def test_return_generator(self): | 
					
						
							|  |  |  |         def gen(): | 
					
						
							|  |  |  |             yield None | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 gen() | 
					
						
							|  |  |  |             return i | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, TIER2_THRESHOLD - 1) | 
					
						
							| 
									
										
										
										
											2024-04-25 11:32:47 +01:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         self.assertIn("_RETURN_GENERATOR", get_opnames(ex)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-26 18:08:50 +01:00
										 |  |  |     def test_for_iter_gen(self): | 
					
						
							|  |  |  |         def gen(n): | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 yield i | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             g = gen(n) | 
					
						
							|  |  |  |             s = 0 | 
					
						
							|  |  |  |             for i in g: | 
					
						
							|  |  |  |                 s += i | 
					
						
							|  |  |  |             return s | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, sum(range(TIER2_THRESHOLD))) | 
					
						
							| 
									
										
										
										
											2024-04-26 18:08:50 +01:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         self.assertIn("_FOR_ITER_GEN_FRAME", get_opnames(ex)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 22:21:06 +01:00
										 |  |  |     def test_modified_local_is_seen_by_optimized_code(self): | 
					
						
							|  |  |  |         l = sys._getframe().f_locals | 
					
						
							|  |  |  |         a = 1 | 
					
						
							|  |  |  |         s = 0 | 
					
						
							|  |  |  |         for j in range(1 << 10): | 
					
						
							|  |  |  |             a + a | 
					
						
							|  |  |  |             l["xa"[j >> 9]] = 1.0 | 
					
						
							|  |  |  |             s += a | 
					
						
							|  |  |  |         self.assertIs(type(a), float) | 
					
						
							|  |  |  |         self.assertIs(type(s), float) | 
					
						
							|  |  |  |         self.assertEqual(s, 1024.0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |     def test_guard_type_version_removed(self): | 
					
						
							|  |  |  |         def thing(a): | 
					
						
							|  |  |  |             x = 0 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |             for _ in range(TIER2_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 x += a.attr | 
					
						
							|  |  |  |                 x += a.attr | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Foo: | 
					
						
							|  |  |  |             attr = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res, ex = self._run_with_optimizer(thing, Foo()) | 
					
						
							|  |  |  |         opnames = list(iter_opnames(ex)) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 2) | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |         guard_type_version_count = opnames.count("_GUARD_TYPE_VERSION") | 
					
						
							|  |  |  |         self.assertEqual(guard_type_version_count, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_guard_type_version_removed_inlined(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Verify that the guard type version if we have an inlined function | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def fn(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def thing(a): | 
					
						
							|  |  |  |             x = 0 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |             for _ in range(TIER2_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 x += a.attr | 
					
						
							|  |  |  |                 fn() | 
					
						
							|  |  |  |                 x += a.attr | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Foo: | 
					
						
							|  |  |  |             attr = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res, ex = self._run_with_optimizer(thing, Foo()) | 
					
						
							|  |  |  |         opnames = list(iter_opnames(ex)) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 2) | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |         guard_type_version_count = opnames.count("_GUARD_TYPE_VERSION") | 
					
						
							|  |  |  |         self.assertEqual(guard_type_version_count, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |     def test_guard_type_version_removed_invalidation(self): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def thing(a): | 
					
						
							|  |  |  |             x = 0 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |             for i in range(TIER2_THRESHOLD * 2 + 1): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 x += a.attr | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |                 # The first TIER2_THRESHOLD iterations we set the attribute on | 
					
						
							|  |  |  |                 # this dummy class, which shouldn't trigger the type watcher. | 
					
						
							|  |  |  |                 # Note that the code needs to be in this weird form so it's | 
					
						
							|  |  |  |                 # optimized inline without any control flow: | 
					
						
							|  |  |  |                 setattr((Bar, Foo)[i == TIER2_THRESHOLD + 1], "attr", 2) | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 x += a.attr | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Foo: | 
					
						
							|  |  |  |             attr = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Bar: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res, ex = self._run_with_optimizer(thing, Foo()) | 
					
						
							|  |  |  |         opnames = list(iter_opnames(ex)) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 6 + 1) | 
					
						
							|  |  |  |         call = opnames.index("_CALL_BUILTIN_FAST") | 
					
						
							|  |  |  |         load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call) | 
					
						
							|  |  |  |         load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call) | 
					
						
							|  |  |  |         self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1) | 
					
						
							|  |  |  |         self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1) | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |     def test_guard_type_version_removed_escaping(self): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def thing(a): | 
					
						
							|  |  |  |             x = 0 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |             for i in range(TIER2_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 x += a.attr | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |                 # eval should be escaping | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 eval("None") | 
					
						
							|  |  |  |                 x += a.attr | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Foo: | 
					
						
							|  |  |  |             attr = 1 | 
					
						
							|  |  |  |         res, ex = self._run_with_optimizer(thing, Foo()) | 
					
						
							|  |  |  |         opnames = list(iter_opnames(ex)) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							| 
									
										
										
										
											2024-11-20 08:11:25 -08:00
										 |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 2) | 
					
						
							|  |  |  |         call = opnames.index("_CALL_BUILTIN_FAST_WITH_KEYWORDS") | 
					
						
							|  |  |  |         load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call) | 
					
						
							|  |  |  |         load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call) | 
					
						
							|  |  |  |         self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1) | 
					
						
							|  |  |  |         self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 1) | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_guard_type_version_executor_invalidated(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Verify that the executor is invalided on a type change. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def thing(a): | 
					
						
							|  |  |  |             x = 0 | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |             for i in range(TIER2_THRESHOLD): | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |                 x += a.attr | 
					
						
							|  |  |  |                 x += a.attr | 
					
						
							|  |  |  |             return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Foo: | 
					
						
							|  |  |  |             attr = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res, ex = self._run_with_optimizer(thing, Foo()) | 
					
						
							| 
									
										
										
										
											2024-11-18 11:11:23 -08:00
										 |  |  |         self.assertEqual(res, TIER2_THRESHOLD * 2) | 
					
						
							| 
									
										
										
										
											2024-06-08 05:41:45 -04:00
										 |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         self.assertEqual(list(iter_opnames(ex)).count("_GUARD_TYPE_VERSION"), 1) | 
					
						
							|  |  |  |         self.assertTrue(ex.is_valid()) | 
					
						
							|  |  |  |         Foo.attr = 0 | 
					
						
							|  |  |  |         self.assertFalse(ex.is_valid()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_type_version_doesnt_segfault(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Tests that setting a type version doesn't cause a segfault when later looking at the stack. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Minimized from mdp.py benchmark | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class A: | 
					
						
							|  |  |  |             def __init__(self): | 
					
						
							|  |  |  |                 self.attr = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def method(self, arg): | 
					
						
							|  |  |  |                 self.attr[arg] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def fn(a): | 
					
						
							|  |  |  |             for _ in range(100): | 
					
						
							|  |  |  |                 (_ for _ in []) | 
					
						
							|  |  |  |                 (_ for _ in [a.method(None)]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fn(A()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-09 11:35:33 +08:00
										 |  |  |     def test_func_guards_removed_or_reduced(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for i in range(n): | 
					
						
							|  |  |  |                 # Only works on functions promoted to constants | 
					
						
							|  |  |  |                 global_identity(i) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |         testfunc(TIER2_THRESHOLD) | 
					
						
							| 
									
										
										
										
											2024-11-09 11:35:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ex = get_first_executor(testfunc) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         self.assertIn("_PUSH_FRAME", uops) | 
					
						
							|  |  |  |         # Strength reduced version | 
					
						
							|  |  |  |         self.assertIn("_CHECK_FUNCTION_VERSION_INLINE", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_CHECK_FUNCTION_VERSION", uops) | 
					
						
							|  |  |  |         # Removed guard | 
					
						
							|  |  |  |         self.assertNotIn("_CHECK_FUNCTION_EXACT_ARGS", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 10:48:27 +00:00
										 |  |  |     def test_jit_error_pops(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Tests that the correct number of pops are inserted into the | 
					
						
							|  |  |  |         exit stub | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         items = 17 * [None] + [[]] | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             {item for item in items} | 
					
						
							| 
									
										
										
										
											2024-05-06 22:21:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-07 17:25:48 -08:00
										 |  |  |     def test_power_type_depends_on_input_values(self): | 
					
						
							|  |  |  |         template = textwrap.dedent("""
 | 
					
						
							|  |  |  |             import _testinternalcapi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             L, R, X, Y = {l}, {r}, {x}, {y} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def check(actual: complex, expected: complex) -> None: | 
					
						
							|  |  |  |                 assert actual == expected, (actual, expected) | 
					
						
							|  |  |  |                 assert type(actual) is type(expected), (actual, expected) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def f(l: complex, r: complex) -> None: | 
					
						
							|  |  |  |                 expected_local_local = pow(l, r) + pow(l, r) | 
					
						
							|  |  |  |                 expected_const_local = pow(L, r) + pow(L, r) | 
					
						
							|  |  |  |                 expected_local_const = pow(l, R) + pow(l, R) | 
					
						
							|  |  |  |                 expected_const_const = pow(L, R) + pow(L, R) | 
					
						
							|  |  |  |                 for _ in range(_testinternalcapi.TIER2_THRESHOLD): | 
					
						
							|  |  |  |                     # Narrow types: | 
					
						
							|  |  |  |                     l + l, r + r | 
					
						
							|  |  |  |                     # The powers produce results, and the addition is unguarded: | 
					
						
							|  |  |  |                     check(l ** r + l ** r, expected_local_local) | 
					
						
							|  |  |  |                     check(L ** r + L ** r, expected_const_local) | 
					
						
							|  |  |  |                     check(l ** R + l ** R, expected_local_const) | 
					
						
							|  |  |  |                     check(L ** R + L ** R, expected_const_const) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # JIT for one pair of values... | 
					
						
							|  |  |  |             f(L, R) | 
					
						
							|  |  |  |             # ...then run with another: | 
					
						
							|  |  |  |             f(X, Y) | 
					
						
							|  |  |  |         """)
 | 
					
						
							|  |  |  |         interesting = [ | 
					
						
							|  |  |  |             (1, 1),  # int ** int -> int | 
					
						
							|  |  |  |             (1, -1),  # int ** int -> float | 
					
						
							|  |  |  |             (1.0, 1),  # float ** int -> float | 
					
						
							|  |  |  |             (1, 1.0),  # int ** float -> float | 
					
						
							|  |  |  |             (-1, 0.5),  # int ** float -> complex | 
					
						
							|  |  |  |             (1.0, 1.0),  # float ** float -> float | 
					
						
							|  |  |  |             (-1.0, 0.5),  # float ** float -> complex | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         for (l, r), (x, y) in itertools.product(interesting, repeat=2): | 
					
						
							|  |  |  |             s = template.format(l=l, r=r, x=x, y=y) | 
					
						
							|  |  |  |             with self.subTest(l=l, r=r, x=x, y=y): | 
					
						
							|  |  |  |                 script_helper.assert_python_ok("-c", s) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-20 15:49:15 +00:00
										 |  |  |     def test_symbols_flow_through_tuples(self): | 
					
						
							|  |  |  |         def testfunc(n): | 
					
						
							|  |  |  |             for _ in range(n): | 
					
						
							|  |  |  |                 a = 1 | 
					
						
							|  |  |  |                 b = 2 | 
					
						
							|  |  |  |                 t = a, b | 
					
						
							|  |  |  |                 x, y = t | 
					
						
							|  |  |  |                 r = x + y | 
					
						
							|  |  |  |             return r | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) | 
					
						
							|  |  |  |         self.assertEqual(res, 3) | 
					
						
							|  |  |  |         self.assertIsNotNone(ex) | 
					
						
							|  |  |  |         uops = get_opnames(ex) | 
					
						
							|  |  |  |         self.assertIn("_BINARY_OP_ADD_INT", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_GUARD_BOTH_INT", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_GUARD_NOS_INT", uops) | 
					
						
							|  |  |  |         self.assertNotIn("_GUARD_TOS_INT", uops) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-13 11:42:45 +00:00
										 |  |  |     def test_decref_escapes(self): | 
					
						
							|  |  |  |         class Convert9999ToNone: | 
					
						
							|  |  |  |             def __del__(self): | 
					
						
							|  |  |  |                 ns = sys._getframe(1).f_locals | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |                 if ns["i"] == _testinternalcapi.TIER2_THRESHOLD: | 
					
						
							| 
									
										
										
										
											2025-01-13 11:42:45 +00:00
										 |  |  |                     ns["i"] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def crash_addition(): | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2025-01-28 16:10:51 -08:00
										 |  |  |                 for i in range(_testinternalcapi.TIER2_THRESHOLD + 1): | 
					
						
							| 
									
										
										
										
											2025-01-13 11:42:45 +00:00
										 |  |  |                     n = Convert9999ToNone() | 
					
						
							|  |  |  |                     i + i  # Remove guards for i. | 
					
						
							|  |  |  |                     n = None  # Change i. | 
					
						
							|  |  |  |                     i + i  # This crashed when we didn't treat DECREF as escaping (gh-124483) | 
					
						
							|  |  |  |             except TypeError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         crash_addition() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-09 11:35:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | def global_identity(x): | 
					
						
							|  |  |  |     return x | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-13 13:49:29 -08:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |