diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 6c26259cf..77193be12 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -87,7 +87,7 @@ cellvars: () freevars: () nlocals: 0 flags: 67108867 -consts: ("'doc string'", 'None') +consts: ("'doc string'",) >>> def keywordonly_args(a,b,*,k1): ... return a,b,k1 @@ -161,7 +161,7 @@ cellvars: () freevars: () nlocals: 3 flags: 67108995 -consts: ("'This is a docstring from async function'", 'None') +consts: ("'This is a docstring from async function'",) >>> def no_docstring(x, y, z): ... return x + "hello" + y + z + "world" @@ -423,14 +423,6 @@ class CodeTest(unittest.TestCase): new_code = code = func.__code__.replace(co_linetable=b'') self.assertEqual(list(new_code.co_lines()), []) - @unittest.expectedFailure # TODO: RUSTPYTHON; co_lnotab intentionally not implemented (deprecated since 3.12) - def test_co_lnotab_is_deprecated(self): # TODO: remove in 3.14 - def func(): - pass - - with self.assertWarns(DeprecationWarning): - func.__code__.co_lnotab - @unittest.skipIf(_testinternalcapi is None, '_testinternalcapi is missing') def test_returns_only_none(self): value = True @@ -540,7 +532,7 @@ class CodeTest(unittest.TestCase): ], [ ("PUSH_EXC_INFO", None), - ("LOAD_CONST", None), # artificial 'None' + ("LOAD_COMMON_CONSTANT", None), # artificial 'None' ("STORE_NAME", "e"), # XX: we know the location for this ("DELETE_NAME", "e"), ("RERAISE", 1), @@ -1165,6 +1157,22 @@ class CodeTest(unittest.TestCase): with self.assertRaises(Exception): _testinternalcapi.verify_stateless_code(func) + def test_code_richcompare_raise_exception(self): + class BadStr(str): + def __eq__(self, _): + raise RuntimeError("Poison!") + + __hash__ = str.__hash__ + + c1 = compile("pass", "test", "exec") + c2 = c1.replace(co_name=BadStr("poison")) + c3 = compile("pass", "poison", "exec") + with self.assertRaises(RuntimeError): + c2 == c3 + + @unittest.expectedFailure # TODO: RUSTPYTHON; co_lnotab intentionally not implemented (deprecated since 3.12) + def test_co_lnotab_is_deprecated(self): + return super().test_co_lnotab_is_deprecated() def isinterned(s): return s is sys.intern(('_' + s + '_')[1:-1]) @@ -1438,6 +1446,7 @@ class CodeLocationTest(unittest.TestCase): co_code=bytes( [ dis.opmap["RESUME"], 0, + dis.opmap["CACHE"], 0, dis.opmap["LOAD_COMMON_CONSTANT"], 0, dis.opmap["RAISE_VARARGS"], 1, ] @@ -1446,7 +1455,7 @@ class CodeLocationTest(unittest.TestCase): [ (1 << 7) | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3) - | (3 - 1), + | (4 - 1), 0, ] ), @@ -1454,7 +1463,7 @@ class CodeLocationTest(unittest.TestCase): self.assertRaises(AssertionError, f) self.assertEqual( list(f.__code__.co_positions()), - 3 * [(42, 42, None, None)], + 4 * [(42, 42, None, None)], ) @cpython_only diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 021c36225..d279851e7 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -724,8 +724,7 @@ class TestSpecifics(unittest.TestCase): @support.cpython_only @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") - @support.run_with_limited_c_stack( - 100_000 if sys.platform == "android" else 500_000) + @support.skip_if_huge_c_stack(100_000 if sys.platform == "android" else 500_000) @support.skip_emscripten_stack_overflow() def test_compiler_recursion_limit(self): # Compiler frames are small @@ -841,8 +840,10 @@ class TestSpecifics(unittest.TestCase): else: return "unused" - self.assertEqual(f.__code__.co_consts, - (f.__doc__, "used")) + if f.__doc__ is None: + self.assertEqual(f.__code__.co_consts, (True, "used")) + else: + self.assertEqual(f.__code__.co_consts, (f.__doc__, "used")) @support.cpython_only def test_remove_unused_consts_no_docstring(self): @@ -887,7 +888,11 @@ class TestSpecifics(unittest.TestCase): def f1(): "docstring" return 42 - self.assertEqual(f1.__code__.co_consts, (f1.__doc__,)) + + if f1.__doc__ is None: + self.assertEqual(f1.__code__.co_consts, (42,)) + else: + self.assertEqual(f1.__code__.co_consts, (f1.__doc__,)) # This is a regression test for a CPython specific peephole optimizer # implementation bug present in a few releases. It's assertion verifies @@ -1294,7 +1299,7 @@ class TestSpecifics(unittest.TestCase): x in y) - genexp_lines = [0, 4, 2, 0, 4] + genexp_lines = [4, 0, 4, 2, 0, 4] genexp_code = return_genexp.__code__.co_consts[0] code_lines = self.get_code_lines(genexp_code) @@ -1629,6 +1634,17 @@ class TestSpecifics(unittest.TestCase): def f(): a if (1 if b else c) else d + def test_lineno_propagation_empty_blocks(self): + # Smoke test. See gh-138714. + def f(): + while name: + try: + break + except: + pass + else: + 1 if 1 else 1 + def test_global_declaration_in_except_used_in_else(self): # See gh-111123 code = textwrap.dedent("""\ @@ -1733,6 +1749,30 @@ class TestSpecifics(unittest.TestCase): self.assertEqual(wm.category, SyntaxWarning) self.assertIn("\"is\" with 'int' literal", str(wm.message)) + def test_filter_syntax_warnings_by_module(self): + filename = support.findfile('test_import/data/syntax_warnings.py') + with open(filename, 'rb') as f: + source = f.read() + module_re = r'test\.test_import\.data\.syntax_warnings\z' + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=module_re) + compile(source, filename, 'exec') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + + with warnings.catch_warnings(record=True) as wlog: + warnings.simplefilter('error') + warnings.filterwarnings('always', module=r'package\.module\z') + warnings.filterwarnings('error', module=module_re) + compile(source, filename, 'exec', module='package.module') + self.assertEqual(sorted(wm.lineno for wm in wlog), [4, 7, 10, 13, 14, 21]) + for wm in wlog: + self.assertEqual(wm.filename, filename) + self.assertIs(wm.category, SyntaxWarning) + @support.subTests('src', [ textwrap.dedent(""" def f(): @@ -2419,8 +2459,8 @@ class TestSourcePositions(unittest.TestCase): for i, pos in enumerate(positions): with self.subTest(i=i, pos=pos): start_line, end_line, start_col, end_col = pos - if i == 0 and start_col == end_col == 0: - # ignore the RESUME in the beginning + if i <= 1: + # ignore the RESUME and CACHE in the beginning continue self.assertEqual(start_line, 1) self.assertEqual(end_line, 1) @@ -2446,12 +2486,13 @@ class TestSourcePositions(unittest.TestCase): start_line, end_line, _, _ = instr.positions self.assertEqual(start_line, end_line) - # Expect four `LOAD_CONST None` instructions: + # Expect four `None`-loading instructions: # three for the no-exception __exit__ call, and one for the return. # They should all have the locations of the context manager ('xyz'). load_none = [instr for instr in dis.get_instructions(f) if - instr.opname == 'LOAD_CONST' and instr.argval is None] + instr.opname in ('LOAD_CONST', 'LOAD_COMMON_CONSTANT') + and instr.argval is None] return_value = [instr for instr in dis.get_instructions(f) if instr.opname == 'RETURN_VALUE'] diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 190374fba..a103601a2 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -56,7 +56,7 @@ dis_c_instance_method = """\ COMPARE_OP 72 (==) LOAD_FAST_BORROW 0 (self) STORE_ATTR 0 (x) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ % (_C.__init__.__code__.co_firstlineno, _C.__init__.__code__.co_firstlineno + 1,) @@ -67,7 +67,7 @@ dis_c_instance_method_bytes = """\ COMPARE_OP 72 (==) LOAD_FAST_BORROW 0 STORE_ATTR 0 - LOAD_CONST 1 + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -79,7 +79,7 @@ dis_c_class_method = """\ COMPARE_OP 72 (==) LOAD_FAST_BORROW 0 (cls) STORE_ATTR 0 (x) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ % (_C.cm.__code__.co_firstlineno, _C.cm.__code__.co_firstlineno + 2,) @@ -90,7 +90,7 @@ dis_c_static_method = """\ LOAD_SMALL_INT 1 COMPARE_OP 72 (==) STORE_FAST 0 (x) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) @@ -127,13 +127,13 @@ dis_f = """\ dis_f_with_offsets = """\ %3d 0 RESUME 0 -%3d 2 LOAD_GLOBAL 1 (print + NULL) - 12 LOAD_FAST_BORROW 0 (a) - 14 CALL 1 - 22 POP_TOP +%3d 4 LOAD_GLOBAL 1 (print + NULL) + 14 LOAD_FAST_BORROW 0 (a) + 16 CALL 1 + 24 POP_TOP -%3d 24 LOAD_SMALL_INT 1 - 26 RETURN_VALUE +%3d 26 LOAD_SMALL_INT 1 + 28 RETURN_VALUE """ % (_f.__code__.co_firstlineno, _f.__code__.co_firstlineno + 1, _f.__code__.co_firstlineno + 2) @@ -174,7 +174,7 @@ dis_bug708901 = """\ %3d LOAD_SMALL_INT 10 %3d CALL 2 - GET_ITER + GET_ITER 0 L1: FOR_ITER 3 (to L2) STORE_FAST 0 (res) @@ -182,7 +182,7 @@ dis_bug708901 = """\ %3d L2: END_FOR POP_ITER - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ % (bug708901.__code__.co_firstlineno, bug708901.__code__.co_firstlineno + 1, @@ -204,7 +204,6 @@ dis_bug1333982 = """\ LOAD_CONST 1 ( at 0x..., file "%s", line %d>) MAKE_FUNCTION LOAD_FAST_BORROW 0 (x) - GET_ITER CALL 0 %3d LOAD_SMALL_INT 1 @@ -230,7 +229,7 @@ bug42562.__code__ = bug42562.__code__.replace(co_linetable=b'\xf8') dis_bug42562 = """\ RESUME 0 - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -283,7 +282,7 @@ dis_kw_names = """\ LOAD_CONST 1 (('c',)) CALL_KW 3 POP_TOP - LOAD_CONST 2 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ % (wrap_func_w_kwargs.__code__.co_firstlineno, wrap_func_w_kwargs.__code__.co_firstlineno + 1) @@ -293,10 +292,10 @@ dis_intrinsic_1_2 = """\ 1 LOAD_SMALL_INT 0 LOAD_CONST 1 (('*',)) - IMPORT_NAME 0 (math) + IMPORT_NAME 2 (math + eager) CALL_INTRINSIC_1 2 (INTRINSIC_IMPORT_STAR) POP_TOP - LOAD_CONST 2 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -323,7 +322,7 @@ _BIG_LINENO_FORMAT = """\ %3d LOAD_GLOBAL 0 (spam) POP_TOP - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -332,19 +331,19 @@ _BIG_LINENO_FORMAT2 = """\ %4d LOAD_GLOBAL 0 (spam) POP_TOP - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ dis_module_expected_results = """\ Disassembly of f: 4 RESUME 0 - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE Disassembly of g: 5 RESUME 0 - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -369,7 +368,7 @@ dis_simple_stmt_str = """\ LOAD_SMALL_INT 1 BINARY_OP 0 (+) STORE_NAME 0 (x) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -410,7 +409,7 @@ dis_annot_stmt_str = """\ LOAD_SMALL_INT 0 CALL 1 STORE_SUBSCR - LOAD_CONST 2 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -428,7 +427,7 @@ dis_fn_with_annotate_str = """\ MAKE_FUNCTION SET_FUNCTION_ATTRIBUTE 16 (annotate) STORE_NAME 0 (foo) - LOAD_CONST 2 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ @@ -454,52 +453,53 @@ dis_compound_stmt_str = """\ """ dis_traceback = """\ -%4d RESUME 0 +%4d RESUME 0 -%4d NOP +%4d NOP -%4d L1: LOAD_SMALL_INT 1 - LOAD_SMALL_INT 0 - --> BINARY_OP 11 (/) - POP_TOP +%4d L1: LOAD_SMALL_INT 1 + LOAD_SMALL_INT 0 + --> BINARY_OP 11 (/) + POP_TOP -%4d L2: LOAD_FAST_CHECK 1 (tb) - RETURN_VALUE +%4d L2: LOAD_FAST_CHECK 1 (tb) + RETURN_VALUE - -- L3: PUSH_EXC_INFO + -- L3: PUSH_EXC_INFO -%4d LOAD_GLOBAL 0 (Exception) - CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 24 (to L7) - NOT_TAKEN - STORE_FAST 0 (e) +%4d LOAD_GLOBAL 0 (Exception) + CHECK_EXC_MATCH + POP_JUMP_IF_FALSE 24 (to L9) + L4: NOT_TAKEN + L5: STORE_FAST 0 (e) -%4d L4: LOAD_FAST 0 (e) - LOAD_ATTR 2 (__traceback__) - STORE_FAST 1 (tb) - L5: POP_EXCEPT - LOAD_CONST 1 (None) - STORE_FAST 0 (e) - DELETE_FAST 0 (e) +%4d L6: LOAD_FAST 0 (e) + LOAD_ATTR 2 (__traceback__) + STORE_FAST 1 (tb) + L7: POP_EXCEPT + LOAD_COMMON_CONSTANT 7 (None) + STORE_FAST 0 (e) + DELETE_FAST 0 (e) -%4d LOAD_FAST 1 (tb) - RETURN_VALUE +%4d LOAD_FAST 1 (tb) + RETURN_VALUE - -- L6: LOAD_CONST 1 (None) - STORE_FAST 0 (e) - DELETE_FAST 0 (e) - RERAISE 1 + -- L8: LOAD_COMMON_CONSTANT 7 (None) + STORE_FAST 0 (e) + DELETE_FAST 0 (e) + RERAISE 1 -%4d L7: RERAISE 0 +%4d L9: RERAISE 0 - -- L8: COPY 3 - POP_EXCEPT - RERAISE 1 + -- L10: COPY 3 + POP_EXCEPT + RERAISE 1 ExceptionTable: L1 to L2 -> L3 [0] - L3 to L4 -> L8 [1] lasti - L4 to L5 -> L6 [1] lasti - L6 to L8 -> L8 [1] lasti + L3 to L4 -> L10 [1] lasti + L5 to L6 -> L10 [1] lasti + L6 to L7 -> L8 [1] lasti + L8 to L10 -> L10 [1] lasti """ % (TRACEBACK_CODE.co_firstlineno, TRACEBACK_CODE.co_firstlineno + 1, TRACEBACK_CODE.co_firstlineno + 2, @@ -554,40 +554,41 @@ dis_with = """\ %4d LOAD_SMALL_INT 1 STORE_FAST 1 (x) -%4d L2: LOAD_CONST 1 (None) - LOAD_CONST 1 (None) - LOAD_CONST 1 (None) +%4d L2: LOAD_COMMON_CONSTANT 7 (None) + LOAD_COMMON_CONSTANT 7 (None) + LOAD_COMMON_CONSTANT 7 (None) CALL 3 POP_TOP %4d LOAD_SMALL_INT 2 STORE_FAST 2 (y) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE %4d L3: PUSH_EXC_INFO WITH_EXCEPT_START TO_BOOL - POP_JUMP_IF_TRUE 2 (to L4) - NOT_TAKEN - RERAISE 2 - L4: POP_TOP - L5: POP_EXCEPT + POP_JUMP_IF_TRUE 2 (to L6) + L4: NOT_TAKEN + L5: RERAISE 2 + L6: POP_TOP + L7: POP_EXCEPT POP_TOP POP_TOP POP_TOP %4d LOAD_SMALL_INT 2 STORE_FAST 2 (y) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE - -- L6: COPY 3 + -- L8: COPY 3 POP_EXCEPT RERAISE 1 ExceptionTable: L1 to L2 -> L3 [2] lasti - L3 to L5 -> L6 [4] lasti + L3 to L4 -> L8 [4] lasti + L5 to L7 -> L8 [4] lasti """ % (_with.__code__.co_firstlineno, _with.__code__.co_firstlineno + 1, _with.__code__.co_firstlineno + 2, @@ -615,47 +616,50 @@ dis_asyncwith = """\ LOAD_SPECIAL 2 (__aenter__) CALL 0 GET_AWAITABLE 1 - LOAD_CONST 0 (None) - L2: SEND 3 (to L5) + PUSH_NULL + LOAD_COMMON_CONSTANT 7 (None) + L2: SEND 4 (to L5) L3: YIELD_VALUE 1 L4: RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to L2) + JUMP_BACKWARD_NO_INTERRUPT 6 (to L2) L5: END_SEND L6: POP_TOP %4d LOAD_SMALL_INT 1 STORE_FAST 1 (x) -%4d L7: LOAD_CONST 0 (None) - LOAD_CONST 0 (None) - LOAD_CONST 0 (None) +%4d L7: LOAD_COMMON_CONSTANT 7 (None) + LOAD_COMMON_CONSTANT 7 (None) + LOAD_COMMON_CONSTANT 7 (None) CALL 3 GET_AWAITABLE 2 - LOAD_CONST 0 (None) - L8: SEND 3 (to L11) + PUSH_NULL + LOAD_COMMON_CONSTANT 7 (None) + L8: SEND 4 (to L11) L9: YIELD_VALUE 1 L10: RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to L8) + JUMP_BACKWARD_NO_INTERRUPT 6 (to L8) L11: END_SEND POP_TOP %4d LOAD_SMALL_INT 2 STORE_FAST 2 (y) - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE %4d L12: CLEANUP_THROW - L13: JUMP_BACKWARD_NO_INTERRUPT 26 (to L5) + L13: JUMP_BACKWARD_NO_INTERRUPT 28 (to L5) L14: CLEANUP_THROW L15: JUMP_BACKWARD_NO_INTERRUPT 10 (to L11) L16: PUSH_EXC_INFO WITH_EXCEPT_START GET_AWAITABLE 2 - LOAD_CONST 0 (None) - L17: SEND 4 (to L21) + PUSH_NULL + LOAD_COMMON_CONSTANT 7 (None) + L17: SEND 5 (to L21) L18: YIELD_VALUE 1 L19: RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to L17) + JUMP_BACKWARD_NO_INTERRUPT 6 (to L17) L20: CLEANUP_THROW L21: END_SEND TO_BOOL @@ -670,7 +674,7 @@ dis_asyncwith = """\ %4d LOAD_SMALL_INT 2 STORE_FAST 2 (y) - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE -- L26: COPY 3 @@ -680,15 +684,15 @@ dis_asyncwith = """\ RERAISE 1 ExceptionTable: L1 to L3 -> L27 [0] lasti - L3 to L4 -> L12 [4] + L3 to L4 -> L12 [5] L4 to L6 -> L27 [0] lasti L6 to L7 -> L16 [2] lasti L7 to L9 -> L27 [0] lasti - L9 to L10 -> L14 [2] + L9 to L10 -> L14 [3] L10 to L13 -> L27 [0] lasti L14 to L15 -> L27 [0] lasti L16 to L18 -> L26 [4] lasti - L18 to L19 -> L20 [7] + L18 to L19 -> L20 [8] L19 to L22 -> L26 [4] lasti L23 to L25 -> L26 [4] lasti L25 to L27 -> L27 [0] lasti @@ -826,14 +830,35 @@ Disassembly of : %4d RESUME 0 -%4d LOAD_GLOBAL 1 (list + NULL) +%4d LOAD_GLOBAL 0 (list) + COPY 1 + LOAD_COMMON_CONSTANT 5 (list) + IS_OP 0 (is) + POP_JUMP_IF_FALSE 22 (to L3) + NOT_TAKEN + POP_TOP + BUILD_LIST 0 + LOAD_FAST_BORROW 0 (x) + BUILD_TUPLE 1 + LOAD_CONST %d ( at 0x..., file "%s", line %d>) + MAKE_FUNCTION + SET_FUNCTION_ATTRIBUTE 8 (closure) + LOAD_DEREF 1 (y) + CALL 0 + PUSH_NULL + L1: FOR_ITER 3 (to L2) + LIST_APPEND 3 + JUMP_BACKWARD 5 (to L1) + L2: END_FOR + POP_ITER + RETURN_VALUE + L3: PUSH_NULL LOAD_FAST_BORROW 0 (x) BUILD_TUPLE 1 LOAD_CONST 1 ( at 0x..., file "%s", line %d>) MAKE_FUNCTION SET_FUNCTION_ATTRIBUTE 8 (closure) LOAD_DEREF 1 (y) - GET_ITER CALL 0 CALL 1 RETURN_VALUE @@ -842,6 +867,9 @@ Disassembly of : _h.__code__.co_firstlineno + 1, _h.__code__.co_firstlineno + 1, _h.__code__.co_firstlineno + 3, + 1 if __debug__ else 0, + __file__, + _h.__code__.co_firstlineno + 3, __file__, _h.__code__.co_firstlineno + 3, ) @@ -849,29 +877,31 @@ Disassembly of : dis_nested_2 = """%s Disassembly of at 0x..., file "%s", line %d>: -- COPY_FREE_VARS 1 + RESUME 4 -%4d RETURN_GENERATOR +%4d LOAD_FAST 0 (.0) + GET_ITER 0 + RETURN_GENERATOR POP_TOP L1: RESUME 0 - LOAD_FAST 0 (.0) - L2: FOR_ITER 14 (to L3) + L2: FOR_ITER 15 (to L3) STORE_FAST 1 (z) LOAD_DEREF 2 (x) LOAD_FAST_BORROW 1 (z) BINARY_OP 0 (+) YIELD_VALUE 0 - RESUME 5 + RESUME 9 POP_TOP - JUMP_BACKWARD 16 (to L2) + JUMP_BACKWARD 17 (to L2) L3: END_FOR POP_ITER - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE -- L4: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) RERAISE 1 ExceptionTable: - L1 to L4 -> L4 [0] lasti + L1 to L4 -> L4 [2] lasti """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, @@ -883,7 +913,7 @@ def load_test(x, y=0): return a, b dis_load_test_quickened_code = """\ -%3d RESUME_CHECK 0 +%3d RESUME_CHECK{: <6} 0 %3d LOAD_FAST_LOAD_FAST 1 (x, y) STORE_FAST_STORE_FAST 50 (b, a) @@ -900,14 +930,14 @@ def loop_test(): load_test(i) dis_loop_test_quickened_code = """\ -%3d RESUME_CHECK 0 +%3d RESUME_CHECK{: <6} 0 %3d BUILD_LIST 0 - LOAD_CONST_MORTAL 2 ((1, 2, 3)) + LOAD_CONST 1 ((1, 2, 3)) LIST_EXTEND 1 LOAD_SMALL_INT 3 BINARY_OP 5 (*) - GET_ITER + GET_ITER_VIRTUAL 0 L1: FOR_ITER_LIST 14 (to L2) STORE_FAST 0 (i) @@ -919,7 +949,7 @@ dis_loop_test_quickened_code = """\ %3d L2: END_FOR POP_ITER - LOAD_CONST_IMMORTAL 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """ % (loop_test.__code__.co_firstlineno, loop_test.__code__.co_firstlineno + 1, @@ -937,7 +967,7 @@ dis_extended_arg_quick_code = """\ UNPACK_EX 256 POP_TOP STORE_FAST 0 (_) - LOAD_CONST 1 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE """% (extended_arg_quick.__code__.co_firstlineno, extended_arg_quick.__code__.co_firstlineno + 1,) @@ -1009,6 +1039,7 @@ class DisTests(DisTestBase): long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT', 'LOAD_FAST_BORROW_LOAD_FAST_BORROW', 'INSTRUMENTED_CALL_FUNCTION_EX', + 'YIELD_FROM_CORO_CHECK', 'ANNOTATIONS_PLACEHOLDER']) for op, opname in enumerate(dis.opname): if opname in long_opcodes or opname.startswith("INSTRUMENTED"): @@ -1053,7 +1084,7 @@ class DisTests(DisTestBase): '', '2:3-3:15 NOP', '', - '3:11-3:15 LOAD_CONST 0 (None)', + '3:11-3:15 LOAD_COMMON_CONSTANT 7 (None)', '3:11-3:15 RETURN_VALUE', '', ' -- L1: PUSH_EXC_INFO', @@ -1084,7 +1115,7 @@ class DisTests(DisTestBase): '', '2:5-2:6 LOAD_SMALL_INT 1', '2:?-2:? STORE_FAST 0 (x)', - '2:?-2:? LOAD_CONST 1 (None)', + '2:?-2:? LOAD_COMMON_CONSTANT 7 (None)', '2:?-2:? RETURN_VALUE', '', ]) @@ -1097,7 +1128,7 @@ class DisTests(DisTestBase): f.__code__ = f.__code__.replace(co_linetable=b'') expect = '\n'.join([ ' RESUME 0', - ' LOAD_CONST 0 (None)', + ' LOAD_COMMON_CONSTANT 7 (None)', ' RETURN_VALUE', '', ]) @@ -1297,28 +1328,32 @@ class DisTests(DisTestBase): def test_super_instructions(self): self.code_quicken(lambda: load_test(0, 0)) got = self.get_disassembly(load_test, adaptive=True) - self.do_disassembly_compare(got, dis_load_test_quickened_code) + jit = sys._jit.is_enabled() + expected = dis_load_test_quickened_code.format("_JIT" if jit else "") + self.do_disassembly_compare(got, expected) @cpython_only @requires_specialization def test_load_attr_specialize(self): load_attr_quicken = """\ - 0 RESUME_CHECK 0 + 0 RESUME_CHECK{: <6} 0 - 1 LOAD_CONST_IMMORTAL 0 ('a') + 1 LOAD_CONST 0 ('a') LOAD_ATTR_SLOT 0 (__class__) RETURN_VALUE """ co = compile("'a'.__class__", "", "eval") self.code_quicken(lambda: exec(co, {}, {})) got = self.get_disassembly(co, adaptive=True) - self.do_disassembly_compare(got, load_attr_quicken) + jit = sys._jit.is_enabled() + expected = load_attr_quicken.format("_JIT" if jit else "") + self.do_disassembly_compare(got, expected) @cpython_only @requires_specialization def test_call_specialize(self): call_quicken = """\ - 0 RESUME_CHECK 0 + 0 RESUME_CHECK{: <6} 0 1 LOAD_NAME 0 (str) PUSH_NULL @@ -1329,7 +1364,9 @@ class DisTests(DisTestBase): co = compile("str(1)", "", "eval") self.code_quicken(lambda: exec(co, {}, {})) got = self.get_disassembly(co, adaptive=True) - self.do_disassembly_compare(got, call_quicken) + jit = sys._jit.is_enabled() + expected = call_quicken.format("_JIT" if jit else "") + self.do_disassembly_compare(got, expected) @cpython_only @requires_specialization @@ -1338,7 +1375,9 @@ class DisTests(DisTestBase): self.code_quicken(loop_test) got = self.get_disassembly(loop_test, adaptive=True) jit = sys._jit.is_enabled() - expected = dis_loop_test_quickened_code.format("JIT" if jit else "NO_JIT") + resume_str = "_JIT" if jit else "" + jit_str = "JIT " if jit else "NO_JIT" + expected = dis_loop_test_quickened_code.format(resume_str, jit_str) self.do_disassembly_compare(got, expected) @cpython_only @@ -1405,7 +1444,7 @@ class DisTests(DisTestBase): caches = list(self.get_cached_values(quickened, adaptive)) for cache in caches: self.assertRegex(cache, pattern) - total_caches = 21 + total_caches = 23 empty_caches = 7 self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) @@ -1467,7 +1506,7 @@ Positional-only arguments: 0 Kw-only arguments: 0 Number of locals: 1 Stack size: \\d+ -Flags: OPTIMIZED, NEWLOCALS, HAS_DOCSTRING +Flags: OPTIMIZED, NEWLOCALS(, HAS_DOCSTRING)? Constants: {code_info_consts} Names: @@ -1494,7 +1533,6 @@ Stack size: \\d+ Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR Constants: 0: - 1: None Variable names: 0: a 1: b @@ -1566,7 +1604,6 @@ Stack size: \\d+ Flags: 0x0 Constants: 0: 1 - 1: None Names: 0: x""" @@ -1601,7 +1638,6 @@ Stack size: \\d+ Flags: OPTIMIZED, NEWLOCALS, COROUTINE Constants: 0: 1 - 1: None Names: 0: b 1: c @@ -1750,209 +1786,210 @@ make_inst = dis.Instruction.make expected_opinfo_outer = [ make_inst(opname='MAKE_CELL', arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None), make_inst(opname='MAKE_CELL', arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None), - make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1), - make_inst(opname='LOAD_CONST', arg=4, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2), - make_inst(opname='LOAD_FAST_BORROW', arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2), - make_inst(opname='BUILD_TUPLE', arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2), - make_inst(opname='LOAD_CONST', arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2), - make_inst(opname='MAKE_FUNCTION', arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=False, line_number=2), - make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2), - make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2), - make_inst(opname='STORE_FAST', arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=False, line_number=2), - make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_DEREF', arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7), - make_inst(opname='LOAD_DEREF', arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7), - make_inst(opname='LOAD_CONST', arg=2, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7), - make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=40, start_offset=40, starts_line=False, line_number=7), - make_inst(opname='BUILD_LIST', arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7), - make_inst(opname='BUILD_MAP', arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7), - make_inst(opname='LOAD_CONST', arg=3, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7), - make_inst(opname='CALL', arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7), - make_inst(opname='LOAD_FAST_BORROW', arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8), - make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=8), + make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=3, argval=(3, 4), argrepr='(3, 4)', offset=8, start_offset=8, starts_line=True, line_number=2), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=2), + make_inst(opname='LOAD_FAST_BORROW', arg=1, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=2), + make_inst(opname='BUILD_TUPLE', arg=2, argval=2, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=2), + make_inst(opname='LOAD_CONST', arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=16, start_offset=16, starts_line=False, line_number=2), + make_inst(opname='MAKE_FUNCTION', arg=None, argval=None, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=2), + make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=8, argval=8, argrepr='closure', offset=20, start_offset=20, starts_line=False, line_number=2), + make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=1, argval=1, argrepr='defaults', offset=22, start_offset=22, starts_line=False, line_number=2), + make_inst(opname='STORE_FAST', arg=2, argval='f', argrepr='f', offset=24, start_offset=24, starts_line=False, line_number=2), + make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=26, start_offset=26, starts_line=True, line_number=7, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_DEREF', arg=0, argval='a', argrepr='a', offset=36, start_offset=36, starts_line=False, line_number=7), + make_inst(opname='LOAD_DEREF', arg=1, argval='b', argrepr='b', offset=38, start_offset=38, starts_line=False, line_number=7), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=8, argval='', argrepr="''", offset=40, start_offset=40, starts_line=False, line_number=7), + make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7), + make_inst(opname='BUILD_LIST', arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7), + make_inst(opname='BUILD_MAP', arg=0, argval=0, argrepr='', offset=46, start_offset=46, starts_line=False, line_number=7), + make_inst(opname='LOAD_CONST', arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=48, start_offset=48, starts_line=False, line_number=7), + make_inst(opname='CALL', arg=7, argval=7, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=58, start_offset=58, starts_line=False, line_number=7), + make_inst(opname='LOAD_FAST_BORROW', arg=2, argval='f', argrepr='f', offset=60, start_offset=60, starts_line=True, line_number=8), + make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=62, start_offset=62, starts_line=False, line_number=8), ] expected_opinfo_f = [ make_inst(opname='COPY_FREE_VARS', arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None), make_inst(opname='MAKE_CELL', arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None), make_inst(opname='MAKE_CELL', arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None), - make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=True, line_number=2), - make_inst(opname='LOAD_CONST', arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3), - make_inst(opname='LOAD_FAST_BORROW', arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3), - make_inst(opname='LOAD_FAST_BORROW', arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3), - make_inst(opname='LOAD_FAST_BORROW', arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3), - make_inst(opname='BUILD_TUPLE', arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3), - make_inst(opname='LOAD_CONST', arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3), - make_inst(opname='MAKE_FUNCTION', arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3), - make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3), - make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3), - make_inst(opname='STORE_FAST', arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=False, line_number=3), - make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=5, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_DEREF', arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=False, line_number=5), - make_inst(opname='LOAD_DEREF', arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=False, line_number=5), - make_inst(opname='LOAD_DEREF', arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=False, line_number=5), - make_inst(opname='LOAD_DEREF', arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=False, line_number=5), - make_inst(opname='CALL', arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5), - make_inst(opname='LOAD_FAST_BORROW', arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=True, line_number=6), - make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=6), + make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=True, line_number=2, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=2, argval=(5, 6), argrepr='(5, 6)', offset=10, start_offset=10, starts_line=True, line_number=3), + make_inst(opname='LOAD_FAST_BORROW', arg=3, argval='a', argrepr='a', offset=12, start_offset=12, starts_line=False, line_number=3), + make_inst(opname='LOAD_FAST_BORROW', arg=4, argval='b', argrepr='b', offset=14, start_offset=14, starts_line=False, line_number=3), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='c', argrepr='c', offset=16, start_offset=16, starts_line=False, line_number=3), + make_inst(opname='LOAD_FAST_BORROW', arg=1, argval='d', argrepr='d', offset=18, start_offset=18, starts_line=False, line_number=3), + make_inst(opname='BUILD_TUPLE', arg=4, argval=4, argrepr='', offset=20, start_offset=20, starts_line=False, line_number=3), + make_inst(opname='LOAD_CONST', arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=22, start_offset=22, starts_line=False, line_number=3), + make_inst(opname='MAKE_FUNCTION', arg=None, argval=None, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=3), + make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=8, argval=8, argrepr='closure', offset=26, start_offset=26, starts_line=False, line_number=3), + make_inst(opname='SET_FUNCTION_ATTRIBUTE', arg=1, argval=1, argrepr='defaults', offset=28, start_offset=28, starts_line=False, line_number=3), + make_inst(opname='STORE_FAST', arg=2, argval='inner', argrepr='inner', offset=30, start_offset=30, starts_line=False, line_number=3), + make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=32, start_offset=32, starts_line=True, line_number=5, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_DEREF', arg=3, argval='a', argrepr='a', offset=42, start_offset=42, starts_line=False, line_number=5), + make_inst(opname='LOAD_DEREF', arg=4, argval='b', argrepr='b', offset=44, start_offset=44, starts_line=False, line_number=5), + make_inst(opname='LOAD_DEREF', arg=0, argval='c', argrepr='c', offset=46, start_offset=46, starts_line=False, line_number=5), + make_inst(opname='LOAD_DEREF', arg=1, argval='d', argrepr='d', offset=48, start_offset=48, starts_line=False, line_number=5), + make_inst(opname='CALL', arg=4, argval=4, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=58, start_offset=58, starts_line=False, line_number=5), + make_inst(opname='LOAD_FAST_BORROW', arg=2, argval='inner', argrepr='inner', offset=60, start_offset=60, starts_line=True, line_number=6), + make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=62, start_offset=62, starts_line=False, line_number=6), ] expected_opinfo_inner = [ make_inst(opname='COPY_FREE_VARS', arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None), - make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=True, line_number=3), - make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=True, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_DEREF', arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=False, line_number=4), - make_inst(opname='LOAD_DEREF', arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=False, line_number=4), - make_inst(opname='LOAD_DEREF', arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=False, line_number=4), - make_inst(opname='LOAD_DEREF', arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=False, line_number=4), - make_inst(opname='LOAD_FAST_BORROW_LOAD_FAST_BORROW', arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=False, line_number=4), - make_inst(opname='CALL', arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=False, line_number=4), - make_inst(opname='LOAD_CONST', arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=False, line_number=4), - make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=36, start_offset=36, starts_line=False, line_number=4), + make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=True, line_number=3, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=6, start_offset=6, starts_line=True, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_DEREF', arg=2, argval='a', argrepr='a', offset=16, start_offset=16, starts_line=False, line_number=4), + make_inst(opname='LOAD_DEREF', arg=3, argval='b', argrepr='b', offset=18, start_offset=18, starts_line=False, line_number=4), + make_inst(opname='LOAD_DEREF', arg=4, argval='c', argrepr='c', offset=20, start_offset=20, starts_line=False, line_number=4), + make_inst(opname='LOAD_DEREF', arg=5, argval='d', argrepr='d', offset=22, start_offset=22, starts_line=False, line_number=4), + make_inst(opname='LOAD_FAST_BORROW_LOAD_FAST_BORROW', arg=1, argval=('e', 'f'), argrepr='e, f', offset=24, start_offset=24, starts_line=False, line_number=4), + make_inst(opname='CALL', arg=6, argval=6, argrepr='', offset=26, start_offset=26, starts_line=False, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=34, start_offset=34, starts_line=False, line_number=4), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=36, start_offset=36, starts_line=False, line_number=4), + make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=38, start_offset=38, starts_line=False, line_number=4), ] expected_opinfo_jumpy = [ - make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=1), - make_inst(opname='LOAD_GLOBAL', arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=True, line_number=3, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_SMALL_INT', arg=10, argval=10, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=3), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='GET_ITER', arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3), - make_inst(opname='FOR_ITER', arg=32, argval=92, argrepr='to L4', offset=24, start_offset=24, starts_line=False, line_number=3, label=1, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='STORE_FAST', arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=4), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5), - make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=54, start_offset=54, starts_line=False, line_number=5), - make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=70, argrepr='to L2', offset=60, start_offset=60, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=64, start_offset=64, starts_line=False, line_number=5), - make_inst(opname='JUMP_BACKWARD', arg=23, argval=24, argrepr='to L1', offset=66, start_offset=66, starts_line=True, line_number=6, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=70, start_offset=70, starts_line=True, line_number=7, label=2), - make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=72, start_offset=72, starts_line=False, line_number=7), - make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=74, start_offset=74, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=88, argrepr='to L3', offset=78, start_offset=78, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=82, start_offset=82, starts_line=False, line_number=7), - make_inst(opname='JUMP_BACKWARD', arg=32, argval=24, argrepr='to L1', offset=84, start_offset=84, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=8, label=3), - make_inst(opname='JUMP_FORWARD', arg=13, argval=118, argrepr='to L5', offset=90, start_offset=90, starts_line=False, line_number=8), - make_inst(opname='END_FOR', arg=None, argval=None, argrepr='', offset=92, start_offset=92, starts_line=True, line_number=3, label=4), - make_inst(opname='POP_ITER', arg=None, argval=None, argrepr='', offset=94, start_offset=94, starts_line=False, line_number=3), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=96, start_offset=96, starts_line=True, line_number=10, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_CONST', arg=1, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=106, start_offset=106, starts_line=False, line_number=10), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=108, start_offset=108, starts_line=False, line_number=10, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=10), - make_inst(opname='LOAD_FAST_CHECK', arg=0, argval='i', argrepr='i', offset=118, start_offset=118, starts_line=True, line_number=11, label=5), - make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=120, start_offset=120, starts_line=False, line_number=11, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_JUMP_IF_FALSE', arg=40, argval=212, argrepr='to L8', offset=128, start_offset=128, starts_line=False, line_number=11, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=132, start_offset=132, starts_line=False, line_number=11), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=134, start_offset=134, starts_line=True, line_number=12, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=144, start_offset=144, starts_line=False, line_number=12), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=146, start_offset=146, starts_line=False, line_number=12, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=154, start_offset=154, starts_line=False, line_number=12), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=156, start_offset=156, starts_line=True, line_number=13), - make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=158, start_offset=158, starts_line=False, line_number=13), - make_inst(opname='BINARY_OP', arg=23, argval=23, argrepr='-=', offset=160, start_offset=160, starts_line=False, line_number=13, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), - make_inst(opname='STORE_FAST', arg=0, argval='i', argrepr='i', offset=172, start_offset=172, starts_line=False, line_number=13), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=174, start_offset=174, starts_line=True, line_number=14), - make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=176, start_offset=176, starts_line=False, line_number=14), - make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=178, start_offset=178, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=192, argrepr='to L6', offset=182, start_offset=182, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=186, start_offset=186, starts_line=False, line_number=14), - make_inst(opname='JUMP_BACKWARD', arg=37, argval=118, argrepr='to L5', offset=188, start_offset=188, starts_line=True, line_number=15, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=192, start_offset=192, starts_line=True, line_number=16, label=6), - make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=194, start_offset=194, starts_line=False, line_number=16), - make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=196, start_offset=196, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=210, argrepr='to L7', offset=200, start_offset=200, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=204, start_offset=204, starts_line=False, line_number=16), - make_inst(opname='JUMP_BACKWARD', arg=46, argval=118, argrepr='to L5', offset=206, start_offset=206, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='JUMP_FORWARD', arg=11, argval=234, argrepr='to L9', offset=210, start_offset=210, starts_line=True, line_number=17, label=7), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=212, start_offset=212, starts_line=True, line_number=19, label=8, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_CONST', arg=2, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=222, start_offset=222, starts_line=False, line_number=19), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=224, start_offset=224, starts_line=False, line_number=19, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=232, start_offset=232, starts_line=False, line_number=19), - make_inst(opname='NOP', arg=None, argval=None, argrepr='', offset=234, start_offset=234, starts_line=True, line_number=20, label=9), - make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=236, start_offset=236, starts_line=True, line_number=21), - make_inst(opname='LOAD_SMALL_INT', arg=0, argval=0, argrepr='', offset=238, start_offset=238, starts_line=False, line_number=21), - make_inst(opname='BINARY_OP', arg=11, argval=11, argrepr='/', offset=240, start_offset=240, starts_line=False, line_number=21, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=252, start_offset=252, starts_line=False, line_number=21), - make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=254, start_offset=254, starts_line=True, line_number=25), - make_inst(opname='COPY', arg=1, argval=1, argrepr='', offset=256, start_offset=256, starts_line=False, line_number=25), - make_inst(opname='LOAD_SPECIAL', arg=1, argval=1, argrepr='__exit__', offset=258, start_offset=258, starts_line=False, line_number=25), - make_inst(opname='SWAP', arg=2, argval=2, argrepr='', offset=260, start_offset=260, starts_line=False, line_number=25), - make_inst(opname='SWAP', arg=3, argval=3, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=25), - make_inst(opname='LOAD_SPECIAL', arg=0, argval=0, argrepr='__enter__', offset=264, start_offset=264, starts_line=False, line_number=25), - make_inst(opname='CALL', arg=0, argval=0, argrepr='', offset=266, start_offset=266, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='STORE_FAST', arg=1, argval='dodgy', argrepr='dodgy', offset=274, start_offset=274, starts_line=False, line_number=25), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=276, start_offset=276, starts_line=True, line_number=26, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_CONST', arg=3, argval='Never reach this', argrepr="'Never reach this'", offset=286, start_offset=286, starts_line=False, line_number=26), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=288, start_offset=288, starts_line=False, line_number=26, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=False, line_number=26), - make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=298, start_offset=298, starts_line=True, line_number=25), - make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=300, start_offset=300, starts_line=False, line_number=25), - make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=302, start_offset=302, starts_line=False, line_number=25), - make_inst(opname='CALL', arg=3, argval=3, argrepr='', offset=304, start_offset=304, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=314, start_offset=314, starts_line=True, line_number=28, label=10, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_CONST', arg=6, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=324, start_offset=324, starts_line=False, line_number=28), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=28), - make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=336, start_offset=336, starts_line=False, line_number=28), - make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=338, start_offset=338, starts_line=False, line_number=28), - make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=True, line_number=25), - make_inst(opname='WITH_EXCEPT_START', arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=25), - make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_JUMP_IF_TRUE', arg=2, argval=360, argrepr='to L11', offset=352, start_offset=352, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=False, line_number=25), - make_inst(opname='RERAISE', arg=2, argval=2, argrepr='', offset=358, start_offset=358, starts_line=False, line_number=25), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=25, label=11), - make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=25), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=364, start_offset=364, starts_line=False, line_number=25), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=366, start_offset=366, starts_line=False, line_number=25), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=25), - make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=29, argval=314, argrepr='to L10', offset=370, start_offset=370, starts_line=False, line_number=25), - make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=372, start_offset=372, starts_line=True, line_number=None), - make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=374, start_offset=374, starts_line=False, line_number=None), - make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=None), - make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=378, start_offset=378, starts_line=False, line_number=None), - make_inst(opname='LOAD_GLOBAL', arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=380, start_offset=380, starts_line=True, line_number=22, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='CHECK_EXC_MATCH', arg=None, argval=None, argrepr='', offset=390, start_offset=390, starts_line=False, line_number=22), - make_inst(opname='POP_JUMP_IF_FALSE', arg=15, argval=426, argrepr='to L12', offset=392, start_offset=392, starts_line=False, line_number=22, cache_info=[('counter', 1, b'\x00\x00')]), - make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=22), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=22), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=400, start_offset=400, starts_line=True, line_number=23, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_CONST', arg=5, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=410, start_offset=410, starts_line=False, line_number=23), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=412, start_offset=412, starts_line=False, line_number=23, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=420, start_offset=420, starts_line=False, line_number=23), - make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=422, start_offset=422, starts_line=False, line_number=23), - make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=56, argval=314, argrepr='to L10', offset=424, start_offset=424, starts_line=False, line_number=23), - make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=426, start_offset=426, starts_line=True, line_number=22, label=12), - make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=428, start_offset=428, starts_line=True, line_number=None), - make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=430, start_offset=430, starts_line=False, line_number=None), - make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None), - make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None), - make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=436, start_offset=436, starts_line=True, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - make_inst(opname='LOAD_CONST', arg=6, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=446, start_offset=446, starts_line=False, line_number=28), - make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=448, start_offset=448, starts_line=False, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=456, start_offset=456, starts_line=False, line_number=28), - make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=458, start_offset=458, starts_line=False, line_number=28), - make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=460, start_offset=460, starts_line=True, line_number=None), - make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=462, start_offset=462, starts_line=False, line_number=None), - make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=464, start_offset=464, starts_line=False, line_number=None), + make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=1, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='LOAD_GLOBAL', arg=1, argval='range', argrepr='range + NULL', offset=4, start_offset=4, starts_line=True, line_number=3, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_SMALL_INT', arg=10, argval=10, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=16, start_offset=16, starts_line=False, line_number=3, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='GET_ITER', arg=0, argval=0, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=3, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='FOR_ITER', arg=33, argval=98, argrepr='to L4', offset=28, start_offset=28, starts_line=False, line_number=3, label=1, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='STORE_FAST', arg=0, argval='i', argrepr='i', offset=32, start_offset=32, starts_line=False, line_number=3), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=34, start_offset=34, starts_line=True, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=44, start_offset=44, starts_line=False, line_number=4), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=46, start_offset=46, starts_line=False, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=54, start_offset=54, starts_line=False, line_number=4), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=56, start_offset=56, starts_line=True, line_number=5), + make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=58, start_offset=58, starts_line=False, line_number=5), + make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=60, start_offset=60, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=74, argrepr='to L2', offset=64, start_offset=64, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=68, start_offset=68, starts_line=False, line_number=5), + make_inst(opname='JUMP_BACKWARD', arg=23, argval=28, argrepr='to L1', offset=70, start_offset=70, starts_line=True, line_number=6, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=74, start_offset=74, starts_line=True, line_number=7, label=2), + make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=76, start_offset=76, starts_line=False, line_number=7), + make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=78, start_offset=78, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=92, argrepr='to L3', offset=82, start_offset=82, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=86, start_offset=86, starts_line=False, line_number=7), + make_inst(opname='JUMP_BACKWARD', arg=32, argval=28, argrepr='to L1', offset=88, start_offset=88, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=92, start_offset=92, starts_line=True, line_number=8, label=3), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=94, start_offset=94, starts_line=False, line_number=8), + make_inst(opname='JUMP_FORWARD', arg=13, argval=124, argrepr='to L5', offset=96, start_offset=96, starts_line=False, line_number=8), + make_inst(opname='END_FOR', arg=None, argval=None, argrepr='', offset=98, start_offset=98, starts_line=True, line_number=3, label=4), + make_inst(opname='POP_ITER', arg=None, argval=None, argrepr='', offset=100, start_offset=100, starts_line=False, line_number=3), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=102, start_offset=102, starts_line=True, line_number=10, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=1, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=112, start_offset=112, starts_line=False, line_number=10), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=114, start_offset=114, starts_line=False, line_number=10, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=122, start_offset=122, starts_line=False, line_number=10), + make_inst(opname='LOAD_FAST_CHECK', arg=0, argval='i', argrepr='i', offset=124, start_offset=124, starts_line=True, line_number=11, label=5), + make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=126, start_offset=126, starts_line=False, line_number=11, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_JUMP_IF_FALSE', arg=40, argval=218, argrepr='to L8', offset=134, start_offset=134, starts_line=False, line_number=11, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=138, start_offset=138, starts_line=False, line_number=11), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=140, start_offset=140, starts_line=True, line_number=12, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=False, line_number=12), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=152, start_offset=152, starts_line=False, line_number=12, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=160, start_offset=160, starts_line=False, line_number=12), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=162, start_offset=162, starts_line=True, line_number=13), + make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=164, start_offset=164, starts_line=False, line_number=13), + make_inst(opname='BINARY_OP', arg=23, argval=23, argrepr='-=', offset=166, start_offset=166, starts_line=False, line_number=13, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), + make_inst(opname='STORE_FAST', arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=False, line_number=13), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=180, start_offset=180, starts_line=True, line_number=14), + make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=182, start_offset=182, starts_line=False, line_number=14), + make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=184, start_offset=184, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=198, argrepr='to L6', offset=188, start_offset=188, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=192, start_offset=192, starts_line=False, line_number=14), + make_inst(opname='JUMP_BACKWARD', arg=37, argval=124, argrepr='to L5', offset=194, start_offset=194, starts_line=True, line_number=15, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=198, start_offset=198, starts_line=True, line_number=16, label=6), + make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=200, start_offset=200, starts_line=False, line_number=16), + make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=202, start_offset=202, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=216, argrepr='to L7', offset=206, start_offset=206, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=210, start_offset=210, starts_line=False, line_number=16), + make_inst(opname='JUMP_BACKWARD', arg=46, argval=124, argrepr='to L5', offset=212, start_offset=212, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='JUMP_FORWARD', arg=11, argval=240, argrepr='to L9', offset=216, start_offset=216, starts_line=True, line_number=17, label=7), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=218, start_offset=218, starts_line=True, line_number=19, label=8, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=2, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=228, start_offset=228, starts_line=False, line_number=19), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=230, start_offset=230, starts_line=False, line_number=19, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=238, start_offset=238, starts_line=False, line_number=19), + make_inst(opname='NOP', arg=None, argval=None, argrepr='', offset=240, start_offset=240, starts_line=True, line_number=20, label=9), + make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=242, start_offset=242, starts_line=True, line_number=21), + make_inst(opname='LOAD_SMALL_INT', arg=0, argval=0, argrepr='', offset=244, start_offset=244, starts_line=False, line_number=21), + make_inst(opname='BINARY_OP', arg=11, argval=11, argrepr='/', offset=246, start_offset=246, starts_line=False, line_number=21, cache_info=[('counter', 1, b'\x00\x00'), ('descr', 4, b'\x00\x00\x00\x00\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=258, start_offset=258, starts_line=False, line_number=21), + make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=260, start_offset=260, starts_line=True, line_number=25), + make_inst(opname='COPY', arg=1, argval=1, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=25), + make_inst(opname='LOAD_SPECIAL', arg=1, argval=1, argrepr='__exit__', offset=264, start_offset=264, starts_line=False, line_number=25), + make_inst(opname='SWAP', arg=2, argval=2, argrepr='', offset=266, start_offset=266, starts_line=False, line_number=25), + make_inst(opname='SWAP', arg=3, argval=3, argrepr='', offset=268, start_offset=268, starts_line=False, line_number=25), + make_inst(opname='LOAD_SPECIAL', arg=0, argval=0, argrepr='__enter__', offset=270, start_offset=270, starts_line=False, line_number=25), + make_inst(opname='CALL', arg=0, argval=0, argrepr='', offset=272, start_offset=272, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='STORE_FAST', arg=1, argval='dodgy', argrepr='dodgy', offset=280, start_offset=280, starts_line=False, line_number=25), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=282, start_offset=282, starts_line=True, line_number=26, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=3, argval='Never reach this', argrepr="'Never reach this'", offset=292, start_offset=292, starts_line=False, line_number=26), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=294, start_offset=294, starts_line=False, line_number=26, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=302, start_offset=302, starts_line=False, line_number=26), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=304, start_offset=304, starts_line=True, line_number=25), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=306, start_offset=306, starts_line=False, line_number=25), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=308, start_offset=308, starts_line=False, line_number=25), + make_inst(opname='CALL', arg=3, argval=3, argrepr='', offset=310, start_offset=310, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=False, line_number=25), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=320, start_offset=320, starts_line=True, line_number=28, label=10, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=330, start_offset=330, starts_line=False, line_number=28), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=28), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=342, start_offset=342, starts_line=False, line_number=28), + make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=28), + make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=True, line_number=25), + make_inst(opname='WITH_EXCEPT_START', arg=None, argval=None, argrepr='', offset=348, start_offset=348, starts_line=False, line_number=25), + make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=350, start_offset=350, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_JUMP_IF_TRUE', arg=2, argval=366, argrepr='to L11', offset=358, start_offset=358, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=25), + make_inst(opname='RERAISE', arg=2, argval=2, argrepr='', offset=364, start_offset=364, starts_line=False, line_number=25), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=366, start_offset=366, starts_line=False, line_number=25, label=11), + make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=25), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=370, start_offset=370, starts_line=False, line_number=25), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=372, start_offset=372, starts_line=False, line_number=25), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=374, start_offset=374, starts_line=False, line_number=25), + make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=29, argval=320, argrepr='to L10', offset=376, start_offset=376, starts_line=False, line_number=25), + make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=378, start_offset=378, starts_line=True, line_number=None), + make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=380, start_offset=380, starts_line=False, line_number=None), + make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=False, line_number=None), + make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=False, line_number=None), + make_inst(opname='LOAD_GLOBAL', arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=386, start_offset=386, starts_line=True, line_number=22, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='CHECK_EXC_MATCH', arg=None, argval=None, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=22), + make_inst(opname='POP_JUMP_IF_FALSE', arg=15, argval=432, argrepr='to L12', offset=398, start_offset=398, starts_line=False, line_number=22, cache_info=[('counter', 1, b'\x00\x00')]), + make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=402, start_offset=402, starts_line=False, line_number=22), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=404, start_offset=404, starts_line=False, line_number=22), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=406, start_offset=406, starts_line=True, line_number=23, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=416, start_offset=416, starts_line=False, line_number=23), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=418, start_offset=418, starts_line=False, line_number=23, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=23), + make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=23), + make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=56, argval=320, argrepr='to L10', offset=430, start_offset=430, starts_line=False, line_number=23), + make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=432, start_offset=432, starts_line=True, line_number=22, label=12), + make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=434, start_offset=434, starts_line=True, line_number=None), + make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=436, start_offset=436, starts_line=False, line_number=None), + make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=438, start_offset=438, starts_line=False, line_number=None), + make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=440, start_offset=440, starts_line=False, line_number=None), + make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=442, start_offset=442, starts_line=True, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + make_inst(opname='LOAD_CONST', arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=452, start_offset=452, starts_line=False, line_number=28), + make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=454, start_offset=454, starts_line=False, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=462, start_offset=462, starts_line=False, line_number=28), + make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=464, start_offset=464, starts_line=False, line_number=28), + make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=466, start_offset=466, starts_line=True, line_number=None), + make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=468, start_offset=468, starts_line=False, line_number=None), + make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=470, start_offset=470, starts_line=False, line_number=None), ] # One last piece of inspect fodder to check the default line number handling def simple(): pass expected_opinfo_simple = [ make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=simple.__code__.co_firstlineno), - make_inst(opname='LOAD_CONST', arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=False, line_number=simple.__code__.co_firstlineno), - make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno), + make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno), + make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=6, start_offset=6, starts_line=False, line_number=simple.__code__.co_firstlineno), ] @@ -2343,8 +2380,10 @@ class BytecodeTests(InstructionTestCase, DisTestBase): @requires_debug_ranges() def test_bytecode_co_positions(self): bytecode = dis.Bytecode("a=1") - for instr, positions in zip(bytecode, bytecode.codeobj.co_positions()): - assert instr.positions == positions + it = bytecode.codeobj.co_positions() + next(it) # Ignore the CACHE for the RESUME + for instr, positions in zip(bytecode, it): + self.assertEqual(instr.positions, positions) class TestBytecodeTestCase(BytecodeTestCase): def test_assert_not_in_with_op_not_in_bytecode(self): @@ -2412,7 +2451,7 @@ class TestFinderMethods(unittest.TestCase): code = func.__code__ offsets = [linestart[0] for linestart in dis.findlinestarts(code)] - self.assertEqual(offsets, [0, 2]) + self.assertEqual(offsets, [0, 4]) class TestDisTraceback(DisTestBase): @@ -2550,6 +2589,7 @@ class TestDisCLI(unittest.TestCase): source = 'print()' expect = ''' 0 RESUME 0 + CACHE 0 (counter: 0) 1 LOAD_NAME 0 (print) PUSH_NULL @@ -2558,7 +2598,7 @@ class TestDisCLI(unittest.TestCase): CACHE 0 (func_version: 0) CACHE 0 POP_TOP - LOAD_CONST 0 (None) + LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE ''' for flag in ['-C', '--show-caches']: @@ -2570,8 +2610,8 @@ class TestDisCLI(unittest.TestCase): expect = ''' 0 0 RESUME 0 - 1 2 LOAD_CONST 0 (None) - 4 RETURN_VALUE + 1 4 LOAD_COMMON_CONSTANT 7 (None) + 6 RETURN_VALUE ''' for flag in ['-O', '--show-offsets']: self.check_output(source, expect, flag) @@ -2582,7 +2622,7 @@ class TestDisCLI(unittest.TestCase): expect = ''' 0:0-1:0 RESUME 0 - 1:0-1:4 LOAD_CONST 0 (None) + 1:0-1:4 LOAD_COMMON_CONSTANT 7 (None) 1:0-1:4 RETURN_VALUE ''' for flag in ['-P', '--show-positions']: @@ -2594,7 +2634,7 @@ class TestDisCLI(unittest.TestCase): expect = ''' 0 RESUME 0 - 1 LOAD_CONST 0 (None) + 1 LOAD_COMMON_CONSTANT 7 (None) RETURN_VALUE ''' for flag in ['-S', '--specialized']: diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 037c1bed5..6eb259601 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -300,7 +300,7 @@ class GeneratorTest(unittest.TestCase): def __iter__(self): return Iterator() - self.assertEqual([1, 2], list(i for i in C())) + self.assertEqual([1,2], list(i for i in C())) def test_close_clears_frame(self): # gh-142766: Test that closing a generator clears its frame @@ -357,26 +357,25 @@ class ModifyUnderlyingIterableTest(unittest.TestCase): yield x return gen(range(10)) - def process_tests(self, get_generator, is_expr): - err_iterator = "'.*' object is not an iterator" - err_iterable = "'.*' object is not iterable" - for obj in self.iterables: - g_obj = get_generator(obj) - with self.subTest(g_obj=g_obj, obj=obj): - if is_expr: - self.assertRaisesRegex(TypeError, err_iterator, list, g_obj) - else: + def process_tests(self, get_generator, changes_iterable): + if changes_iterable: + for obj in self.iterables: + g_obj = get_generator(obj) + with self.subTest(g_obj=g_obj, obj=obj): self.assertListEqual(list(g_obj), list(obj)) - g_iter = get_generator(iter(obj)) - with self.subTest(g_iter=g_iter, obj=obj): - self.assertListEqual(list(g_iter), list(obj)) + g_iter = get_generator(iter(obj)) + with self.subTest(g_iter=g_iter, obj=obj): + self.assertListEqual(list(g_iter), list(obj)) + err_regex = "'.*' object is not iterable" for obj in self.non_iterables: g_obj = get_generator(obj) with self.subTest(g_obj=g_obj): - err = err_iterator if is_expr else err_iterable - self.assertRaisesRegex(TypeError, err, list, g_obj) + if changes_iterable: + self.assertRaisesRegex(TypeError, err_regex, list, g_obj) + else: + next(g_obj) def test_modify_f_locals(self): def modify_f_locals(g, local, obj): @@ -389,22 +388,22 @@ class ModifyUnderlyingIterableTest(unittest.TestCase): def get_generator_genfunc(obj): return modify_f_locals(self.genfunc(), 'it', obj) - self.process_tests(get_generator_genexpr, True) - self.process_tests(get_generator_genfunc, False) + self.process_tests(get_generator_genexpr, False) + self.process_tests(get_generator_genfunc, True) def test_new_gen_from_gi_code(self): def new_gen_from_gi_code(g, obj): generator_func = types.FunctionType(g.gi_code, {}) return generator_func(obj) - def get_generator_genexpr(obj): - return new_gen_from_gi_code(self.genexpr(), obj) + for obj in self.non_iterables: + with self.assertRaises(TypeError): + new_gen_from_gi_code(self.genexpr(), obj) def get_generator_genfunc(obj): return new_gen_from_gi_code(self.genfunc(), obj) - self.process_tests(get_generator_genexpr, True) - self.process_tests(get_generator_genfunc, False) + self.process_tests(get_generator_genfunc, True) class ExceptionTest(unittest.TestCase): @@ -1367,7 +1366,7 @@ From the Iterators list, about the types of these things. >>> type(i) >>> [s for s in dir(i) if not s.startswith('_')] -['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_suspended', 'gi_yieldfrom', 'send', 'throw'] +['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_state', 'gi_suspended', 'gi_yieldfrom', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS >>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') Implement next(self). @@ -2878,8 +2877,7 @@ __test__ = {"tut": tutorial_tests, } def load_tests(loader, tests, pattern): - from test.support.rustpython import DocTestChecker # TODO: RUSTPYTHON - tests.addTest(doctest.DocTestSuite(checker=DocTestChecker())) # TODO: RUSTPYTHON + tests.addTest(doctest.DocTestSuite()) return tests diff --git a/Lib/test/test_import/data/syntax_warnings.py b/Lib/test/test_import/data/syntax_warnings.py new file mode 100644 index 000000000..103f07b61 --- /dev/null +++ b/Lib/test/test_import/data/syntax_warnings.py @@ -0,0 +1,21 @@ +# Syntax warnings emitted in different parts of the Python compiler. + +# Parser/lexer/lexer.c +x = 1or 0 # line 4 + +# Parser/tokenizer/helpers.c +'\z' # line 7 + +# Parser/string_parser.c +'\400' # line 10 + +# _PyCompile_Warn() in Python/codegen.c +assert(x, 'message') # line 13 +x is 1 # line 14 + +# _PyErr_EmitSyntaxWarning() in Python/ast_preprocess.c +def f(): + try: + pass + finally: + return 42 # line 21 diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index bb375606a..db4059b86 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -12,16 +12,7 @@ import types import unittest import test.support -from test.support import requires_specialization_ft, script_helper - -try: - import _testcapi -except ImportError: - _testcapi = None -try: - import _testinternalcapi -except ImportError: - _testinternalcapi = None +from test.support import import_helper, requires_specialization, script_helper PAIR = (0,1) @@ -202,13 +193,10 @@ INSTRUMENTED_EVENTS = [ (E.BRANCH, "branch"), ] -EXCEPT_EVENTS = [ +SIMPLE_EVENTS = INSTRUMENTED_EVENTS + [ (E.RAISE, "raise"), - (E.PY_UNWIND, "unwind"), (E.EXCEPTION_HANDLED, "exception_handled"), -] - -SIMPLE_EVENTS = INSTRUMENTED_EVENTS + EXCEPT_EVENTS + [ + (E.PY_UNWIND, "unwind"), (E.C_RAISE, "c_raise"), (E.C_RETURN, "c_return"), ] @@ -744,18 +732,6 @@ class TestDisable(MonitoringTestBase, unittest.TestCase): sys.monitoring.register_callback(TEST_TOOL, event, None) - def test_disable_illegal_events(self): - for event, name in EXCEPT_EVENTS: - try: - counter = CounterWithDisable() - counter.disable = True - sys.monitoring.register_callback(TEST_TOOL, event, counter) - sys.monitoring.set_events(TEST_TOOL, event) - with self.assertRaises(ValueError): - self.raise_handle_reraise() - finally: - sys.monitoring.set_events(TEST_TOOL, 0) - sys.monitoring.register_callback(TEST_TOOL, event, None) class ExceptionRecorder: @@ -879,7 +855,6 @@ class ExceptionMonitoringTest(CheckEvents): self.check_events(func1, [("raise", KeyError)]) - @unittest.skipUnless(_testinternalcapi, "requires _testinternalcapi") def test_implicit_stop_iteration(self): """Generators are documented as raising a StopIteration when they terminate. @@ -889,6 +864,8 @@ class ExceptionMonitoringTest(CheckEvents): This test checks that both paths record an equivalent event. """ + _testinternalcapi = import_helper.import_module("_testinternalcapi") + def gen(): yield 1 return 2 @@ -1054,9 +1031,10 @@ class ExceptionMonitoringTest(CheckEvents): ) self.assertEqual(events[0], ("throw", IndexError)) - @unittest.skipUnless(_testinternalcapi, "requires _testinternalcapi") - @requires_specialization_ft + @requires_specialization def test_no_unwind_for_shim_frame(self): + _testinternalcapi = import_helper.import_module("_testinternalcapi") + class ValueErrorRaiser: def __init__(self): raise ValueError() @@ -1222,19 +1200,20 @@ class TestLineAndInstructionEvents(CheckEvents): line3 = 3 self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'get_events', 10), - ('line', 'func1', 1), - ('instruction', 'func1', 2), - ('instruction', 'func1', 4), - ('line', 'func1', 2), - ('instruction', 'func1', 6), - ('instruction', 'func1', 8), - ('line', 'func1', 3), - ('instruction', 'func1', 10), - ('instruction', 'func1', 12), - ('instruction', 'func1', 14), - ('instruction', 'func1', 16), - ('line', 'get_events', 11)]) + ("line", "get_events", 10), + ("line", "func1", 1), + ("instruction", "func1", 4), + ("instruction", "func1", 6), + ("line", "func1", 2), + ("instruction", "func1", 8), + ("instruction", "func1", 10), + ("line", "func1", 3), + ("instruction", "func1", 12), + ("instruction", "func1", 14), + ("instruction", "func1", 16), + ("instruction", "func1", 18), + ("line", "get_events", 11), + ]) def test_c_call(self): @@ -1244,22 +1223,23 @@ class TestLineAndInstructionEvents(CheckEvents): line3 = 3 self.check_events(func2, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'get_events', 10), - ('line', 'func2', 1), - ('instruction', 'func2', 2), - ('instruction', 'func2', 4), - ('line', 'func2', 2), - ('instruction', 'func2', 6), - ('instruction', 'func2', 8), - ('instruction', 'func2', 28), - ('instruction', 'func2', 30), - ('instruction', 'func2', 38), - ('line', 'func2', 3), - ('instruction', 'func2', 40), - ('instruction', 'func2', 42), - ('instruction', 'func2', 44), - ('instruction', 'func2', 46), - ('line', 'get_events', 11)]) + ("line", "get_events", 10), + ("line", "func2", 1), + ("instruction", "func2", 4), + ("instruction", "func2", 6), + ("line", "func2", 2), + ("instruction", "func2", 8), + ("instruction", "func2", 10), + ("instruction", "func2", 30), + ("instruction", "func2", 32), + ("instruction", "func2", 40), + ("line", "func2", 3), + ("instruction", "func2", 42), + ("instruction", "func2", 44), + ("instruction", "func2", 46), + ("instruction", "func2", 48), + ("line", "get_events", 11), + ]) def test_try_except(self): @@ -1272,28 +1252,29 @@ class TestLineAndInstructionEvents(CheckEvents): line = 6 self.check_events(func3, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ - ('line', 'get_events', 10), - ('line', 'func3', 1), - ('instruction', 'func3', 2), - ('line', 'func3', 2), - ('instruction', 'func3', 4), - ('instruction', 'func3', 6), - ('line', 'func3', 3), - ('instruction', 'func3', 8), - ('instruction', 'func3', 18), - ('instruction', 'func3', 20), - ('line', 'func3', 4), - ('instruction', 'func3', 22), - ('line', 'func3', 5), - ('instruction', 'func3', 24), - ('instruction', 'func3', 26), - ('instruction', 'func3', 28), - ('line', 'func3', 6), - ('instruction', 'func3', 30), - ('instruction', 'func3', 32), - ('instruction', 'func3', 34), - ('instruction', 'func3', 36), - ('line', 'get_events', 11)]) + ("line", "get_events", 10), + ("line", "func3", 1), + ("instruction", "func3", 4), + ("line", "func3", 2), + ("instruction", "func3", 6), + ("instruction", "func3", 8), + ("line", "func3", 3), + ("instruction", "func3", 10), + ("instruction", "func3", 20), + ("instruction", "func3", 22), + ("line", "func3", 4), + ("instruction", "func3", 24), + ("line", "func3", 5), + ("instruction", "func3", 26), + ("instruction", "func3", 28), + ("instruction", "func3", 30), + ("line", "func3", 6), + ("instruction", "func3", 32), + ("instruction", "func3", 34), + ("instruction", "func3", 36), + ("instruction", "func3", 38), + ("line", "get_events", 11), + ]) def test_with_restart(self): def func1(): @@ -1304,16 +1285,16 @@ class TestLineAndInstructionEvents(CheckEvents): self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ ('line', 'get_events', 10), ('line', 'func1', 1), - ('instruction', 'func1', 2), ('instruction', 'func1', 4), - ('line', 'func1', 2), ('instruction', 'func1', 6), + ('line', 'func1', 2), ('instruction', 'func1', 8), - ('line', 'func1', 3), ('instruction', 'func1', 10), + ('line', 'func1', 3), ('instruction', 'func1', 12), ('instruction', 'func1', 14), ('instruction', 'func1', 16), + ('instruction', 'func1', 18), ('line', 'get_events', 11)]) sys.monitoring.restart_events() @@ -1321,16 +1302,16 @@ class TestLineAndInstructionEvents(CheckEvents): self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ ('line', 'get_events', 10), ('line', 'func1', 1), - ('instruction', 'func1', 2), ('instruction', 'func1', 4), - ('line', 'func1', 2), ('instruction', 'func1', 6), + ('line', 'func1', 2), ('instruction', 'func1', 8), - ('line', 'func1', 3), ('instruction', 'func1', 10), + ('line', 'func1', 3), ('instruction', 'func1', 12), ('instruction', 'func1', 14), ('instruction', 'func1', 16), + ('instruction', 'func1', 18), ('line', 'get_events', 11)]) def test_turn_off_only_instruction(self): @@ -1378,10 +1359,10 @@ class TestInstallIncrementally(MonitoringTestBase, unittest.TestCase): line1 = 1 MUST_INCLUDE_LI = [ - ('instruction', 'func1', 2), - ('line', 'func1', 2), ('instruction', 'func1', 4), - ('instruction', 'func1', 6)] + ('line', 'func1', 2), + ('instruction', 'func1', 6), + ('instruction', 'func1', 8)] def test_line_then_instruction(self): recorders = [ LineRecorder, InstructionRecorder ] @@ -1398,11 +1379,11 @@ class TestInstallIncrementally(MonitoringTestBase, unittest.TestCase): len(()) MUST_INCLUDE_CI = [ - ('instruction', 'func2', 2), + ('instruction', 'func2', 4), ('call', 'func2', sys.monitoring.MISSING), ('call', 'len', ()), - ('instruction', 'func2', 12), - ('instruction', 'func2', 14)] + ('instruction', 'func2', 14), + ('instruction', 'func2', 16)] @@ -1486,8 +1467,334 @@ class TestLocalEvents(MonitoringTestBase, unittest.TestCase): ('line', 'func3', 6)]) def test_set_non_local_event(self): + # C_RETURN/C_RAISE are ancillary (derived) events — not settable as local with self.assertRaises(ValueError): - sys.monitoring.set_local_events(TEST_TOOL, just_call.__code__, E.RAISE) + sys.monitoring.set_local_events(TEST_TOOL, just_call.__code__, E.C_RETURN) + + def test_local_reraise(self): + """RERAISE fires as a local event only for the instrumented code object.""" + + def foo(): + try: + raise RuntimeError("test") + except RuntimeError: + raise + + def bar(): + try: + raise RuntimeError("test") + except RuntimeError: + raise + + events = set() + + def callback(code, offset, exc): + events.add(code.co_name) + + try: + sys.monitoring.register_callback(TEST_TOOL, E.RERAISE, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.RERAISE) + try: + foo() + except RuntimeError: + pass + try: + bar() # should NOT trigger the callback + except RuntimeError: + pass + self.assertEqual(events, {'foo'}) + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.RERAISE, None) + + def test_local_reraise_disable(self): + """Returning DISABLE from a RERAISE callback disables it for that code object.""" + + call_count = 0 + + def foo(): + try: + raise RuntimeError("test") + except RuntimeError: + raise + + def callback(code, offset, exc): + nonlocal call_count + call_count += 1 + return sys.monitoring.DISABLE + + try: + sys.monitoring.register_callback(TEST_TOOL, E.RERAISE, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.RERAISE) + try: + foo() + except RuntimeError: + pass + self.assertEqual(call_count, 1) + try: + foo() + except RuntimeError: + pass + self.assertEqual(call_count, 1) # not fired again — disabled + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.RERAISE, None) + + def test_local_py_throw(self): + """PY_THROW fires as a local event only for the instrumented code object.""" + + def gen_foo(): + yield 1 + yield 2 + + def gen_bar(): + yield 1 + yield 2 + + events = [] + + def callback(code, offset, exc): + events.append(code.co_name) + + try: + sys.monitoring.register_callback(TEST_TOOL, E.PY_THROW, callback) + sys.monitoring.set_local_events(TEST_TOOL, gen_foo.__code__, E.PY_THROW) + + g = gen_foo() + next(g) + try: + g.throw(RuntimeError("test")) + except RuntimeError: + pass + + h = gen_bar() + next(h) + try: + h.throw(RuntimeError("test")) # should NOT trigger the callback + except RuntimeError: + pass + + self.assertEqual(events, ['gen_foo']) + finally: + sys.monitoring.set_local_events(TEST_TOOL, gen_foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_THROW, None) + + def test_local_py_throw_disable(self): + """Returning DISABLE from a PY_THROW callback disables it for that code object.""" + + call_count = 0 + + def gen_foo(): + yield 1 + yield 2 + + def callback(code, offset, exc): + nonlocal call_count + call_count += 1 + return sys.monitoring.DISABLE + + try: + sys.monitoring.register_callback(TEST_TOOL, E.PY_THROW, callback) + sys.monitoring.set_local_events(TEST_TOOL, gen_foo.__code__, E.PY_THROW) + + g = gen_foo() + next(g) + try: + g.throw(RuntimeError("test")) + except RuntimeError: + pass + self.assertEqual(call_count, 1) + + g2 = gen_foo() + next(g2) + try: + g2.throw(RuntimeError("test")) + except RuntimeError: + pass + self.assertEqual(call_count, 1) # not fired again — disabled + finally: + sys.monitoring.set_local_events(TEST_TOOL, gen_foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_THROW, None) + + def test_local_raise(self): + """RAISE fires as a local event only for the instrumented code object.""" + + def foo(): + try: + raise RuntimeError("test") + except RuntimeError: + pass + + def bar(): + try: + raise RuntimeError("test") + except RuntimeError: + pass + + events = [] + + def callback(code, offset, exc): + events.append(code.co_name) + + try: + sys.monitoring.register_callback(TEST_TOOL, E.RAISE, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.RAISE) + foo() + bar() # should NOT trigger the callback + self.assertEqual(events, ['foo']) + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.RAISE, None) + + def test_local_raise_disable(self): + """Returning DISABLE from a RAISE callback disables it for that code object.""" + + call_count = 0 + + def foo(): + try: + raise RuntimeError("test") + except RuntimeError: + pass + + def callback(code, offset, exc): + nonlocal call_count + call_count += 1 + return sys.monitoring.DISABLE + + try: + sys.monitoring.register_callback(TEST_TOOL, E.RAISE, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.RAISE) + foo() + self.assertEqual(call_count, 1) + foo() + self.assertEqual(call_count, 1) # not fired again — disabled + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.RAISE, None) + + def test_local_exception_handled(self): + """EXCEPTION_HANDLED fires as a local event only for the instrumented code object.""" + + def foo(): + try: + raise RuntimeError("test") + except RuntimeError: + pass + + def bar(): + try: + raise RuntimeError("test") + except RuntimeError: + pass + + events = [] + + def callback(code, offset, exc): + events.append(code.co_name) + + try: + sys.monitoring.register_callback(TEST_TOOL, E.EXCEPTION_HANDLED, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.EXCEPTION_HANDLED) + foo() + bar() # should NOT trigger the callback + self.assertEqual(events, ['foo']) + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.EXCEPTION_HANDLED, None) + + def test_local_exception_handled_disable(self): + """Returning DISABLE from an EXCEPTION_HANDLED callback disables it for that code object.""" + + call_count = 0 + + def foo(): + try: + raise RuntimeError("test") + except RuntimeError: + pass + + def callback(code, offset, exc): + nonlocal call_count + call_count += 1 + return sys.monitoring.DISABLE + + try: + sys.monitoring.register_callback(TEST_TOOL, E.EXCEPTION_HANDLED, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.EXCEPTION_HANDLED) + foo() + self.assertEqual(call_count, 1) + foo() + self.assertEqual(call_count, 1) # not fired again — disabled + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.EXCEPTION_HANDLED, None) + + def test_local_py_unwind(self): + """PY_UNWIND fires as a local event only for the instrumented code object.""" + + def foo(): + raise RuntimeError("test") + + def bar(): + raise RuntimeError("test") + + events = [] + + def callback(code, offset, exc): + events.append(code.co_name) + + try: + sys.monitoring.register_callback(TEST_TOOL, E.PY_UNWIND, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.PY_UNWIND) + + try: + foo() + except RuntimeError: + pass + + try: + bar() # should NOT trigger the callback + except RuntimeError: + pass + + self.assertEqual(events, ['foo']) + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_UNWIND, None) + + def test_local_py_unwind_disable(self): + """Returning DISABLE from a PY_UNWIND callback disables it for that code object.""" + + call_count = 0 + + def foo(): + raise RuntimeError("test") + + def callback(code, offset, exc): + nonlocal call_count + call_count += 1 + return sys.monitoring.DISABLE + + try: + sys.monitoring.register_callback(TEST_TOOL, E.PY_UNWIND, callback) + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, E.PY_UNWIND) + + try: + foo() + except RuntimeError: + pass + self.assertEqual(call_count, 1) # fired once + + try: + foo() + except RuntimeError: + pass + self.assertEqual(call_count, 1) # not fired again — disabled by DISABLE return + + finally: + sys.monitoring.set_local_events(TEST_TOOL, foo.__code__, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_UNWIND, None) def line_from_offset(code, offset): for start, end, line in code.co_lines(): @@ -1617,11 +1924,11 @@ class TestBranchAndJumpEvents(CheckEvents): ('branch right', 'whilefunc', 1, 3)]) self.check_events(func, recorders = BRANCH_OFFSET_RECORDERS, expected = [ - ('branch left', 'func', 28, 32), - ('branch right', 'func', 44, 58), - ('branch left', 'func', 28, 32), - ('branch left', 'func', 44, 50), - ('branch right', 'func', 28, 70)]) + ('branch left', 'func', 32, 36), + ('branch right', 'func', 48, 62), + ('branch left', 'func', 32, 36), + ('branch left', 'func', 48, 54), + ('branch right', 'func', 32, 74)]) def test_except_star(self): @@ -1648,8 +1955,8 @@ class TestBranchAndJumpEvents(CheckEvents): ('branch', 'func', 4, 4), ('line', 'func', 5), ('line', 'meth', 1), - ('jump', 'func', 5, '[offset=120]'), - ('branch', 'func', '[offset=124]', '[offset=130]'), + ('jump', 'func', 5, '[offset=122]'), + ('branch', 'func', '[offset=126]', '[offset=132]'), ('line', 'get_events', 11)]) self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [ @@ -1663,8 +1970,8 @@ class TestBranchAndJumpEvents(CheckEvents): ('line', 'func', 5), ('line', 'meth', 1), ('return', 'meth', None), - ('jump', 'func', 5, '[offset=120]'), - ('branch', 'func', '[offset=124]', '[offset=130]'), + ('jump', 'func', 5, '[offset=122]'), + ('branch', 'func', '[offset=126]', '[offset=132]'), ('return', 'func', None), ('line', 'get_events', 11)]) @@ -1676,8 +1983,8 @@ class TestBranchAndJumpEvents(CheckEvents): n += 1 return None - in_loop = ('branch left', 'foo', 10, 16) - exit_loop = ('branch right', 'foo', 10, 40) + in_loop = ('branch left', 'foo', 12, 18) + exit_loop = ('branch right', 'foo', 12, 42) self.check_events(foo, recorders = BRANCH_OFFSET_RECORDERS, expected = [ in_loop, in_loop, @@ -2150,8 +2457,8 @@ class TestRegressions(MonitoringTestBase, unittest.TestCase): finally: sys.monitoring.set_events(TEST_TOOL, 0) - @unittest.skipUnless(_testinternalcapi, "requires _testinternalcapi") def test_108390(self): + _testinternalcapi = import_helper.import_module("_testinternalcapi") class Foo: def __init__(self, set_event): @@ -2209,6 +2516,21 @@ class TestRegressions(MonitoringTestBase, unittest.TestCase): sys.monitoring.restart_events() sys.monitoring.set_events(0, 0) + def test_134879(self): + # gh-134789 + # Specialized FOR_ITER not incrementing index + def foo(): + t = 0 + for i in [1,2,3,4]: + t += i + self.assertEqual(t, 10) + + sys.monitoring.use_tool_id(0, "test") + self.addCleanup(sys.monitoring.free_tool_id, 0) + sys.monitoring.set_local_events(0, foo.__code__, E.BRANCH_LEFT | E.BRANCH_RIGHT) + foo() + sys.monitoring.set_local_events(0, foo.__code__, 0) + class TestOptimizer(MonitoringTestBase, unittest.TestCase): @@ -2227,8 +2549,9 @@ class TestOptimizer(MonitoringTestBase, unittest.TestCase): class TestTier2Optimizer(CheckEvents): - @unittest.skipUnless(_testinternalcapi, "requires _testinternalcapi") def test_monitoring_already_opimized_loop(self): + _testinternalcapi = import_helper.import_module("_testinternalcapi") + def test_func(recorder): set_events = sys.monitoring.set_events line = E.LINE @@ -2262,23 +2585,24 @@ class TestMonitoringAtShutdown(unittest.TestCase): script_helper.run_test_script(script) -@unittest.skipUnless(_testcapi, "requires _testcapi") class TestCApiEventGeneration(MonitoringTestBase, unittest.TestCase): class Scope: def __init__(self, *args): + self._testcapi = import_helper.import_module("_testcapi") self.args = args def __enter__(self): - _testcapi.monitoring_enter_scope(*self.args) + self._testcapi.monitoring_enter_scope(*self.args) def __exit__(self, *args): - _testcapi.monitoring_exit_scope() + self._testcapi.monitoring_exit_scope() def setUp(self): super(TestCApiEventGeneration, self).setUp() - capi = _testcapi + self._testcapi = import_helper.import_module("_testcapi") + capi = self._testcapi self.codelike = capi.CodeLike(2) @@ -2347,7 +2671,7 @@ class TestCApiEventGeneration(MonitoringTestBase, unittest.TestCase): def test_fire_event(self): for expected, event, function, *args in self.cases: offset = 0 - self.codelike = _testcapi.CodeLike(1) + self.codelike = self._testcapi.CodeLike(1) with self.subTest(function.__name__): args_ = (self.codelike, offset) + tuple(args) self.check_event_count(event, function, args_, expected) @@ -2358,7 +2682,7 @@ class TestCApiEventGeneration(MonitoringTestBase, unittest.TestCase): continue assert args and isinstance(args[-1], BaseException) offset = 0 - self.codelike = _testcapi.CodeLike(1) + self.codelike = self._testcapi.CodeLike(1) with self.subTest(function.__name__): args_ = (self.codelike, offset) + tuple(args[:-1]) + (None,) evt = int(math.log2(event)) @@ -2368,7 +2692,7 @@ class TestCApiEventGeneration(MonitoringTestBase, unittest.TestCase): def test_fire_event_failing_callback(self): for expected, event, function, *args in self.cases: offset = 0 - self.codelike = _testcapi.CodeLike(1) + self.codelike = self._testcapi.CodeLike(1) with self.subTest(function.__name__): args_ = (self.codelike, offset) + tuple(args) exc = OSError(42) @@ -2418,12 +2742,14 @@ class TestCApiEventGeneration(MonitoringTestBase, unittest.TestCase): def test_disable_event(self): for expected, event, function, *args in self.cases: offset = 0 - self.codelike = _testcapi.CodeLike(2) + self.codelike = self._testcapi.CodeLike(2) with self.subTest(function.__name__): args_ = (self.codelike, 0) + tuple(args) self.check_disable(event, function, args_, expected) def test_enter_scope_two_events(self): + _testcapi = self._testcapi + try: yield_counter = CounterWithDisable() unwind_counter = CounterWithDisable() diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 66af5ae7c..1c683077e 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -13,7 +13,7 @@ except ImportError: from test import support from test.support.bytecode_helper import ( - BytecodeTestCase, CfgOptimizationTestCase, CompilationStepTestCase) + BytecodeTestCase, CfgOptimizationTestCase) def compile_pattern_with_fast_locals(pattern): @@ -106,7 +106,7 @@ class TestTranforms(BytecodeTestCase): self.check_lnotab(code) def test_global_as_constant(self): - # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False + # LOAD_GLOBAL None/True/False --> LOAD_COMMON_CONSTANT None/True/False def f(): x = None x = None @@ -121,7 +121,7 @@ class TestTranforms(BytecodeTestCase): for func, elem in ((f, None), (g, True), (h, False)): with self.subTest(func=func): self.assertNotInBytecode(func, 'LOAD_GLOBAL') - self.assertInBytecode(func, 'LOAD_CONST', elem) + self.assertInBytecode(func, 'LOAD_COMMON_CONSTANT', elem) self.check_lnotab(func) def f(): @@ -129,7 +129,7 @@ class TestTranforms(BytecodeTestCase): return None self.assertNotInBytecode(f, 'LOAD_GLOBAL') - self.assertInBytecode(f, 'LOAD_CONST', None) + self.assertInBytecode(f, 'LOAD_COMMON_CONSTANT', None) self.check_lnotab(f) def test_while_one(self): @@ -146,13 +146,14 @@ class TestTranforms(BytecodeTestCase): def test_pack_unpack(self): for line, elem in ( - ('a, = a,', 'LOAD_CONST',), + ('a, = a,', None), ('a, b = a, b', 'SWAP',), ('a, b, c = a, b, c', 'SWAP',), ): with self.subTest(line=line): code = compile(line,'','single') - self.assertInBytecode(code, elem) + if elem is not None: + self.assertInBytecode(code, elem) self.assertNotInBytecode(code, 'BUILD_TUPLE') self.assertNotInBytecode(code, 'UNPACK_SEQUENCE') self.check_lnotab(code) @@ -174,10 +175,10 @@ class TestTranforms(BytecodeTestCase): # Long tuples should be folded too. code = compile(repr(tuple(range(10000))),'','single') self.assertNotInBytecode(code, 'BUILD_TUPLE') - # One LOAD_CONST for the tuple, one for the None return value + # One LOAD_CONST for the tuple; None return value uses LOAD_COMMON_CONSTANT load_consts = [instr for instr in dis.get_instructions(code) if instr.opname == 'LOAD_CONST'] - self.assertEqual(len(load_consts), 2) + self.assertEqual(len(load_consts), 1) self.check_lnotab(code) # Bug 1053819: Tuple of constants misidentified when presented with: @@ -283,11 +284,11 @@ class TestTranforms(BytecodeTestCase): ('-0.0', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.0), ('-(1.0-1.0)', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.0), ('-0.5', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.5), - ('---1', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -1), + ('---1', 'UNARY_NEGATIVE', None, True, 'LOAD_COMMON_CONSTANT', -1), ('---""', 'UNARY_NEGATIVE', None, False, None, None), ('~~~1', 'UNARY_INVERT', None, True, 'LOAD_CONST', -2), ('~~~""', 'UNARY_INVERT', None, False, None, None), - ('not not True', 'UNARY_NOT', None, True, 'LOAD_CONST', True), + ('not not True', 'UNARY_NOT', None, True, 'LOAD_COMMON_CONSTANT', True), ('not not x', 'UNARY_NOT', None, True, 'LOAD_NAME', 'x'), # this should be optimized regardless of constant or not ('+++1', 'CALL_INTRINSIC_1', intrinsic_positive, True, 'LOAD_SMALL_INT', 1), ('---x', 'UNARY_NEGATIVE', None, False, None, None), @@ -326,7 +327,7 @@ class TestTranforms(BytecodeTestCase): ('1 + 2', 'NB_ADD', True, 'LOAD_SMALL_INT', 3), ('1 + 2 + 3', 'NB_ADD', True, 'LOAD_SMALL_INT', 6), ('1 + ""', 'NB_ADD', False, None, None), - ('1 - 2', 'NB_SUBTRACT', True, 'LOAD_CONST', -1), + ('1 - 2', 'NB_SUBTRACT', True, 'LOAD_COMMON_CONSTANT', -1), ('1 - 2 - 3', 'NB_SUBTRACT', True, 'LOAD_CONST', -4), ('1 - ""', 'NB_SUBTRACT', False, None, None), ('2 * 2', 'NB_MULTIPLY', True, 'LOAD_SMALL_INT', 4), @@ -734,23 +735,27 @@ class TestTranforms(BytecodeTestCase): with self.assertRaisesRegex(TypeError, 'not all arguments converted during string formatting'): eval("'%s' % (x, y)", {'x': 1, 'y': 2}) - with self.assertRaisesRegex(ValueError, 'incomplete format'): + with self.assertRaisesRegex(ValueError, 'stray % at position 2'): eval("'%s%' % (x,)", {'x': 1234}) - with self.assertRaisesRegex(ValueError, 'incomplete format'): + with self.assertRaisesRegex(ValueError, 'stray % at position 4'): eval("'%s%%%' % (x,)", {'x': 1234}) with self.assertRaisesRegex(TypeError, 'not enough arguments for format string'): eval("'%s%z' % (x,)", {'x': 1234}) - with self.assertRaisesRegex(ValueError, 'unsupported format character'): + with self.assertRaisesRegex(ValueError, + 'unsupported format %z at position 2'): eval("'%s%z' % (x, 5)", {'x': 1234}) with self.assertRaisesRegex(TypeError, 'format argument 1: %d requires a real number, not str'): eval("'%d' % (x,)", {'x': '1234'}) - with self.assertRaisesRegex(TypeError, 'an integer is required, not float'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %x requires an integer, not float'): eval("'%x' % (x,)", {'x': 1234.56}) - with self.assertRaisesRegex(TypeError, 'an integer is required, not str'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %x requires an integer, not str'): eval("'%x' % (x,)", {'x': '1234'}) - with self.assertRaisesRegex(TypeError, 'must be real number, not str'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %f requires a real number, not str'): eval("'%f' % (x,)", {'x': '1234'}) with self.assertRaisesRegex(TypeError, 'not enough arguments for format string'): @@ -1118,6 +1123,13 @@ class TestMarkingVariablesAsUnKnown(BytecodeTestCase): self.assertInBytecode(f, "LOAD_FAST_BORROW") self.assertNotInBytecode(f, "LOAD_FAST_CHECK") + def test_import_from_doesnt_clobber_load_fast_borrow(self): + def f(self): + if x: pass + self.x + from shutil import ExecError + print(ExecError) + self.assertInBytecode(f, "LOAD_FAST_BORROW", "self") class DirectCfgOptimizerTests(CfgOptimizationTestCase): @@ -1507,7 +1519,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_SMALL_INT', 1, 0), ('LOAD_SMALL_INT', 2, 0), ('BUILD_LIST', 2, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1520,7 +1532,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ] after = [ ('LOAD_CONST', 1, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1528,7 +1540,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): end, ('END_FOR', None, 0), ('POP_ITER', None, 0), - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, (1, 2)]) @@ -1538,7 +1550,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_SMALL_INT', 1, 0), ('LOAD_NAME', 0, 0), ('BUILD_LIST', 2, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1553,7 +1565,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_SMALL_INT', 1, 0), ('LOAD_NAME', 0, 0), ('BUILD_TUPLE', 2, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1561,7 +1573,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): end, ('END_FOR', None, 0), ('POP_ITER', None, 0), - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None]) @@ -1572,7 +1584,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_SMALL_INT', 1, 0), ('LOAD_SMALL_INT', 2, 0), ('BUILD_SET', 2, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1585,7 +1597,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ] after = [ ('LOAD_CONST', 1, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1593,7 +1605,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): end, ('END_FOR', None, 0), ('POP_ITER', None, 0), - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, frozenset({1, 2})]) @@ -1604,7 +1616,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_SMALL_INT', 1, 0), ('LOAD_NAME', 0, 0), ('BUILD_SET', 2, 0), - ('GET_ITER', None, 0), + ('GET_ITER', 0, 0), start := self.Label(), ('FOR_ITER', end := self.Label(), 0), ('STORE_FAST', 0, 0), @@ -1615,7 +1627,22 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_CONST', 0, 0), ('RETURN_VALUE', None, 0), ] - self.cfg_optimization_test(same, same, consts=[None], expected_consts=[None]) + expected = [ + ('LOAD_SMALL_INT', 1, 0), + ('LOAD_NAME', 0, 0), + ('BUILD_SET', 2, 0), + ('GET_ITER', 0, 0), + start := self.Label(), + ('FOR_ITER', end := self.Label(), 0), + ('STORE_FAST', 0, 0), + ('JUMP', start, 0), + end, + ('END_FOR', None, 0), + ('POP_ITER', None, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), + ('RETURN_VALUE', None, 0), + ] + self.cfg_optimization_test(same, expected, consts=[None], expected_consts=[None]) def test_optimize_literal_list_contains(self): # x in [1, 2] ==> x in (1, 2) @@ -1634,7 +1661,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_CONST', 1, 0), ('CONTAINS_OP', 0, 0), ('POP_TOP', None, 0), - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, (1, 2)]) @@ -1657,7 +1684,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('BUILD_TUPLE', 2, 0), ('CONTAINS_OP', 0, 0), ('POP_TOP', None, 0), - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None]) @@ -1679,7 +1706,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_CONST', 1, 0), ('CONTAINS_OP', 0, 0), ('POP_TOP', None, 0), - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, frozenset({1, 2})]) @@ -1696,7 +1723,17 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('LOAD_CONST', 0, 0), ('RETURN_VALUE', None, 0), ] - self.cfg_optimization_test(same, same, consts=[None], expected_consts=[None]) + expected = [ + ('LOAD_NAME', 0, 0), + ('LOAD_SMALL_INT', 1, 0), + ('LOAD_NAME', 1, 0), + ('BUILD_SET', 2, 0), + ('CONTAINS_OP', 0, 0), + ('POP_TOP', None, 0), + ('LOAD_COMMON_CONSTANT', 7, 0), + ('RETURN_VALUE', None, 0), + ] + self.cfg_optimization_test(same, expected, consts=[None], expected_consts=[None]) def test_optimize_unary_not(self): # test folding @@ -1707,10 +1744,10 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('RETURN_VALUE', None, 0), ] after = [ - ('LOAD_CONST', 1, 0), + ('LOAD_COMMON_CONSTANT', 10, 0), ('RETURN_VALUE', None, 0), ] - self.cfg_optimization_test(before, after, consts=[], expected_consts=[True, False]) + self.cfg_optimization_test(before, after, consts=[], expected_consts=[True]) # test cancel out before = [ @@ -1758,7 +1795,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('RETURN_VALUE', None, 0), ] after = [ - ('LOAD_CONST', 0, 0), + ('LOAD_COMMON_CONSTANT', 9, 0), ('RETURN_VALUE', None, 0), ] self.cfg_optimization_test(before, after, consts=[], expected_consts=[True]) @@ -1774,10 +1811,10 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ('RETURN_VALUE', None, 0), ] after = [ - ('LOAD_CONST', 1, 0), + ('LOAD_COMMON_CONSTANT', 10, 0), ('RETURN_VALUE', None, 0), ] - self.cfg_optimization_test(before, after, consts=[], expected_consts=[True, False]) + self.cfg_optimization_test(before, after, consts=[], expected_consts=[True]) # test cancel out & eliminate to bool (to bool stays as we are not iterating to a fixed point) before = [ @@ -2393,7 +2430,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ("LOAD_FAST", 1, 4), ("LIST_EXTEND", 1, 5), ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6), - ("GET_ITER", None, 7), + ("GET_ITER", 0, 7), top := self.Label(), ("FOR_ITER", end := self.Label(), 8), ("STORE_FAST", 2, 9), @@ -2411,7 +2448,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): ("LOAD_FAST_BORROW", 1, 4), ("LIST_EXTEND", 1, 5), ("NOP", None, 6), # ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 6), - ("GET_ITER", None, 7), + ("GET_ITER", 0, 7), top := self.Label(), ("FOR_ITER", end := self.Label(), 8), ("STORE_FAST", 2, 9), @@ -2419,7 +2456,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): end, ("END_FOR", None, 11), ("POP_TOP", None, 12), - ("LOAD_CONST", 0, 13), + ("LOAD_COMMON_CONSTANT", 7, 13), ("RETURN_VALUE", None, 14), ] self.cfg_optimization_test(insts, expected_insts, consts=[None]) @@ -2433,6 +2470,168 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase): self.assertEqual(b, [3, 2, 1, 0]) self.assertEqual(items, []) + def test_fold_constant_big_list_for_iter(self): + # for x in [c1, c2, ..., cN] (N > 30) should fold to LOAD_CONST tuple + consts = 35 + before = ( + [("BUILD_LIST", 0, 1)] + + [("LOAD_CONST", 0, 2), ("LIST_APPEND", 1, 3)] * consts + + [("GET_ITER", 0, 4), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 5), + ("STORE_FAST", 0, 6), + ("JUMP", top, 7), + end, + ("END_FOR", None, 8), + ("POP_ITER", None, 9), + ("LOAD_CONST", 0, 10), + ("RETURN_VALUE", None, 11)] + ) + after = [ + ("LOAD_CONST", 1, 3), + ("GET_ITER", 0, 4), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 5), + ("STORE_FAST", 0, 6), + ("JUMP", top, 7), + end, + ("END_FOR", None, 8), + ("POP_ITER", None, 9), + ("LOAD_CONST", 0, 10), + ("RETURN_VALUE", None, 11), + ] + result_const = tuple(["test"] * consts) + self.cfg_optimization_test(before, after, consts=["test"], + expected_consts=["test", result_const]) + + def test_fold_constant_big_set_for_iter(self): + # for x in {c1, c2, ..., cN} (N > 30) should fold to LOAD_CONST frozenset + before = [ + ("BUILD_SET", 0, 1), + ("LOAD_SMALL_INT", 1, 2), ("SET_ADD", 1, 3), + ("LOAD_SMALL_INT", 2, 4), ("SET_ADD", 1, 5), + ("LOAD_SMALL_INT", 3, 6), ("SET_ADD", 1, 7), + ("GET_ITER", 0, 8), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 9), + ("STORE_FAST", 0, 10), + ("JUMP", top, 11), + end, + ("END_FOR", None, 12), + ("POP_ITER", None, 13), + ("LOAD_CONST", 0, 14), + ("RETURN_VALUE", None, 15), + ] + after = [ + ("LOAD_CONST", 1, 7), + ("GET_ITER", 0, 8), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 9), + ("STORE_FAST", 0, 10), + ("JUMP", top, 11), + end, + ("END_FOR", None, 12), + ("POP_ITER", None, 13), + ("LOAD_CONST", 0, 14), + ("RETURN_VALUE", None, 15), + ] + self.cfg_optimization_test(before, after, consts=["test"], + expected_consts=["test", frozenset({1, 2, 3})]) + + def test_fold_constant_list_to_tuple_for_iter(self): + INTRINSIC_LIST_TO_TUPLE = 6 + before = [ + ("BUILD_LIST", 0, 1), + ("LOAD_SMALL_INT", 1, 2), ("LIST_APPEND", 1, 3), + ("LOAD_SMALL_INT", 2, 4), ("LIST_APPEND", 1, 5), + ("LOAD_SMALL_INT", 3, 6), ("LIST_APPEND", 1, 7), + ("CALL_INTRINSIC_1", INTRINSIC_LIST_TO_TUPLE, 8), + ("GET_ITER", 0, 9), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 10), + ("STORE_FAST", 0, 11), + ("JUMP", top, 12), + end, + ("END_FOR", None, 13), + ("POP_ITER", None, 14), + ("LOAD_CONST", 0, 15), + ("RETURN_VALUE", None, 16), + ] + after = [ + ("LOAD_CONST", 1, 8), + ("GET_ITER", 0, 9), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 10), + ("STORE_FAST", 0, 11), + ("JUMP", top, 12), + end, + ("END_FOR", None, 13), + ("POP_ITER", None, 14), + ("LOAD_CONST", 0, 15), + ("RETURN_VALUE", None, 16), + ] + self.cfg_optimization_test(before, after, consts=["test"], + expected_consts=["test", (1, 2, 3)]) + + def test_fold_constant_big_list_contains_op(self): + # x in [c1, c2, ..., cN] (N > 30) should fold to LOAD_CONST tuple + before = [ + ("LOAD_FAST", 0, 1), + ("BUILD_LIST", 0, 2), + ("LOAD_SMALL_INT", 1, 3), ("LIST_APPEND", 1, 4), + ("LOAD_SMALL_INT", 2, 5), ("LIST_APPEND", 1, 6), + ("LOAD_SMALL_INT", 3, 7), ("LIST_APPEND", 1, 8), + ("CONTAINS_OP", 0, 9), + ("RETURN_VALUE", None, 10), + ] + after = [ + ("LOAD_FAST_BORROW", 0, 1), + ("LOAD_CONST", 1, 8), + ("CONTAINS_OP", 0, 9), + ("RETURN_VALUE", None, 10), + ] + self.cfg_optimization_test(before, after, consts=[None], + expected_consts=[None, (1, 2, 3)]) + + def test_fold_constant_big_set_contains_op(self): + # x in {c1, c2, ..., cN} (N > 30) should fold to LOAD_CONST frozenset + before = [ + ("LOAD_FAST", 0, 1), + ("BUILD_SET", 0, 2), + ("LOAD_SMALL_INT", 1, 3), ("SET_ADD", 1, 4), + ("LOAD_SMALL_INT", 2, 5), ("SET_ADD", 1, 6), + ("LOAD_SMALL_INT", 3, 7), ("SET_ADD", 1, 8), + ("CONTAINS_OP", 0, 9), + ("RETURN_VALUE", None, 10), + ] + after = [ + ("LOAD_FAST_BORROW", 0, 1), + ("LOAD_CONST", 1, 8), + ("CONTAINS_OP", 0, 9), + ("RETURN_VALUE", None, 10), + ] + self.cfg_optimization_test(before, after, consts=[None], + expected_consts=[None, frozenset({1, 2, 3})]) + + def test_no_fold_big_list_for_iter_with_non_const(self): + same = [ + ("BUILD_LIST", 0, 1), + ("LOAD_SMALL_INT", 1, 2), ("LIST_APPEND", 1, 3), + ("LOAD_FAST_BORROW", 0, 4), ("LIST_APPEND", 1, 5), + ("LOAD_SMALL_INT", 3, 6), ("LIST_APPEND", 1, 7), + ("GET_ITER", 0, 8), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 9), + ("STORE_FAST", 1, 10), + ("JUMP", top, 11), + end, + ("END_FOR", None, 12), + ("POP_ITER", None, 13), + ("LOAD_CONST", 0, 14), + ("RETURN_VALUE", None, 15), + ] + self.cfg_optimization_test(same, same, consts=["test"]) + class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): def make_bb(self, insts): @@ -2443,7 +2642,7 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): maxconst = max(maxconst, arg) consts = [None for _ in range(maxconst + 1)] return insts + [ - ("LOAD_CONST", 0, last_loc + 1), + ("LOAD_COMMON_CONSTANT", 7, last_loc + 1), ("RETURN_VALUE", None, last_loc + 2), ], consts @@ -2474,7 +2673,7 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ] expected = [ ("LOAD_FAST_BORROW", 0, 1), - ("LOAD_CONST", 1, 2), + ("LOAD_COMMON_CONSTANT", 7, 2), ("SWAP", 2, 3), ("POP_TOP", None, 4), ] @@ -2512,7 +2711,13 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("STORE_FAST", 0, 3), ("POP_TOP", None, 4), ] - self.check(insts, insts) + expected = [ + ("LOAD_FAST", 0, 1), + ("LOAD_COMMON_CONSTANT", 7, 2), + ("STORE_FAST", 0, 3), + ("POP_TOP", None, 4), + ] + self.check(insts, expected) insts = [ ("LOAD_FAST", 0, 1), @@ -2521,7 +2726,14 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4), ("POP_TOP", None, 5), ] - self.check(insts, insts) + expected = [ + ("LOAD_FAST", 0, 1), + ("LOAD_COMMON_CONSTANT", 7, 2), + ("LOAD_COMMON_CONSTANT", 7, 3), + ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4), + ("POP_TOP", None, 5), + ] + self.check(insts, expected) insts = [ ("LOAD_FAST", 0, 1), @@ -2542,7 +2754,12 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("LOAD_CONST", 0, 3), ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4), ] - self.check(insts, insts) + expected = [ + ("LOAD_FAST", 0, 1), + ("LOAD_COMMON_CONSTANT", 7, 3), + ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4), + ] + self.check(insts, expected) def test_consume_no_inputs(self): insts = [ @@ -2587,7 +2804,19 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("LOAD_CONST", 0, 7), ("RETURN_VALUE", None, 8), ] - self.cfg_optimization_test(insts, insts, consts=[None]) + expected = [ + ("LOAD_FAST", 0, 1), + top := self.Label(), + ("FOR_ITER", end := self.Label(), 2), + ("STORE_FAST", 2, 3), + ("JUMP", top, 4), + end, + ("END_FOR", None, 5), + ("POP_TOP", None, 6), + ("LOAD_COMMON_CONSTANT", 7, 7), + ("RETURN_VALUE", None, 8), + ] + self.cfg_optimization_test(insts, expected, consts=[None]) def test_load_attr(self): insts = [ @@ -2656,10 +2885,10 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("LOAD_FAST", 0, 1), ("LOAD_FAST_BORROW", 1, 2), ("SEND", end := self.Label(), 3), - ("LOAD_CONST", 0, 4), + ("LOAD_COMMON_CONSTANT", 7, 4), ("RETURN_VALUE", None, 5), end, - ("LOAD_CONST", 0, 6), + ("LOAD_COMMON_CONSTANT", 7, 6), ("RETURN_VALUE", None, 7) ] self.cfg_optimization_test(insts, expected, consts=[None]) @@ -2697,7 +2926,15 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("LOAD_CONST", 0, 5), ("RETURN_VALUE", None, 6) ] - self.cfg_optimization_test(insts, insts, consts=[None]) + expected = [ + ("LOAD_COMMON_CONSTANT", 7, 1), + ("LOAD_FAST", 0, 2), + ("SET_FUNCTION_ATTRIBUTE", 2, 3), + ("STORE_FAST", 1, 4), + ("LOAD_COMMON_CONSTANT", 7, 5), + ("RETURN_VALUE", None, 6) + ] + self.cfg_optimization_test(insts, expected, consts=[None]) insts = [ ("LOAD_CONST", 0, 1), @@ -2706,7 +2943,7 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): ("RETURN_VALUE", None, 4) ] expected = [ - ("LOAD_CONST", 0, 1), + ("LOAD_COMMON_CONSTANT", 7, 1), ("LOAD_FAST_BORROW", 0, 2), ("SET_FUNCTION_ATTRIBUTE", 2, 3), ("RETURN_VALUE", None, 4) @@ -2714,22 +2951,37 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests): self.cfg_optimization_test(insts, expected, consts=[None]) def test_get_yield_from_iter(self): - # GET_YIELD_FROM_ITER may leave its operand on the stack insts = [ ("LOAD_FAST", 0, 1), - ("GET_YIELD_FROM_ITER", None, 2), - ("LOAD_CONST", 0, 3), + ("GET_ITER", 1, 2), + ("PUSH_NULL", None, 3), + ("LOAD_CONST", 0, 4), send := self.Label(), - ("SEND", end := self.Label(), 5), - ("YIELD_VALUE", 1, 6), - ("RESUME", 2, 7), - ("JUMP", send, 8), + ("SEND", end := self.Label(), 6), + ("YIELD_VALUE", 1, 7), + ("RESUME", 2, 8), + ("JUMP", send, 9), end, - ("END_SEND", None, 9), - ("LOAD_CONST", 0, 10), - ("RETURN_VALUE", None, 11), + ("END_SEND", None, 10), + ("LOAD_CONST", 0, 11), + ("RETURN_VALUE", None, 12), ] - self.cfg_optimization_test(insts, insts, consts=[None]) + expected = [ + ("LOAD_FAST", 0, 1), + ("GET_ITER", 1, 2), + ("PUSH_NULL", None, 3), + ("LOAD_COMMON_CONSTANT", 7, 4), + send := self.Label(), + ("SEND", end := self.Label(), 6), + ("YIELD_VALUE", 1, 7), + ("RESUME", 2, 8), + ("JUMP", send, 9), + end, + ("END_SEND", None, 10), + ("LOAD_COMMON_CONSTANT", 7, 11), + ("RETURN_VALUE", None, 12), + ] + self.cfg_optimization_test(insts, expected, consts=[None]) def test_push_exc_info(self): insts = [ diff --git a/crates/vm/src/builtins/frame.rs b/crates/vm/src/builtins/frame.rs index bf29caca7..d8faf0da7 100644 --- a/crates/vm/src/builtins/frame.rs +++ b/crates/vm/src/builtins/frame.rs @@ -8,7 +8,7 @@ use crate::{ class::PyClassImpl, frame::{FrameObject, FrameOwner}, function::PySetterValue, - types::{Destructor, Representable}, + types::Representable, }; use core::sync::atomic::Ordering::Relaxed; use num_traits::Zero; @@ -515,19 +515,19 @@ impl Py { ); match owner { FrameOwner::Generator => { - // FRAME_SUSPENDED (lasti > 0) cannot be cleared. FRAME_CREATED - // and finished frames go through the owner finalizer. - if self.lasti() != 0 { - return Err(vm.new_runtime_error("cannot clear a suspended frame")); - } + // RETURN_GENERATOR executes the creation preamble, so lasti + // no longer distinguishes a created frame from a suspended one. if let Some(owner) = self.iframe().generator.to_owned() { - if let Some(coro) = owner.downcast_ref::() { - let _ = PyCoroutine::del(coro, vm); + let coro = if let Some(coro) = owner.downcast_ref::() { + coro.as_coro() } else if let Some(async_gen) = owner.downcast_ref::() { - let _ = PyAsyncGen::del(async_gen, vm); + async_gen.as_coro() } else if let Some(generator) = owner.downcast_ref::() { - let _ = PyGenerator::del(generator, vm); - } + generator.as_coro() + } else { + unreachable!("generator-owned frame has no coroutine owner") + }; + coro.clear_frame(&owner, vm)?; } return Ok(()); } diff --git a/crates/vm/src/builtins/generator.rs b/crates/vm/src/builtins/generator.rs index 8eb6013e7..5e1b5dc48 100644 --- a/crates/vm/src/builtins/generator.rs +++ b/crates/vm/src/builtins/generator.rs @@ -122,6 +122,19 @@ impl Py { self.inner.running() } + #[pygetset] + fn gi_state(&self) -> &'static str { + if self.inner.closed() { + "GEN_CLOSED" + } else if self.inner.running() { + "GEN_RUNNING" + } else if self.inner.started() { + "GEN_SUSPENDED" + } else { + "GEN_CREATED" + } + } + #[pygetset] fn gi_code(&self, _vm: &VirtualMachine) -> PyRef { self.inner.code() diff --git a/crates/vm/src/coroutine.rs b/crates/vm/src/coroutine.rs index bf287c028..feb95d49c 100644 --- a/crates/vm/src/coroutine.rs +++ b/crates/vm/src/coroutine.rs @@ -495,6 +495,32 @@ impl Coro { } } + /// Clear a created generator frame without resuming its body. + pub(crate) fn clear_frame(&self, jen: &PyObject, vm: &VirtualMachine) -> PyResult<()> { + if self.closed.load() { + return Ok(()); + } + if self.running.compare_exchange(false, true).is_err() { + return Err(vm.new_runtime_error("cannot clear an executing frame")); + } + let claim = RunningGuard(self); + if self.closed.load() { + return Ok(()); + } + if self.started() { + return Err(vm.new_runtime_error("cannot clear a suspended frame")); + } + self.closed.store(true); + // Closed owners cannot resume. Publish that state and release the + // running claim before a warning hook can observe or clear us again. + drop(claim); + if jen.class().is(vm.ctx.types.coroutine_type) { + crate::warn::warn_unawaited_coroutine(jen, &self.qualname(), vm); + } + self.clear_except_code(); + Ok(()) + } + /// Whether the frame has run at all, i.e. is stopped at a `yield` rather /// than at its start. pub(crate) fn started(&self) -> bool {