]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-109039: Branch prediction for Tier 2 interpreter (#109038)
authorGuido van Rossum <guido@python.org>
Mon, 11 Sep 2023 18:20:24 +0000 (11:20 -0700)
committerGitHub <noreply@github.com>
Mon, 11 Sep 2023 18:20:24 +0000 (18:20 +0000)
This adds a 16-bit inline cache entry to the conditional branch instructions POP_JUMP_IF_{FALSE,TRUE,NONE,NOT_NONE} and their instrumented variants, which is used to keep track of the branch direction.

Each time we encounter these instructions we shift the cache entry left by one and set the bottom bit to whether we jumped.

Then when it's time to translate such a branch to Tier 2 uops, we use the bit count from the cache entry to decided whether to continue translating the "didn't jump" branch or the "jumped" branch.

The counter is initialized to a pattern of alternating ones and zeros to avoid bias.

The .pyc file magic number is updated. There's a new test, some fixes for existing tests, and a few miscellaneous cleanups.

15 files changed:
Include/internal/pycore_instruments.h
Include/internal/pycore_opcode_metadata.h
Lib/importlib/_bootstrap_external.py
Lib/opcode.py
Lib/test/support/__init__.py
Lib/test/test_capi/test_misc.py
Lib/test/test_dis.py
Lib/test/test_monitoring.py
Lib/test/test_regrtest.py
Python/bytecodes.c
Python/generated_cases.c.h
Python/instrumentation.c
Python/optimizer.c
Python/specialize.c
Tools/cases_generator/generate_cases.py

index fad475c3dafb99bc85af7c2ddc128bd60723c151..97dcfb9f8672f7f99ca97dd92cdd2279ecf7362b 100644 (file)
@@ -5,7 +5,6 @@
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
-#include "pycore_bitutils.h"      // _Py_popcount32
 #include "pycore_frame.h"         // _PyInterpreterFrame
 
 #ifdef __cplusplus
index f70b75a56c150cdf17121d6d46bc8cd407074a1c..e1de21255f64fd383636cce858f5d459c7339d63 100644 (file)
@@ -1361,11 +1361,11 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
     [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG },
-    [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
-    [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
+    [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
+    [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [IS_NONE] = { true, INSTR_FMT_IX, 0 },
-    [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
-    [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
+    [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
+    [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [GET_LEN] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG },
     [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG },
@@ -1449,10 +1449,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
     [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG },
     [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
     [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG },
-    [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
-    [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
-    [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
-    [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
+    [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
+    [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
+    [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
+    [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
     [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
     [CACHE] = { true, INSTR_FMT_IX, 0 },
     [RESERVED] = { true, INSTR_FMT_IX, 0 },
@@ -1885,7 +1885,6 @@ extern const uint8_t _PyOpcode_Caches[256];
 #ifdef NEED_OPCODE_METADATA
 const uint8_t _PyOpcode_Caches[256] = {
     [TO_BOOL] = 3,
-    [BINARY_OP] = 1,
     [BINARY_SUBSCR] = 1,
     [STORE_SUBSCR] = 1,
     [SEND] = 1,
@@ -1895,8 +1894,13 @@ const uint8_t _PyOpcode_Caches[256] = {
     [LOAD_SUPER_ATTR] = 1,
     [LOAD_ATTR] = 9,
     [COMPARE_OP] = 1,
+    [POP_JUMP_IF_FALSE] = 1,
+    [POP_JUMP_IF_TRUE] = 1,
     [FOR_ITER] = 1,
     [CALL] = 3,
+    [BINARY_OP] = 1,
+    [POP_JUMP_IF_NONE] = 1,
+    [POP_JUMP_IF_NOT_NONE] = 1,
     [JUMP_BACKWARD] = 1,
 };
 #endif // NEED_OPCODE_METADATA
index 7a83a58d0874dfe11e9ad94cd4f66d4711fc5269..843af30050016948e4a26a513fb6bfd40d4de58d 100644 (file)
@@ -456,6 +456,7 @@ _code_type = type(_write_atomic.__code__)
 #     Python 3.13a1 3558 (Reorder the stack items for CALL)
 #     Python 3.13a1 3559 (Generate opcode IDs from bytecodes.c)
 #     Python 3.13a1 3560 (Add RESUME_CHECK instruction)
+#     Python 3.13a1 3561 (Add cache entry to branch instructions)
 
 #     Python 3.14 will start with 3600
 
@@ -472,7 +473,7 @@ _code_type = type(_write_atomic.__code__)
 # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
 # in PC/launcher.c must also be updated.
 
-MAGIC_NUMBER = (3560).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3561).to_bytes(2, 'little') + b'\r\n'
 
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
index 386a2fba396a6a82ae7eb2ab13804ac329d8ba13..88f4df7c0e8c3867300b8c7bebc5cdf3b4188e42 100644 (file)
@@ -93,6 +93,18 @@ _cache_format = {
         "counter": 1,
         "version": 2,
     },
+    "POP_JUMP_IF_TRUE": {
+        "counter": 1,
+    },
+    "POP_JUMP_IF_FALSE": {
+        "counter": 1,
+    },
+    "POP_JUMP_IF_NONE": {
+        "counter": 1,
+    },
+    "POP_JUMP_IF_NOT_NONE": {
+        "counter": 1,
+    },
 }
 
 _inline_cache_entries = {
index 6fc85ff5d704e18c7da4f8aa6f543e18e4de7aa1..0d9efe10c6504c2b33e6f267a731e35a04a703b1 100644 (file)
@@ -62,6 +62,7 @@ __all__ = [
     "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
     "Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", "Py_C_RECURSION_LIMIT",
     "skip_on_s390x",
+    "without_optimizer",
     ]
 
 
@@ -2533,3 +2534,19 @@ skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == '
                                 'skipped on s390x')
 
 Py_TRACE_REFS = hasattr(sys, 'getobjects')
+
+# Decorator to disable optimizer while a function run
+def without_optimizer(func):
+    try:
+        import _testinternalcapi
+    except ImportError:
+        return func
+    @functools.wraps(func)
+    def wrapper(*args, **kwargs):
+        save_opt = _testinternalcapi.get_optimizer()
+        try:
+            _testinternalcapi.set_optimizer(None)
+            return func(*args, **kwargs)
+        finally:
+            _testinternalcapi.set_optimizer(save_opt)
+    return wrapper
index 004ce3976965568e032cf7e1c605ef2ca48f3ce8..964886ad1ca0d855e80dbf5b472a74018e2ba6db 100644 (file)
@@ -2455,7 +2455,7 @@ class TestUops(unittest.TestCase):
         opt = _testinternalcapi.get_uop_optimizer()
 
         with temporary_optimizer(opt):
-            testfunc(10)
+            testfunc(20)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2470,7 +2470,7 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(10)
+            testfunc(20)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2485,7 +2485,7 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(range(10))
+            testfunc(range(20))
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2495,12 +2495,13 @@ class TestUops(unittest.TestCase):
     def test_pop_jump_if_not_none(self):
         def testfunc(a):
             for x in a:
+                x = None
                 if x is not None:
                     x = 0
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(range(10))
+            testfunc(range(20))
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2515,7 +2516,7 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(10)
+            testfunc(20)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2530,7 +2531,7 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(10)
+            testfunc(20)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2550,7 +2551,7 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(10)
+            testfunc(20)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2568,8 +2569,8 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            total = testfunc(10)
-            self.assertEqual(total, 45)
+            total = testfunc(20)
+            self.assertEqual(total, 190)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2589,9 +2590,9 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            a = list(range(10))
+            a = list(range(20))
             total = testfunc(a)
-            self.assertEqual(total, 45)
+            self.assertEqual(total, 190)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2611,9 +2612,9 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            a = tuple(range(10))
+            a = tuple(range(20))
             total = testfunc(a)
-            self.assertEqual(total, 45)
+            self.assertEqual(total, 190)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2647,7 +2648,7 @@ class TestUops(unittest.TestCase):
 
         opt = _testinternalcapi.get_uop_optimizer()
         with temporary_optimizer(opt):
-            testfunc(10)
+            testfunc(20)
 
         ex = get_first_executor(testfunc)
         self.assertIsNotNone(ex)
@@ -2655,6 +2656,22 @@ class TestUops(unittest.TestCase):
         self.assertIn("_PUSH_FRAME", uops)
         self.assertIn("_BINARY_OP_ADD_INT", uops)
 
+    def test_branch_taken(self):
+        def testfunc(n):
+            for i in range(n):
+                if i < 0:
+                    i = 0
+                else:
+                    i = 1
+
+        opt = _testinternalcapi.get_uop_optimizer()
+        with temporary_optimizer(opt):
+            testfunc(20)
+
+        ex = get_first_executor(testfunc)
+        self.assertIsNotNone(ex)
+        uops = {opname for opname, _, _ in ex}
+        self.assertIn("_POP_JUMP_IF_TRUE", uops)
 
 
 if __name__ == "__main__":
index eae1918efc35062d2a8db8e9b7398e608f3709a1..c3ad105fb2a3b5b4d29963d3cc01a0ff2e120d0a 100644 (file)
@@ -404,7 +404,7 @@ None     >> PUSH_EXC_INFO
 
 %4d        LOAD_GLOBAL              0 (Exception)
             CHECK_EXC_MATCH
-            POP_JUMP_IF_FALSE       23 (to 80)
+            POP_JUMP_IF_FALSE       23 (to 82)
             STORE_FAST               0 (e)
 
 %4d        LOAD_FAST                0 (e)
@@ -492,7 +492,7 @@ dis_with = """\
 %4d     >> PUSH_EXC_INFO
             WITH_EXCEPT_START
             TO_BOOL
-            POP_JUMP_IF_TRUE         1 (to 50)
+            POP_JUMP_IF_TRUE         1 (to 52)
             RERAISE                  2
          >> POP_TOP
             POP_EXCEPT
@@ -579,7 +579,7 @@ None        JUMP_BACKWARD           11 (to 60)
          >> CLEANUP_THROW
          >> END_SEND
             TO_BOOL
-            POP_JUMP_IF_TRUE         1 (to 116)
+            POP_JUMP_IF_TRUE         1 (to 118)
             RERAISE                  2
          >> POP_TOP
             POP_EXCEPT
@@ -1273,7 +1273,8 @@ class DisTests(DisTestBase):
         got = self.get_disassembly(loop_test, adaptive=True)
         expected = dis_loop_test_quickened_code
         if _testinternalcapi.get_optimizer():
-            expected = expected.replace("JUMP_BACKWARD ", "ENTER_EXECUTOR")
+            # We *may* see ENTER_EXECUTOR in the disassembly
+            got = got.replace("ENTER_EXECUTOR", "JUMP_BACKWARD ")
         self.do_disassembly_compare(got, expected)
 
     @cpython_only
@@ -1713,7 +1714,7 @@ expected_opinfo_jumpy = [
   Instruction(opname='LOAD_CONST', opcode=143, arg=1, argval=10, argrepr='10', offset=12, start_offset=12, starts_line=False, line_number=3, is_jump_target=False, positions=None),
   Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, is_jump_target=False, positions=None),
   Instruction(opname='GET_ITER', opcode=31, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, is_jump_target=False, positions=None),
-  Instruction(opname='FOR_ITER', opcode=115, arg=28, argval=84, argrepr='to 84', offset=24, start_offset=24, starts_line=False, line_number=3, is_jump_target=True, positions=None),
+  Instruction(opname='FOR_ITER', opcode=115, arg=30, argval=88, argrepr='to 88', offset=24, start_offset=24, starts_line=False, line_number=3, is_jump_target=True, positions=None),
   Instruction(opname='STORE_FAST', opcode=177, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4, is_jump_target=False, positions=None),
@@ -1722,108 +1723,108 @@ expected_opinfo_jumpy = [
   Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=143, arg=2, argval=4, argrepr='4', offset=54, start_offset=54, starts_line=False, line_number=5, is_jump_target=False, positions=None),
   Instruction(opname='COMPARE_OP', opcode=98, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=2, argval=66, argrepr='to 66', offset=60, start_offset=60, starts_line=False, line_number=5, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=21, argval=24, argrepr='to 24', offset=62, start_offset=62, starts_line=True, line_number=6, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=66, start_offset=66, starts_line=True, line_number=7, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=3, argval=6, argrepr='6', offset=68, start_offset=68, starts_line=False, line_number=7, is_jump_target=False, positions=None),
-  Instruction(opname='COMPARE_OP', opcode=98, arg=148, argval='>', argrepr='bool(>)', offset=70, start_offset=70, starts_line=False, line_number=7, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_TRUE', opcode=164, arg=2, argval=80, argrepr='to 80', offset=74, start_offset=74, starts_line=False, line_number=7, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=28, argval=24, argrepr='to 24', offset=76, start_offset=76, starts_line=False, line_number=7, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=80, start_offset=80, starts_line=True, line_number=8, is_jump_target=True, positions=None),
-  Instruction(opname='JUMP_FORWARD', opcode=126, arg=12, argval=108, argrepr='to 108', offset=82, start_offset=82, starts_line=False, line_number=8, is_jump_target=False, positions=None),
-  Instruction(opname='END_FOR', opcode=24, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=True, line_number=3, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=86, start_offset=86, starts_line=True, line_number=10, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=96, start_offset=96, starts_line=False, line_number=10, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=98, start_offset=98, starts_line=False, line_number=10, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=106, start_offset=106, starts_line=False, line_number=10, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST_CHECK', opcode=147, arg=0, argval='i', argrepr='i', offset=108, start_offset=108, starts_line=True, line_number=11, is_jump_target=True, positions=None),
-  Instruction(opname='TO_BOOL', opcode=57, arg=None, argval=None, argrepr='', offset=110, start_offset=110, starts_line=False, line_number=11, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=37, argval=194, argrepr='to 194', offset=118, start_offset=118, starts_line=False, line_number=11, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=120, start_offset=120, starts_line=True, line_number=12, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=130, start_offset=130, starts_line=False, line_number=12, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=132, start_offset=132, starts_line=False, line_number=12, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=140, start_offset=140, starts_line=False, line_number=12, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=142, start_offset=142, starts_line=True, line_number=13, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=5, argval=1, argrepr='1', offset=144, start_offset=144, starts_line=False, line_number=13, is_jump_target=False, positions=None),
-  Instruction(opname='BINARY_OP', opcode=68, arg=23, argval=23, argrepr='-=', offset=146, start_offset=146, starts_line=False, line_number=13, is_jump_target=False, positions=None),
-  Instruction(opname='STORE_FAST', opcode=177, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=False, line_number=13, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=152, start_offset=152, starts_line=True, line_number=14, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=3, argval=6, argrepr='6', offset=154, start_offset=154, starts_line=False, line_number=14, is_jump_target=False, positions=None),
-  Instruction(opname='COMPARE_OP', opcode=98, arg=148, argval='>', argrepr='bool(>)', offset=156, start_offset=156, starts_line=False, line_number=14, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=2, argval=166, argrepr='to 166', offset=160, start_offset=160, starts_line=False, line_number=14, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=29, argval=108, argrepr='to 108', offset=162, start_offset=162, starts_line=True, line_number=15, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=166, start_offset=166, starts_line=True, line_number=16, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=2, argval=4, argrepr='4', offset=168, start_offset=168, starts_line=False, line_number=16, is_jump_target=False, positions=None),
-  Instruction(opname='COMPARE_OP', opcode=98, arg=18, argval='<', argrepr='bool(<)', offset=170, start_offset=170, starts_line=False, line_number=16, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=1, argval=178, argrepr='to 178', offset=174, start_offset=174, starts_line=False, line_number=16, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_FORWARD', opcode=126, arg=19, argval=216, argrepr='to 216', offset=176, start_offset=176, starts_line=True, line_number=17, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=True, line_number=11, is_jump_target=True, positions=None),
-  Instruction(opname='TO_BOOL', opcode=57, arg=None, argval=None, argrepr='', offset=180, start_offset=180, starts_line=False, line_number=11, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=2, argval=194, argrepr='to 194', offset=188, start_offset=188, starts_line=False, line_number=11, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=37, argval=120, argrepr='to 120', offset=190, start_offset=190, starts_line=False, line_number=11, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=194, start_offset=194, starts_line=True, line_number=19, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=False, line_number=19, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=False, line_number=19, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=False, line_number=19, is_jump_target=False, positions=None),
-  Instruction(opname='NOP', opcode=42, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=True, line_number=20, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=5, argval=1, argrepr='1', offset=218, start_offset=218, starts_line=True, line_number=21, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=7, argval=0, argrepr='0', offset=220, start_offset=220, starts_line=False, line_number=21, is_jump_target=False, positions=None),
-  Instruction(opname='BINARY_OP', opcode=68, arg=11, argval=11, argrepr='/', offset=222, start_offset=222, starts_line=False, line_number=21, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=False, line_number=21, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=228, start_offset=228, starts_line=True, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='BEFORE_WITH', opcode=2, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='STORE_FAST', opcode=177, arg=1, argval='dodgy', argrepr='dodgy', offset=232, start_offset=232, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=234, start_offset=234, starts_line=True, line_number=26, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=244, start_offset=244, starts_line=False, line_number=26, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=246, start_offset=246, starts_line=False, line_number=26, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=254, start_offset=254, starts_line=False, line_number=26, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=0, argval=None, argrepr='None', offset=256, start_offset=256, starts_line=True, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=0, argval=None, argrepr='None', offset=258, start_offset=258, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=0, argval=None, argrepr='None', offset=260, start_offset=260, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=2, argval=2, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=272, start_offset=272, starts_line=True, line_number=28, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=282, start_offset=282, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=284, start_offset=284, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=292, start_offset=292, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='RETURN_CONST', opcode=168, arg=0, argval=None, argrepr='None', offset=294, start_offset=294, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=True, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='WITH_EXCEPT_START', opcode=67, arg=None, argval=None, argrepr='', offset=298, start_offset=298, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='TO_BOOL', opcode=57, arg=None, argval=None, argrepr='', offset=300, start_offset=300, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_TRUE', opcode=164, arg=1, argval=312, argrepr='to 312', offset=308, start_offset=308, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=167, arg=2, argval=2, argrepr='', offset=310, start_offset=310, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25, is_jump_target=True, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=26, argval=272, argrepr='to 272', offset=320, start_offset=320, starts_line=False, line_number=25, is_jump_target=False, positions=None),
-  Instruction(opname='COPY', opcode=104, arg=3, argval=3, argrepr='', offset=324, start_offset=324, starts_line=True, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=167, arg=1, argval=1, argrepr='', offset=328, start_offset=328, starts_line=False, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, start_offset=332, starts_line=True, line_number=22, is_jump_target=False, positions=None),
-  Instruction(opname='CHECK_EXC_MATCH', opcode=20, arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=22, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=15, argval=376, argrepr='to 376', offset=344, start_offset=344, starts_line=False, line_number=22, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=False, line_number=22, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=348, start_offset=348, starts_line=True, line_number=23, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=358, start_offset=358, starts_line=False, line_number=23, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=23, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=False, line_number=23, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=370, start_offset=370, starts_line=False, line_number=23, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=52, argval=272, argrepr='to 272', offset=372, start_offset=372, starts_line=False, line_number=23, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=167, arg=0, argval=0, argrepr='', offset=376, start_offset=376, starts_line=True, line_number=22, is_jump_target=True, positions=None),
-  Instruction(opname='COPY', opcode=104, arg=3, argval=3, argrepr='', offset=378, start_offset=378, starts_line=True, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=380, start_offset=380, starts_line=False, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=167, arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=False, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=False, line_number=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=386, start_offset=386, starts_line=True, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=143, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=396, start_offset=396, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=406, start_offset=406, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=167, arg=0, argval=0, argrepr='', offset=408, start_offset=408, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='COPY', opcode=104, arg=3, argval=3, argrepr='', offset=410, start_offset=410, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=412, start_offset=412, starts_line=False, line_number=28, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=167, arg=1, argval=1, argrepr='', offset=414, start_offset=414, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=2, argval=68, argrepr='to 68', offset=60, start_offset=60, starts_line=False, line_number=5, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=22, argval=24, argrepr='to 24', offset=64, start_offset=64, starts_line=True, line_number=6, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=68, start_offset=68, starts_line=True, line_number=7, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=3, argval=6, argrepr='6', offset=70, start_offset=70, starts_line=False, line_number=7, is_jump_target=False, positions=None),
+  Instruction(opname='COMPARE_OP', opcode=98, arg=148, argval='>', argrepr='bool(>)', offset=72, start_offset=72, starts_line=False, line_number=7, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_TRUE', opcode=164, arg=2, argval=84, argrepr='to 84', offset=76, start_offset=76, starts_line=False, line_number=7, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=30, argval=24, argrepr='to 24', offset=80, start_offset=80, starts_line=False, line_number=7, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=True, line_number=8, is_jump_target=True, positions=None),
+  Instruction(opname='JUMP_FORWARD', opcode=126, arg=12, argval=112, argrepr='to 112', offset=86, start_offset=86, starts_line=False, line_number=8, is_jump_target=False, positions=None),
+  Instruction(opname='END_FOR', opcode=24, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=3, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=90, start_offset=90, starts_line=True, line_number=10, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=100, start_offset=100, starts_line=False, line_number=10, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=102, start_offset=102, starts_line=False, line_number=10, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=110, start_offset=110, starts_line=False, line_number=10, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST_CHECK', opcode=147, arg=0, argval='i', argrepr='i', offset=112, start_offset=112, starts_line=True, line_number=11, is_jump_target=True, positions=None),
+  Instruction(opname='TO_BOOL', opcode=57, arg=None, argval=None, argrepr='', offset=114, start_offset=114, starts_line=False, line_number=11, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=40, argval=206, argrepr='to 206', offset=122, start_offset=122, starts_line=False, line_number=11, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=126, start_offset=126, starts_line=True, line_number=12, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=136, start_offset=136, starts_line=False, line_number=12, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=138, start_offset=138, starts_line=False, line_number=12, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=146, start_offset=146, starts_line=False, line_number=12, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=148, start_offset=148, starts_line=True, line_number=13, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=5, argval=1, argrepr='1', offset=150, start_offset=150, starts_line=False, line_number=13, is_jump_target=False, positions=None),
+  Instruction(opname='BINARY_OP', opcode=68, arg=23, argval=23, argrepr='-=', offset=152, start_offset=152, starts_line=False, line_number=13, is_jump_target=False, positions=None),
+  Instruction(opname='STORE_FAST', opcode=177, arg=0, argval='i', argrepr='i', offset=156, start_offset=156, starts_line=False, line_number=13, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=True, line_number=14, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=3, argval=6, argrepr='6', offset=160, start_offset=160, starts_line=False, line_number=14, is_jump_target=False, positions=None),
+  Instruction(opname='COMPARE_OP', opcode=98, arg=148, argval='>', argrepr='bool(>)', offset=162, start_offset=162, starts_line=False, line_number=14, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=2, argval=174, argrepr='to 174', offset=166, start_offset=166, starts_line=False, line_number=14, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=31, argval=112, argrepr='to 112', offset=170, start_offset=170, starts_line=True, line_number=15, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=174, start_offset=174, starts_line=True, line_number=16, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=2, argval=4, argrepr='4', offset=176, start_offset=176, starts_line=False, line_number=16, is_jump_target=False, positions=None),
+  Instruction(opname='COMPARE_OP', opcode=98, arg=18, argval='<', argrepr='bool(<)', offset=178, start_offset=178, starts_line=False, line_number=16, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=1, argval=188, argrepr='to 188', offset=182, start_offset=182, starts_line=False, line_number=16, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_FORWARD', opcode=126, arg=20, argval=228, argrepr='to 228', offset=186, start_offset=186, starts_line=True, line_number=17, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=188, start_offset=188, starts_line=True, line_number=11, is_jump_target=True, positions=None),
+  Instruction(opname='TO_BOOL', opcode=57, arg=None, argval=None, argrepr='', offset=190, start_offset=190, starts_line=False, line_number=11, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=2, argval=206, argrepr='to 206', offset=198, start_offset=198, starts_line=False, line_number=11, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=40, argval=126, argrepr='to 126', offset=202, start_offset=202, starts_line=False, line_number=11, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=206, start_offset=206, starts_line=True, line_number=19, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=216, start_offset=216, starts_line=False, line_number=19, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=218, start_offset=218, starts_line=False, line_number=19, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=False, line_number=19, is_jump_target=False, positions=None),
+  Instruction(opname='NOP', opcode=42, arg=None, argval=None, argrepr='', offset=228, start_offset=228, starts_line=True, line_number=20, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=5, argval=1, argrepr='1', offset=230, start_offset=230, starts_line=True, line_number=21, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=7, argval=0, argrepr='0', offset=232, start_offset=232, starts_line=False, line_number=21, is_jump_target=False, positions=None),
+  Instruction(opname='BINARY_OP', opcode=68, arg=11, argval=11, argrepr='/', offset=234, start_offset=234, starts_line=False, line_number=21, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=238, start_offset=238, starts_line=False, line_number=21, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=145, arg=0, argval='i', argrepr='i', offset=240, start_offset=240, starts_line=True, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='BEFORE_WITH', opcode=2, arg=None, argval=None, argrepr='', offset=242, start_offset=242, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='STORE_FAST', opcode=177, arg=1, argval='dodgy', argrepr='dodgy', offset=244, start_offset=244, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=246, start_offset=246, starts_line=True, line_number=26, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=256, start_offset=256, starts_line=False, line_number=26, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=258, start_offset=258, starts_line=False, line_number=26, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=266, start_offset=266, starts_line=False, line_number=26, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=0, argval=None, argrepr='None', offset=268, start_offset=268, starts_line=True, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=0, argval=None, argrepr='None', offset=270, start_offset=270, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=0, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=2, argval=2, argrepr='', offset=274, start_offset=274, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=282, start_offset=282, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=284, start_offset=284, starts_line=True, line_number=28, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=294, start_offset=294, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=296, start_offset=296, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=304, start_offset=304, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='RETURN_CONST', opcode=168, arg=0, argval=None, argrepr='None', offset=306, start_offset=306, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=308, start_offset=308, starts_line=True, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='WITH_EXCEPT_START', opcode=67, arg=None, argval=None, argrepr='', offset=310, start_offset=310, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='TO_BOOL', opcode=57, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_TRUE', opcode=164, arg=1, argval=326, argrepr='to 326', offset=320, start_offset=320, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=167, arg=2, argval=2, argrepr='', offset=324, start_offset=324, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=25, is_jump_target=True, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=328, start_offset=328, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=27, argval=284, argrepr='to 284', offset=334, start_offset=334, starts_line=False, line_number=25, is_jump_target=False, positions=None),
+  Instruction(opname='COPY', opcode=104, arg=3, argval=3, argrepr='', offset=338, start_offset=338, starts_line=True, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=167, arg=1, argval=1, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=346, start_offset=346, starts_line=True, line_number=22, is_jump_target=False, positions=None),
+  Instruction(opname='CHECK_EXC_MATCH', opcode=20, arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=False, line_number=22, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_FALSE', opcode=161, arg=15, argval=392, argrepr='to 392', offset=358, start_offset=358, starts_line=False, line_number=22, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=22, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=364, start_offset=364, starts_line=True, line_number=23, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=374, start_offset=374, starts_line=False, line_number=23, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=23, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=False, line_number=23, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=386, start_offset=386, starts_line=False, line_number=23, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_BACKWARD', opcode=124, arg=54, argval=284, argrepr='to 284', offset=388, start_offset=388, starts_line=False, line_number=23, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=167, arg=0, argval=0, argrepr='', offset=392, start_offset=392, starts_line=True, line_number=22, is_jump_target=True, positions=None),
+  Instruction(opname='COPY', opcode=104, arg=3, argval=3, argrepr='', offset=394, start_offset=394, starts_line=True, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=167, arg=1, argval=1, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='PUSH_EXC_INFO', opcode=45, arg=None, argval=None, argrepr='', offset=400, start_offset=400, starts_line=False, line_number=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=151, arg=3, argval='print', argrepr='print + NULL', offset=402, start_offset=402, starts_line=True, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=143, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=412, start_offset=412, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=76, arg=1, argval=1, argrepr='', offset=414, start_offset=414, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=44, arg=None, argval=None, argrepr='', offset=422, start_offset=422, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=167, arg=0, argval=0, argrepr='', offset=424, start_offset=424, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='COPY', opcode=104, arg=3, argval=3, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=43, arg=None, argval=None, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=28, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=167, arg=1, argval=1, argrepr='', offset=430, start_offset=430, starts_line=False, line_number=28, is_jump_target=False, positions=None),
 ]
 
 # One last piece of inspect fodder to check the default line number handling
@@ -2026,6 +2027,7 @@ class InstructionTests(InstructionTestCase):
             opcode.opmap["EXTENDED_ARG"], 0x01,
             opcode.opmap["EXTENDED_ARG"], 0x01,
             opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF,
+            opcode.opmap["CACHE"], 0x00,
         ])
         jump = list(dis._get_instructions_bytes(code))[-1]
         self.assertEqual(8, jump.offset)
@@ -2035,18 +2037,20 @@ class InstructionTests(InstructionTestCase):
             opcode.opmap["LOAD_FAST"], 0x00,
             opcode.opmap["EXTENDED_ARG"], 0x01,
             opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF,
+            opcode.opmap["CACHE"], 0x00,
             opcode.opmap["EXTENDED_ARG"], 0x01,
             opcode.opmap["EXTENDED_ARG"], 0x01,
             opcode.opmap["EXTENDED_ARG"], 0x01,
             opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF,
+            opcode.opmap["CACHE"], 0x00,
         ])
         instructions = list(dis._get_instructions_bytes(code))
         # 1st jump
         self.assertEqual(4, instructions[2].offset)
         self.assertEqual(2, instructions[2].start_offset)
         # 2nd jump
-        self.assertEqual(12, instructions[6].offset)
-        self.assertEqual(6, instructions[6].start_offset)
+        self.assertEqual(14, instructions[6].offset)
+        self.assertEqual(8, instructions[6].start_offset)
 
     def test_cache_offset_and_end_offset(self):
         code = bytes([
index e575eca42fabf9afac7eac94e025cddf82f51be5..a4725be21706ff18cf54974764e01f327349774c 100644 (file)
@@ -1348,10 +1348,10 @@ class TestBranchAndJumpEvents(CheckEvents):
 
         self.check_events(func, recorders = JUMP_AND_BRANCH_RECORDERS, expected = [
             ('branch', 'func', 2, 2),
-            ('branch', 'func', 3, 6),
+            ('branch', 'func', 3, 4),
             ('jump', 'func', 6, 2),
             ('branch', 'func', 2, 2),
-            ('branch', 'func', 3, 4),
+            ('branch', 'func', 3, 3),
             ('jump', 'func', 4, 2),
             ('branch', 'func', 2, 2)])
 
@@ -1361,13 +1361,13 @@ class TestBranchAndJumpEvents(CheckEvents):
             ('line', 'func', 2),
             ('branch', 'func', 2, 2),
             ('line', 'func', 3),
-            ('branch', 'func', 3, 6),
+            ('branch', 'func', 3, 4),
             ('line', 'func', 6),
             ('jump', 'func', 6, 2),
             ('line', 'func', 2),
             ('branch', 'func', 2, 2),
             ('line', 'func', 3),
-            ('branch', 'func', 3, 4),
+            ('branch', 'func', 3, 3),
             ('line', 'func', 4),
             ('jump', 'func', 4, 2),
             ('line', 'func', 2),
@@ -1400,8 +1400,8 @@ class TestBranchAndJumpEvents(CheckEvents):
             ('line', 'func', 5),
             ('line', 'meth', 1),
             ('jump', 'func', 5, 5),
-            ('jump', 'func', 5, '[offset=112]'),
-            ('branch', 'func', '[offset=118]', '[offset=120]'),
+            ('jump', 'func', 5, '[offset=114]'),
+            ('branch', 'func', '[offset=120]', '[offset=122]'),
             ('line', 'get_events', 11)])
 
         self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [
@@ -1416,8 +1416,8 @@ class TestBranchAndJumpEvents(CheckEvents):
             ('line', 'meth', 1),
             ('return', None),
             ('jump', 'func', 5, 5),
-            ('jump', 'func', 5, '[offset=112]'),
-            ('branch', 'func', '[offset=118]', '[offset=120]'),
+            ('jump', 'func', 5, '[offset=114]'),
+            ('branch', 'func', '[offset=120]', '[offset=122]'),
             ('return', None),
             ('line', 'get_events', 11)])
 
index f587a8f919dcde04ec90d9b714a0ae2ece4e2d13..466b6f66797b7aff0fd8fb5d298db155016d9316 100644 (file)
@@ -19,7 +19,7 @@ import tempfile
 import textwrap
 import unittest
 from test import support
-from test.support import os_helper, TestStats
+from test.support import os_helper, TestStats, without_optimizer
 from test.libregrtest import cmdline
 from test.libregrtest import utils
 from test.libregrtest import setup
@@ -1018,12 +1018,13 @@ class ArgsTestCase(BaseTestCase):
                                   stats=TestStats(4, 1),
                                   forever=True)
 
+    @without_optimizer
     def check_leak(self, code, what, *, multiprocessing=False):
         test = self.create_test('huntrleaks', code=code)
 
         filename = 'reflog.txt'
         self.addCleanup(os_helper.unlink, filename)
-        cmd = ['--huntrleaks', '6:3:']
+        cmd = ['--huntrleaks', '3:3:']
         if multiprocessing:
             cmd.append('-j1')
         cmd.append(test)
@@ -1032,7 +1033,7 @@ class ArgsTestCase(BaseTestCase):
                                 stderr=subprocess.STDOUT)
         self.check_executed_tests(output, [test], failed=test, stats=1)
 
-        line = 'beginning 9 repetitions\n123456789\n.........\n'
+        line = 'beginning 6 repetitions\n123456\n......\n'
         self.check_line(output, re.escape(line))
 
         line2 = '%s leaked [1, 1, 1] %s, sum=3\n' % (test, what)
index ff95f37b900da638727737b28fdc820793baa56a..c9dea5c4562f7c3408d0206159eb2a8dd860c4e7 100644 (file)
@@ -2292,14 +2292,22 @@ dummy_func(
             goto resume_frame;
         }
 
-        inst(POP_JUMP_IF_FALSE, (cond -- )) {
+        inst(POP_JUMP_IF_FALSE, (unused/1, cond -- )) {
             assert(PyBool_Check(cond));
-            JUMPBY(oparg * Py_IsFalse(cond));
+            int flag = Py_IsFalse(cond);
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
+            JUMPBY(oparg * flag);
         }
 
-        inst(POP_JUMP_IF_TRUE, (cond -- )) {
+        inst(POP_JUMP_IF_TRUE, (unused/1, cond -- )) {
             assert(PyBool_Check(cond));
-            JUMPBY(oparg * Py_IsTrue(cond));
+            int flag = Py_IsTrue(cond);
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
+            JUMPBY(oparg * flag);
         }
 
         op(IS_NONE, (value -- b)) {
@@ -3751,47 +3759,63 @@ dummy_func(
             INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP);
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) {
+        inst(INSTRUMENTED_POP_JUMP_IF_TRUE, (unused/1 -- )) {
             PyObject *cond = POP();
             assert(PyBool_Check(cond));
             _Py_CODEUNIT *here = next_instr - 1;
-            int offset = Py_IsTrue(cond) * oparg;
+            int flag = Py_IsTrue(cond);
+            int offset = flag * oparg;
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_FALSE, ( -- )) {
+        inst(INSTRUMENTED_POP_JUMP_IF_FALSE, (unused/1 -- )) {
             PyObject *cond = POP();
             assert(PyBool_Check(cond));
             _Py_CODEUNIT *here = next_instr - 1;
-            int offset = Py_IsFalse(cond) * oparg;
+            int flag = Py_IsFalse(cond);
+            int offset = flag * oparg;
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_NONE, ( -- )) {
+        inst(INSTRUMENTED_POP_JUMP_IF_NONE, (unused/1 -- )) {
             PyObject *value = POP();
-            _Py_CODEUNIT *here = next_instr-1;
+            _Py_CODEUNIT *here = next_instr - 1;
+            int flag = Py_IsNone(value);
             int offset;
-            if (Py_IsNone(value)) {
+            if (flag) {
                 offset = oparg;
             }
             else {
                 Py_DECREF(value);
                 offset = 0;
             }
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
         }
 
-        inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, ( -- )) {
+        inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, (unused/1 -- )) {
             PyObject *value = POP();
             _Py_CODEUNIT *here = next_instr-1;
             int offset;
-            if (Py_IsNone(value)) {
+            int nflag = Py_IsNone(value);
+            if (nflag) {
                 offset = 0;
             }
             else {
                 Py_DECREF(value);
                 offset = oparg;
             }
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | !nflag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
         }
 
index e84599d87a6968660f9751f0ba757da259790840..a4944c7fcdfbd388eeab41f825c0bf5ae320a4b7 100644 (file)
             PyObject *cond;
             cond = stack_pointer[-1];
             assert(PyBool_Check(cond));
-            JUMPBY(oparg * Py_IsFalse(cond));
+            int flag = Py_IsFalse(cond);
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
+            JUMPBY(oparg * flag);
             STACK_SHRINK(1);
+            next_instr += 1;
             DISPATCH();
         }
 
             PyObject *cond;
             cond = stack_pointer[-1];
             assert(PyBool_Check(cond));
-            JUMPBY(oparg * Py_IsTrue(cond));
+            int flag = Py_IsTrue(cond);
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
+            JUMPBY(oparg * flag);
             STACK_SHRINK(1);
+            next_instr += 1;
             DISPATCH();
         }
 
             cond = b;
             {
                 assert(PyBool_Check(cond));
-                JUMPBY(oparg * Py_IsTrue(cond));
+                int flag = Py_IsTrue(cond);
+                #if ENABLE_SPECIALIZATION
+                next_instr->cache = (next_instr->cache << 1) | flag;
+                #endif
+                JUMPBY(oparg * flag);
             }
             STACK_SHRINK(1);
+            next_instr += 1;
             DISPATCH();
         }
 
             cond = b;
             {
                 assert(PyBool_Check(cond));
-                JUMPBY(oparg * Py_IsFalse(cond));
+                int flag = Py_IsFalse(cond);
+                #if ENABLE_SPECIALIZATION
+                next_instr->cache = (next_instr->cache << 1) | flag;
+                #endif
+                JUMPBY(oparg * flag);
             }
             STACK_SHRINK(1);
+            next_instr += 1;
             DISPATCH();
         }
 
             PyObject *cond = POP();
             assert(PyBool_Check(cond));
             _Py_CODEUNIT *here = next_instr - 1;
-            int offset = Py_IsTrue(cond) * oparg;
+            int flag = Py_IsTrue(cond);
+            int offset = flag * oparg;
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+            next_instr += 1;
             DISPATCH();
         }
 
             PyObject *cond = POP();
             assert(PyBool_Check(cond));
             _Py_CODEUNIT *here = next_instr - 1;
-            int offset = Py_IsFalse(cond) * oparg;
+            int flag = Py_IsFalse(cond);
+            int offset = flag * oparg;
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+            next_instr += 1;
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) {
             PyObject *value = POP();
-            _Py_CODEUNIT *here = next_instr-1;
+            _Py_CODEUNIT *here = next_instr - 1;
+            int flag = Py_IsNone(value);
             int offset;
-            if (Py_IsNone(value)) {
+            if (flag) {
                 offset = oparg;
             }
             else {
                 Py_DECREF(value);
                 offset = 0;
             }
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | flag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+            next_instr += 1;
             DISPATCH();
         }
 
             PyObject *value = POP();
             _Py_CODEUNIT *here = next_instr-1;
             int offset;
-            if (Py_IsNone(value)) {
+            int nflag = Py_IsNone(value);
+            if (nflag) {
                 offset = 0;
             }
             else {
                 Py_DECREF(value);
                 offset = oparg;
             }
+            #if ENABLE_SPECIALIZATION
+            next_instr->cache = (next_instr->cache << 1) | !nflag;
+            #endif
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+            next_instr += 1;
             DISPATCH();
         }
 
index 5f714602eafbb8d6a5c211d4299f3171de71473d..fee6eae1734394e51eb0d875c043bf9ae5dfcae4 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "opcode_ids.h"
 
+#include "pycore_bitutils.h"      // _Py_popcount32
 #include "pycore_call.h"
 #include "pycore_code.h"          // _PyCode_Clear_Executors()
 #include "pycore_frame.h"
index c6d0f9e5bf22d7df640d21e2fc7b22c9bb31cfed..8eca37a7e4a28335790dc3caf5f3c6ba359a55c0 100644 (file)
@@ -1,6 +1,7 @@
 #include "Python.h"
 #include "opcode.h"
 #include "pycore_interp.h"
+#include "pycore_bitutils.h"        // _Py_popcount32()
 #include "pycore_opcode_metadata.h" // _PyOpcode_OpName()
 #include "pycore_opcode_utils.h"  // MAX_REAL_OPCODE
 #include "pycore_optimizer.h"     // _Py_uop_analyze_and_optimize()
@@ -501,7 +502,7 @@ translate_bytecode_to_trace(
             code->co_firstlineno,
             2 * INSTR_IP(initial_instr, code));
 
-top:  // Jump here after _PUSH_FRAME
+top:  // Jump here after _PUSH_FRAME or likely branches
     for (;;) {
         RESERVE_RAW(2, "epilogue");  // Always need space for SAVE_IP and EXIT_TRACE
         ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code), 0);
@@ -547,16 +548,29 @@ top:  // Jump here after _PUSH_FRAME
             case POP_JUMP_IF_TRUE:
             {
 pop_jump_if_bool:
-                // Assume jump unlikely (TODO: handle jump likely case)
                 RESERVE(1, 2);
-                _Py_CODEUNIT *target_instr =
-                    instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg;
                 max_length -= 2;  // Really the start of the stubs
-                uint32_t uopcode = opcode == POP_JUMP_IF_TRUE ?
+                int counter = instr[1].cache;
+                int bitcount = _Py_popcount32(counter);
+                bool jump_likely = bitcount > 8;
+                bool jump_sense = opcode == POP_JUMP_IF_TRUE;
+                uint32_t uopcode = jump_sense ^ jump_likely ?
                     _POP_JUMP_IF_TRUE : _POP_JUMP_IF_FALSE;
+                _Py_CODEUNIT *next_instr = instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]];
+                _Py_CODEUNIT *target_instr = next_instr + oparg;
+                _Py_CODEUNIT *stub_target = jump_likely ? next_instr : target_instr;
+                DPRINTF(4, "%s(%d): counter=%x, bitcount=%d, likely=%d, sense=%d, uopcode=%s\n",
+                        uop_name(opcode), oparg,
+                        counter, bitcount, jump_likely, jump_sense, uop_name(uopcode));
                 ADD_TO_TRACE(uopcode, max_length, 0);
-                ADD_TO_STUB(max_length, SAVE_IP, INSTR_IP(target_instr, code), 0);
+                ADD_TO_STUB(max_length, SAVE_IP, INSTR_IP(stub_target, code), 0);
                 ADD_TO_STUB(max_length + 1, EXIT_TRACE, 0, 0);
+                if (jump_likely) {
+                    DPRINTF(2, "Jump likely (%x = %d bits), continue at byte offset %d\n",
+                            instr[1].cache, bitcount, 2 * INSTR_IP(target_instr, code));
+                    instr = target_instr;
+                    goto top;
+                }
                 break;
             }
 
@@ -927,6 +941,6 @@ PyUnstable_Optimizer_NewUOpOptimizer(void)
     opt->resume_threshold = UINT16_MAX;
     // Need at least 3 iterations to settle specializations.
     // A few lower bits of the counter are reserved for other flags.
-    opt->backedge_threshold = 3 << OPTIMIZER_BITS_IN_COUNTER;
+    opt->backedge_threshold = 16 << OPTIMIZER_BITS_IN_COUNTER;
     return (PyObject *)opt;
 }
index 8b4aac2f890930e28422b61ccf0266927c4035d2..91243419ec6fb02d3eaed96139cd70bb272d476a 100644 (file)
@@ -338,9 +338,23 @@ _PyCode_Quicken(PyCodeObject *code)
         assert(opcode < MIN_INSTRUMENTED_OPCODE);
         int caches = _PyOpcode_Caches[opcode];
         if (caches) {
-            // JUMP_BACKWARD counter counts up from 0 until it is > backedge_threshold
-            instructions[i + 1].cache =
-                opcode == JUMP_BACKWARD ? 0 : adaptive_counter_warmup();
+            // The initial value depends on the opcode
+            int initial_value;
+            switch (opcode) {
+                case JUMP_BACKWARD:
+                    initial_value = 0;
+                    break;
+                case POP_JUMP_IF_FALSE:
+                case POP_JUMP_IF_TRUE:
+                case POP_JUMP_IF_NONE:
+                case POP_JUMP_IF_NOT_NONE:
+                    initial_value = 0x5555;  // Alternating 0, 1 bits
+                    break;
+                default:
+                    initial_value = adaptive_counter_warmup();
+                    break;
+            }
+            instructions[i + 1].cache = initial_value;
             i += caches;
         }
     }
index 1335c0c29ebbf6b7ab3e23569faf9d3e611a153e..ad4a99931d9af602397508b373415bcba47befa8 100644 (file)
@@ -549,10 +549,20 @@ class Generator(Analyzer):
                 "=",
                 ";",
             ):
-                for name, _ in self.families.items():
-                    instr = self.instrs[name]
-                    if instr.cache_offset > 0:
-                        self.out.emit(f'[{name}] = {instr.cache_offset},')
+                family_member_names: set[str] = set()
+                for family in self.families.values():
+                    family_member_names.update(family.members)
+                for instr in self.instrs.values():
+                    if (
+                        instr.name not in family_member_names
+                        and instr.cache_offset > 0
+                        and instr.kind == "inst"
+                        and not instr.name.startswith("INSTRUMENTED_")
+                    ):
+                        self.out.emit(f"[{instr.name}] = {instr.cache_offset},")
+                for mac in self.macro_instrs.values():
+                    if mac.name not in family_member_names and mac.cache_offset > 0:
+                        self.out.emit(f"[{mac.name}] = {mac.cache_offset},")
                 # Irregular case:
                 self.out.emit('[JUMP_BACKWARD] = 1,')