]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-127958: Trace from RESUME in the JIT (GH-145905)
authorKen Jin <kenjin@python.org>
Mon, 16 Mar 2026 16:18:59 +0000 (00:18 +0800)
committerGitHub <noreply@github.com>
Mon, 16 Mar 2026 16:18:59 +0000 (00:18 +0800)
34 files changed:
Include/internal/pycore_backoff.h
Include/internal/pycore_code.h
Include/internal/pycore_interp_structs.h
Include/internal/pycore_magic_number.h
Include/internal/pycore_opcode_metadata.h
Include/internal/pycore_optimizer.h
Include/internal/pycore_uop.h
Include/internal/pycore_uop_ids.h
Include/opcode_ids.h
Lib/_opcode_metadata.py
Lib/opcode.py
Lib/test/test_capi/test_opt.py
Lib/test/test_code.py
Lib/test/test_compile.py
Lib/test/test_dis.py
Lib/test/test_monitoring.py
Misc/NEWS.d/next/Core_and_Builtins/2026-03-13-09-48-57.gh-issue-127958.U-znTv.rst [new file with mode: 0644]
Modules/_testinternalcapi.c
Modules/_testinternalcapi/test_cases.c.h
Modules/_testinternalcapi/test_targets.h
Objects/codeobject.c
Objects/genobject.c
Programs/test_frozenmain.h
Python/assemble.c
Python/bytecodes.c
Python/ceval.c
Python/executor_cases.c.h
Python/generated_cases.c.h
Python/instrumentation.c
Python/opcode_targets.h
Python/optimizer.c
Python/optimizer_cases.c.h
Python/pystate.c
Python/specialize.c

index ee907ae0534e4f4de82e2536f04dd3dd597d6517..38dd82f6fc8a1402acb93eb0de42963b5a0c0cc4 100644 (file)
@@ -135,6 +135,20 @@ initial_jump_backoff_counter(_PyOptimizationConfig *opt_config)
         opt_config->jump_backward_initial_backoff);
 }
 
+// This needs to be around 2-4x of JUMP_BACKWARD_INITIAL_VALUE
+// The reasoning is that we always want loop traces to form and inline
+// functions before functions themselves warm up and link to them instead
+// of inlining.
+#define RESUME_INITIAL_VALUE 8190
+#define RESUME_INITIAL_BACKOFF 6
+static inline _Py_BackoffCounter
+initial_resume_backoff_counter(_PyOptimizationConfig *opt_config)
+{
+    return make_backoff_counter(
+        opt_config->resume_initial_value,
+        opt_config->resume_initial_backoff);
+}
+
 /* Initial exit temperature.
  * Must be larger than ADAPTIVE_COOLDOWN_VALUE,
  * otherwise when a side exit warms up we may construct
index efae3b38654c4168d70f8bc7d83e0a6cea246afc..376e68a4c8773c0237698fccd9789cfdb0df23f9 100644 (file)
@@ -323,6 +323,7 @@ PyAPI_FUNC(void) _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr);
 PyAPI_FUNC(void) _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr);
 PyAPI_FUNC(void) _Py_GatherStats_GetIter(_PyStackRef iterable);
 PyAPI_FUNC(void) _Py_Specialize_CallFunctionEx(_PyStackRef func_st, _Py_CODEUNIT *instr);
+PyAPI_FUNC(void) _Py_Specialize_Resume(_Py_CODEUNIT *instr, PyThreadState *tstate, _PyInterpreterFrame *frame);
 
 // Utility functions for reading/writing 32/64-bit values in the inline caches.
 // Great care should be taken to ensure that these functions remain correct and
index e2008f8303e21be0acee8090c132e554f88c3253..4822360a8f08d0e60494989be4073eb447d4043a 100644 (file)
@@ -414,6 +414,9 @@ typedef struct _PyOptimizationConfig {
     uint16_t jump_backward_initial_value;
     uint16_t jump_backward_initial_backoff;
 
+    uint16_t resume_initial_value;
+    uint16_t resume_initial_backoff;
+
     // JIT optimization thresholds
     uint16_t side_exit_initial_value;
     uint16_t side_exit_initial_backoff;
index 3fcf650426d36d0dbe76d27214d74c44c4e092d3..ec9cfe432371c76594736a5039463d5e51638ecd 100644 (file)
@@ -292,6 +292,7 @@ Known values:
     Python 3.15a4 3659 (Add CALL_FUNCTION_EX specialization)
     Python 3.15a4 3660 (Change generator preamble code)
     Python 3.15a4 3661 (Lazy imports IMPORT_NAME opcode changes)
+    Python 3.15a6 3662 (Add counter to RESUME)
 
 
     Python 3.16 will start with 3700
@@ -305,7 +306,7 @@ PC/launcher.c must also be updated.
 
 */
 
-#define PYC_MAGIC_NUMBER 3661
+#define PYC_MAGIC_NUMBER 3662
 /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
    (little-endian) and then appending b'\r\n'. */
 #define PYC_MAGIC_NUMBER_TOKEN \
index fc5689c5afe13ab2734cf6d4773f1c8f2733e165..c46015c4d98239dd42fe674af9a1e54dbbe8f56a 100644 (file)
@@ -426,6 +426,8 @@ int _PyOpcode_num_popped(int opcode, int oparg)  {
             return 0;
         case RESUME_CHECK:
             return 0;
+        case RESUME_CHECK_JIT:
+            return 0;
         case RETURN_GENERATOR:
             return 0;
         case RETURN_VALUE:
@@ -917,6 +919,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg)  {
             return 0;
         case RESUME_CHECK:
             return 0;
+        case RESUME_CHECK_JIT:
+            return 0;
         case RETURN_GENERATOR:
             return 1;
         case RETURN_VALUE:
@@ -1209,7 +1213,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
     [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG },
     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ESCAPES_FLAG },
     [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
-    [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
+    [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
     [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
     [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
     [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG },
@@ -1278,8 +1282,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
     [RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
     [RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
     [RESERVED] = { true, INSTR_FMT_IX, 0 },
-    [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
-    [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
+    [RESUME] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
+    [RESUME_CHECK] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG },
+    [RESUME_CHECK_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
     [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
     [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
     [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
@@ -1493,7 +1498,7 @@ _PyOpcode_macro_expansion[256] = {
     [POP_TOP] = { .nuops = 1, .uops = { { _POP_TOP, OPARG_SIMPLE, 0 } } },
     [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { _PUSH_EXC_INFO, OPARG_SIMPLE, 0 } } },
     [PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, OPARG_SIMPLE, 0 } } },
-    [RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 0 } } },
+    [RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 1 } } },
     [RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } },
     [RETURN_VALUE] = { .nuops = 2, .uops = { { _MAKE_HEAP_SAFE, OPARG_SIMPLE, 0 }, { _RETURN_VALUE, OPARG_SIMPLE, 0 } } },
     [SEND_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS_GEN_FUNC, OPARG_SIMPLE, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
@@ -1734,6 +1739,7 @@ const char *_PyOpcode_OpName[267] = {
     [RESERVED] = "RESERVED",
     [RESUME] = "RESUME",
     [RESUME_CHECK] = "RESUME_CHECK",
+    [RESUME_CHECK_JIT] = "RESUME_CHECK_JIT",
     [RETURN_GENERATOR] = "RETURN_GENERATOR",
     [RETURN_VALUE] = "RETURN_VALUE",
     [SEND] = "SEND",
@@ -1785,6 +1791,7 @@ const char *_PyOpcode_OpName[267] = {
 PyAPI_DATA(const uint8_t) _PyOpcode_Caches[256];
 #ifdef NEED_OPCODE_METADATA
 const uint8_t _PyOpcode_Caches[256] = {
+    [RESUME] = 1,
     [TO_BOOL] = 3,
     [STORE_SUBSCR] = 1,
     [SEND] = 1,
@@ -1818,7 +1825,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
     [125] = 125,
     [126] = 126,
     [127] = 127,
-    [213] = 213,
     [214] = 214,
     [215] = 215,
     [216] = 216,
@@ -2026,6 +2032,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
     [RESERVED] = RESERVED,
     [RESUME] = RESUME,
     [RESUME_CHECK] = RESUME,
+    [RESUME_CHECK_JIT] = RESUME,
     [RETURN_GENERATOR] = RETURN_GENERATOR,
     [RETURN_VALUE] = RETURN_VALUE,
     [SEND] = SEND,
@@ -2079,7 +2086,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
     case 125: \
     case 126: \
     case 127: \
-    case 213: \
     case 214: \
     case 215: \
     case 216: \
index cea9fcce237301a24d6dd276928578e812fa1e68..8b52d77538abf28b38ffea8e232bf41b6f110666 100644 (file)
@@ -361,6 +361,8 @@ _PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame,
     int oparg, _PyExecutorObject *current_executor);
 
 PyAPI_FUNC(void) _PyJit_FinalizeTracing(PyThreadState *tstate, int err);
+PyAPI_FUNC(bool) _PyJit_EnterExecutorShouldStopTracing(int og_opcode);
+
 void _PyPrintExecutor(_PyExecutorObject *executor, const _PyUOpInstruction *marker);
 void _PyJit_TracerFree(_PyThreadStateImpl *_tstate);
 
index f9be01acb57197774b559d1aa8caa99fc14fb99f..e7ac7d59ff7e27d298096f09b294f4111f519c72 100644 (file)
@@ -36,7 +36,7 @@ typedef struct _PyUOpInstruction{
 } _PyUOpInstruction;
 
 // This is the length of the trace we translate initially.
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) && defined(_Py_JIT)
     // With asserts, the stencils are a lot larger
 #define UOP_MAX_TRACE_LENGTH 1000
 #else
index 451c0dd5732d8504b4086a22ca2174efa8d437a8..d29d98d3f166978efd5b2336c1f3c882a518c5cd 100644 (file)
@@ -330,17 +330,16 @@ extern "C" {
 #define _PY_FRAME_EX 547
 #define _PY_FRAME_GENERAL 548
 #define _PY_FRAME_KW 549
-#define _QUICKEN_RESUME 550
-#define _RECORD_4OS 551
-#define _RECORD_BOUND_METHOD 552
-#define _RECORD_CALLABLE 553
-#define _RECORD_CODE 554
-#define _RECORD_NOS 555
-#define _RECORD_NOS_GEN_FUNC 556
-#define _RECORD_TOS 557
-#define _RECORD_TOS_TYPE 558
-#define _REPLACE_WITH_TRUE 559
-#define _RESUME_CHECK RESUME_CHECK
+#define _RECORD_4OS 550
+#define _RECORD_BOUND_METHOD 551
+#define _RECORD_CALLABLE 552
+#define _RECORD_CODE 553
+#define _RECORD_NOS 554
+#define _RECORD_NOS_GEN_FUNC 555
+#define _RECORD_TOS 556
+#define _RECORD_TOS_TYPE 557
+#define _REPLACE_WITH_TRUE 558
+#define _RESUME_CHECK 559
 #define _RETURN_GENERATOR RETURN_GENERATOR
 #define _RETURN_VALUE 560
 #define _SAVE_RETURN_OFFSET 561
@@ -1141,152 +1140,148 @@ extern "C" {
 #define _PY_FRAME_EX_r31 1342
 #define _PY_FRAME_GENERAL_r01 1343
 #define _PY_FRAME_KW_r11 1344
-#define _QUICKEN_RESUME_r00 1345
-#define _QUICKEN_RESUME_r11 1346
-#define _QUICKEN_RESUME_r22 1347
-#define _QUICKEN_RESUME_r33 1348
-#define _REPLACE_WITH_TRUE_r02 1349
-#define _REPLACE_WITH_TRUE_r12 1350
-#define _REPLACE_WITH_TRUE_r23 1351
-#define _RESUME_CHECK_r00 1352
-#define _RESUME_CHECK_r11 1353
-#define _RESUME_CHECK_r22 1354
-#define _RESUME_CHECK_r33 1355
-#define _RETURN_GENERATOR_r01 1356
-#define _RETURN_VALUE_r11 1357
-#define _SAVE_RETURN_OFFSET_r00 1358
-#define _SAVE_RETURN_OFFSET_r11 1359
-#define _SAVE_RETURN_OFFSET_r22 1360
-#define _SAVE_RETURN_OFFSET_r33 1361
-#define _SEND_r22 1362
-#define _SEND_GEN_FRAME_r22 1363
-#define _SETUP_ANNOTATIONS_r00 1364
-#define _SET_ADD_r10 1365
-#define _SET_FUNCTION_ATTRIBUTE_r01 1366
-#define _SET_FUNCTION_ATTRIBUTE_r11 1367
-#define _SET_FUNCTION_ATTRIBUTE_r21 1368
-#define _SET_FUNCTION_ATTRIBUTE_r32 1369
-#define _SET_IP_r00 1370
-#define _SET_IP_r11 1371
-#define _SET_IP_r22 1372
-#define _SET_IP_r33 1373
-#define _SET_UPDATE_r10 1374
-#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1375
-#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1376
-#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1377
-#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1378
-#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1379
-#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1380
-#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1381
-#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1382
-#define _SPILL_OR_RELOAD_r01 1383
-#define _SPILL_OR_RELOAD_r02 1384
-#define _SPILL_OR_RELOAD_r03 1385
-#define _SPILL_OR_RELOAD_r10 1386
-#define _SPILL_OR_RELOAD_r12 1387
-#define _SPILL_OR_RELOAD_r13 1388
-#define _SPILL_OR_RELOAD_r20 1389
-#define _SPILL_OR_RELOAD_r21 1390
-#define _SPILL_OR_RELOAD_r23 1391
-#define _SPILL_OR_RELOAD_r30 1392
-#define _SPILL_OR_RELOAD_r31 1393
-#define _SPILL_OR_RELOAD_r32 1394
-#define _START_EXECUTOR_r00 1395
-#define _STORE_ATTR_r20 1396
-#define _STORE_ATTR_INSTANCE_VALUE_r21 1397
-#define _STORE_ATTR_SLOT_r21 1398
-#define _STORE_ATTR_WITH_HINT_r21 1399
-#define _STORE_DEREF_r10 1400
-#define _STORE_FAST_LOAD_FAST_r11 1401
-#define _STORE_FAST_STORE_FAST_r20 1402
-#define _STORE_GLOBAL_r10 1403
-#define _STORE_NAME_r10 1404
-#define _STORE_SLICE_r30 1405
-#define _STORE_SUBSCR_r30 1406
-#define _STORE_SUBSCR_DICT_r31 1407
-#define _STORE_SUBSCR_LIST_INT_r32 1408
-#define _SWAP_r11 1409
-#define _SWAP_2_r02 1410
-#define _SWAP_2_r12 1411
-#define _SWAP_2_r22 1412
-#define _SWAP_2_r33 1413
-#define _SWAP_3_r03 1414
-#define _SWAP_3_r13 1415
-#define _SWAP_3_r23 1416
-#define _SWAP_3_r33 1417
-#define _SWAP_FAST_r01 1418
-#define _SWAP_FAST_r11 1419
-#define _SWAP_FAST_r22 1420
-#define _SWAP_FAST_r33 1421
-#define _SWAP_FAST_0_r01 1422
-#define _SWAP_FAST_0_r11 1423
-#define _SWAP_FAST_0_r22 1424
-#define _SWAP_FAST_0_r33 1425
-#define _SWAP_FAST_1_r01 1426
-#define _SWAP_FAST_1_r11 1427
-#define _SWAP_FAST_1_r22 1428
-#define _SWAP_FAST_1_r33 1429
-#define _SWAP_FAST_2_r01 1430
-#define _SWAP_FAST_2_r11 1431
-#define _SWAP_FAST_2_r22 1432
-#define _SWAP_FAST_2_r33 1433
-#define _SWAP_FAST_3_r01 1434
-#define _SWAP_FAST_3_r11 1435
-#define _SWAP_FAST_3_r22 1436
-#define _SWAP_FAST_3_r33 1437
-#define _SWAP_FAST_4_r01 1438
-#define _SWAP_FAST_4_r11 1439
-#define _SWAP_FAST_4_r22 1440
-#define _SWAP_FAST_4_r33 1441
-#define _SWAP_FAST_5_r01 1442
-#define _SWAP_FAST_5_r11 1443
-#define _SWAP_FAST_5_r22 1444
-#define _SWAP_FAST_5_r33 1445
-#define _SWAP_FAST_6_r01 1446
-#define _SWAP_FAST_6_r11 1447
-#define _SWAP_FAST_6_r22 1448
-#define _SWAP_FAST_6_r33 1449
-#define _SWAP_FAST_7_r01 1450
-#define _SWAP_FAST_7_r11 1451
-#define _SWAP_FAST_7_r22 1452
-#define _SWAP_FAST_7_r33 1453
-#define _TIER2_RESUME_CHECK_r00 1454
-#define _TIER2_RESUME_CHECK_r11 1455
-#define _TIER2_RESUME_CHECK_r22 1456
-#define _TIER2_RESUME_CHECK_r33 1457
-#define _TO_BOOL_r11 1458
-#define _TO_BOOL_BOOL_r01 1459
-#define _TO_BOOL_BOOL_r11 1460
-#define _TO_BOOL_BOOL_r22 1461
-#define _TO_BOOL_BOOL_r33 1462
-#define _TO_BOOL_INT_r02 1463
-#define _TO_BOOL_INT_r12 1464
-#define _TO_BOOL_INT_r23 1465
-#define _TO_BOOL_LIST_r02 1466
-#define _TO_BOOL_LIST_r12 1467
-#define _TO_BOOL_LIST_r23 1468
-#define _TO_BOOL_NONE_r01 1469
-#define _TO_BOOL_NONE_r11 1470
-#define _TO_BOOL_NONE_r22 1471
-#define _TO_BOOL_NONE_r33 1472
-#define _TO_BOOL_STR_r02 1473
-#define _TO_BOOL_STR_r12 1474
-#define _TO_BOOL_STR_r23 1475
-#define _TRACE_RECORD_r00 1476
-#define _UNARY_INVERT_r12 1477
-#define _UNARY_NEGATIVE_r12 1478
-#define _UNARY_NOT_r01 1479
-#define _UNARY_NOT_r11 1480
-#define _UNARY_NOT_r22 1481
-#define _UNARY_NOT_r33 1482
-#define _UNPACK_EX_r10 1483
-#define _UNPACK_SEQUENCE_r10 1484
-#define _UNPACK_SEQUENCE_LIST_r10 1485
-#define _UNPACK_SEQUENCE_TUPLE_r10 1486
-#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1487
-#define _WITH_EXCEPT_START_r33 1488
-#define _YIELD_VALUE_r11 1489
-#define MAX_UOP_REGS_ID 1489
+#define _REPLACE_WITH_TRUE_r02 1345
+#define _REPLACE_WITH_TRUE_r12 1346
+#define _REPLACE_WITH_TRUE_r23 1347
+#define _RESUME_CHECK_r00 1348
+#define _RESUME_CHECK_r11 1349
+#define _RESUME_CHECK_r22 1350
+#define _RESUME_CHECK_r33 1351
+#define _RETURN_GENERATOR_r01 1352
+#define _RETURN_VALUE_r11 1353
+#define _SAVE_RETURN_OFFSET_r00 1354
+#define _SAVE_RETURN_OFFSET_r11 1355
+#define _SAVE_RETURN_OFFSET_r22 1356
+#define _SAVE_RETURN_OFFSET_r33 1357
+#define _SEND_r22 1358
+#define _SEND_GEN_FRAME_r22 1359
+#define _SETUP_ANNOTATIONS_r00 1360
+#define _SET_ADD_r10 1361
+#define _SET_FUNCTION_ATTRIBUTE_r01 1362
+#define _SET_FUNCTION_ATTRIBUTE_r11 1363
+#define _SET_FUNCTION_ATTRIBUTE_r21 1364
+#define _SET_FUNCTION_ATTRIBUTE_r32 1365
+#define _SET_IP_r00 1366
+#define _SET_IP_r11 1367
+#define _SET_IP_r22 1368
+#define _SET_IP_r33 1369
+#define _SET_UPDATE_r10 1370
+#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1371
+#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1372
+#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1373
+#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1374
+#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1375
+#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1376
+#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1377
+#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1378
+#define _SPILL_OR_RELOAD_r01 1379
+#define _SPILL_OR_RELOAD_r02 1380
+#define _SPILL_OR_RELOAD_r03 1381
+#define _SPILL_OR_RELOAD_r10 1382
+#define _SPILL_OR_RELOAD_r12 1383
+#define _SPILL_OR_RELOAD_r13 1384
+#define _SPILL_OR_RELOAD_r20 1385
+#define _SPILL_OR_RELOAD_r21 1386
+#define _SPILL_OR_RELOAD_r23 1387
+#define _SPILL_OR_RELOAD_r30 1388
+#define _SPILL_OR_RELOAD_r31 1389
+#define _SPILL_OR_RELOAD_r32 1390
+#define _START_EXECUTOR_r00 1391
+#define _STORE_ATTR_r20 1392
+#define _STORE_ATTR_INSTANCE_VALUE_r21 1393
+#define _STORE_ATTR_SLOT_r21 1394
+#define _STORE_ATTR_WITH_HINT_r21 1395
+#define _STORE_DEREF_r10 1396
+#define _STORE_FAST_LOAD_FAST_r11 1397
+#define _STORE_FAST_STORE_FAST_r20 1398
+#define _STORE_GLOBAL_r10 1399
+#define _STORE_NAME_r10 1400
+#define _STORE_SLICE_r30 1401
+#define _STORE_SUBSCR_r30 1402
+#define _STORE_SUBSCR_DICT_r31 1403
+#define _STORE_SUBSCR_LIST_INT_r32 1404
+#define _SWAP_r11 1405
+#define _SWAP_2_r02 1406
+#define _SWAP_2_r12 1407
+#define _SWAP_2_r22 1408
+#define _SWAP_2_r33 1409
+#define _SWAP_3_r03 1410
+#define _SWAP_3_r13 1411
+#define _SWAP_3_r23 1412
+#define _SWAP_3_r33 1413
+#define _SWAP_FAST_r01 1414
+#define _SWAP_FAST_r11 1415
+#define _SWAP_FAST_r22 1416
+#define _SWAP_FAST_r33 1417
+#define _SWAP_FAST_0_r01 1418
+#define _SWAP_FAST_0_r11 1419
+#define _SWAP_FAST_0_r22 1420
+#define _SWAP_FAST_0_r33 1421
+#define _SWAP_FAST_1_r01 1422
+#define _SWAP_FAST_1_r11 1423
+#define _SWAP_FAST_1_r22 1424
+#define _SWAP_FAST_1_r33 1425
+#define _SWAP_FAST_2_r01 1426
+#define _SWAP_FAST_2_r11 1427
+#define _SWAP_FAST_2_r22 1428
+#define _SWAP_FAST_2_r33 1429
+#define _SWAP_FAST_3_r01 1430
+#define _SWAP_FAST_3_r11 1431
+#define _SWAP_FAST_3_r22 1432
+#define _SWAP_FAST_3_r33 1433
+#define _SWAP_FAST_4_r01 1434
+#define _SWAP_FAST_4_r11 1435
+#define _SWAP_FAST_4_r22 1436
+#define _SWAP_FAST_4_r33 1437
+#define _SWAP_FAST_5_r01 1438
+#define _SWAP_FAST_5_r11 1439
+#define _SWAP_FAST_5_r22 1440
+#define _SWAP_FAST_5_r33 1441
+#define _SWAP_FAST_6_r01 1442
+#define _SWAP_FAST_6_r11 1443
+#define _SWAP_FAST_6_r22 1444
+#define _SWAP_FAST_6_r33 1445
+#define _SWAP_FAST_7_r01 1446
+#define _SWAP_FAST_7_r11 1447
+#define _SWAP_FAST_7_r22 1448
+#define _SWAP_FAST_7_r33 1449
+#define _TIER2_RESUME_CHECK_r00 1450
+#define _TIER2_RESUME_CHECK_r11 1451
+#define _TIER2_RESUME_CHECK_r22 1452
+#define _TIER2_RESUME_CHECK_r33 1453
+#define _TO_BOOL_r11 1454
+#define _TO_BOOL_BOOL_r01 1455
+#define _TO_BOOL_BOOL_r11 1456
+#define _TO_BOOL_BOOL_r22 1457
+#define _TO_BOOL_BOOL_r33 1458
+#define _TO_BOOL_INT_r02 1459
+#define _TO_BOOL_INT_r12 1460
+#define _TO_BOOL_INT_r23 1461
+#define _TO_BOOL_LIST_r02 1462
+#define _TO_BOOL_LIST_r12 1463
+#define _TO_BOOL_LIST_r23 1464
+#define _TO_BOOL_NONE_r01 1465
+#define _TO_BOOL_NONE_r11 1466
+#define _TO_BOOL_NONE_r22 1467
+#define _TO_BOOL_NONE_r33 1468
+#define _TO_BOOL_STR_r02 1469
+#define _TO_BOOL_STR_r12 1470
+#define _TO_BOOL_STR_r23 1471
+#define _TRACE_RECORD_r00 1472
+#define _UNARY_INVERT_r12 1473
+#define _UNARY_NEGATIVE_r12 1474
+#define _UNARY_NOT_r01 1475
+#define _UNARY_NOT_r11 1476
+#define _UNARY_NOT_r22 1477
+#define _UNARY_NOT_r33 1478
+#define _UNPACK_EX_r10 1479
+#define _UNPACK_SEQUENCE_r10 1480
+#define _UNPACK_SEQUENCE_LIST_r10 1481
+#define _UNPACK_SEQUENCE_TUPLE_r10 1482
+#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1483
+#define _WITH_EXCEPT_START_r33 1484
+#define _YIELD_VALUE_r11 1485
+#define MAX_UOP_REGS_ID 1485
 
 #ifdef __cplusplus
 }
index c46368444f4c597f9ea59c5a2a07bd15dda24fcf..f9173fd83c295e01e8d08d9316472031d81fefe2 100644 (file)
@@ -201,21 +201,22 @@ extern "C" {
 #define LOAD_SUPER_ATTR_ATTR                   195
 #define LOAD_SUPER_ATTR_METHOD                 196
 #define RESUME_CHECK                           197
-#define SEND_GEN                               198
-#define STORE_ATTR_INSTANCE_VALUE              199
-#define STORE_ATTR_SLOT                        200
-#define STORE_ATTR_WITH_HINT                   201
-#define STORE_SUBSCR_DICT                      202
-#define STORE_SUBSCR_LIST_INT                  203
-#define TO_BOOL_ALWAYS_TRUE                    204
-#define TO_BOOL_BOOL                           205
-#define TO_BOOL_INT                            206
-#define TO_BOOL_LIST                           207
-#define TO_BOOL_NONE                           208
-#define TO_BOOL_STR                            209
-#define UNPACK_SEQUENCE_LIST                   210
-#define UNPACK_SEQUENCE_TUPLE                  211
-#define UNPACK_SEQUENCE_TWO_TUPLE              212
+#define RESUME_CHECK_JIT                       198
+#define SEND_GEN                               199
+#define STORE_ATTR_INSTANCE_VALUE              200
+#define STORE_ATTR_SLOT                        201
+#define STORE_ATTR_WITH_HINT                   202
+#define STORE_SUBSCR_DICT                      203
+#define STORE_SUBSCR_LIST_INT                  204
+#define TO_BOOL_ALWAYS_TRUE                    205
+#define TO_BOOL_BOOL                           206
+#define TO_BOOL_INT                            207
+#define TO_BOOL_LIST                           208
+#define TO_BOOL_NONE                           209
+#define TO_BOOL_STR                            210
+#define UNPACK_SEQUENCE_LIST                   211
+#define UNPACK_SEQUENCE_TUPLE                  212
+#define UNPACK_SEQUENCE_TWO_TUPLE              213
 #define INSTRUMENTED_END_FOR                   233
 #define INSTRUMENTED_POP_ITER                  234
 #define INSTRUMENTED_END_SEND                  235
index 6e37288c32dd9a477bfb161a981e998185da05dc..8d2c1ece8bc6a82c5a4434c46a4909c94042e699 100644 (file)
@@ -5,6 +5,7 @@
 _specializations = frozendict(
     RESUME=(
             "RESUME_CHECK",
+            "RESUME_CHECK_JIT",
     ),
     TO_BOOL=(
             "TO_BOOL_ALWAYS_TRUE",
@@ -195,21 +196,22 @@ _specialized_opmap = frozendict(
     LOAD_SUPER_ATTR_ATTR=195,
     LOAD_SUPER_ATTR_METHOD=196,
     RESUME_CHECK=197,
-    SEND_GEN=198,
-    STORE_ATTR_INSTANCE_VALUE=199,
-    STORE_ATTR_SLOT=200,
-    STORE_ATTR_WITH_HINT=201,
-    STORE_SUBSCR_DICT=202,
-    STORE_SUBSCR_LIST_INT=203,
-    TO_BOOL_ALWAYS_TRUE=204,
-    TO_BOOL_BOOL=205,
-    TO_BOOL_INT=206,
-    TO_BOOL_LIST=207,
-    TO_BOOL_NONE=208,
-    TO_BOOL_STR=209,
-    UNPACK_SEQUENCE_LIST=210,
-    UNPACK_SEQUENCE_TUPLE=211,
-    UNPACK_SEQUENCE_TWO_TUPLE=212,
+    RESUME_CHECK_JIT=198,
+    SEND_GEN=199,
+    STORE_ATTR_INSTANCE_VALUE=200,
+    STORE_ATTR_SLOT=201,
+    STORE_ATTR_WITH_HINT=202,
+    STORE_SUBSCR_DICT=203,
+    STORE_SUBSCR_LIST_INT=204,
+    TO_BOOL_ALWAYS_TRUE=205,
+    TO_BOOL_BOOL=206,
+    TO_BOOL_INT=207,
+    TO_BOOL_LIST=208,
+    TO_BOOL_NONE=209,
+    TO_BOOL_STR=210,
+    UNPACK_SEQUENCE_LIST=211,
+    UNPACK_SEQUENCE_TUPLE=212,
+    UNPACK_SEQUENCE_TWO_TUPLE=213,
 )
 
 opmap = frozendict(
index 165f42baed94e3d26dedd2afb17a1dc53a70936d..d53b94d89b46f74daa733bb9035da9da1f5f52db 100644 (file)
@@ -119,6 +119,9 @@ _cache_format = frozendict(
     POP_JUMP_IF_NOT_NONE=frozendict(
         counter=1,
     ),
+    RESUME=frozendict(
+        counter=1,
+    ),
 )
 
 _inline_cache_entries = frozendict({
index d66031ed31cbe2becd8483e0bacd7c7a91a73408..1385a7f840d7bec51603ab48ccb0cea28cfc2d9f 100644 (file)
@@ -15,7 +15,7 @@ from test.support import (script_helper, requires_specialization,
 
 _testinternalcapi = import_helper.import_module("_testinternalcapi")
 
-from _testinternalcapi import _PY_NSMALLPOSINTS, TIER2_THRESHOLD
+from _testinternalcapi import _PY_NSMALLPOSINTS, TIER2_THRESHOLD, TIER2_RESUME_THRESHOLD
 
 #For test of issue 136154
 GLOBAL_136154 = 42
@@ -322,6 +322,23 @@ class TestUops(unittest.TestCase):
         uops = get_opnames(ex)
         self.assertIn("_JUMP_TO_TOP", uops)
 
+    def test_resume(self):
+        def testfunc(x):
+            if x <= 1:
+                return 1
+            return testfunc(x-1)
+
+        for _ in range((TIER2_RESUME_THRESHOLD + 99)//100):
+            testfunc(101)
+
+        ex = get_first_executor(testfunc)
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        # 0. _START_EXECUTOR
+        # 1. _MAKE_WARM
+        # 2. _TIER2_RESUME_CHECK
+        self.assertEqual(uops[2], "_TIER2_RESUME_CHECK")
+
     def test_jump_forward(self):
         def testfunc(n):
             a = 0
@@ -1419,7 +1436,7 @@ class TestUopsOptimization(unittest.TestCase):
 
         def thing(a):
             x = 0
-            for i in range(TIER2_THRESHOLD * 2 + 1):
+            for i in range(TIER2_THRESHOLD + 1):
                 x += a.attr
                 # The first TIER2_THRESHOLD iterations we set the attribute on
                 # this dummy class, which shouldn't trigger the type watcher.
@@ -1437,8 +1454,7 @@ class TestUopsOptimization(unittest.TestCase):
 
         res, ex = self._run_with_optimizer(thing, Foo())
         opnames = list(iter_opnames(ex))
-        self.assertIsNotNone(ex)
-        self.assertEqual(res, TIER2_THRESHOLD * 6 + 1)
+        self.assertEqual(res, TIER2_THRESHOLD * 2 + 2)
         call = opnames.index("_CALL_BUILTIN_FAST")
         load_attr_top = opnames.index("_POP_TOP_LOAD_CONST_INLINE_BORROW", 0, call)
         load_attr_bottom = opnames.index("_POP_TOP_LOAD_CONST_INLINE_BORROW", call)
index 0d5c6e6e77f5d799a7efe7ce01c1b2911f3100cf..19fa387cd7b2712f22d9993e331428471419fe10 100644 (file)
@@ -1437,6 +1437,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,
                 ]
@@ -1445,7 +1446,7 @@ class CodeLocationTest(unittest.TestCase):
                 [
                     (1 << 7)
                     | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3)
-                    | (3 - 1),
+                    | (4 - 1),
                     0,
                 ]
             ),
@@ -1453,7 +1454,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
index 302b2c21935efe1866a14ac203021fb1e7446c14..ac8837359c14454e0df089fd286d9c399cbbc617 100644 (file)
@@ -2458,8 +2458,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)
index cefd64ddfe84173e1f95e6b1606b69f805e949ca..f4210db5bd788ee3c8729d44037d5bc757ad29f3 100644 (file)
@@ -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)
@@ -617,10 +617,10 @@ dis_asyncwith = """\
                 CALL                     0
                 GET_AWAITABLE            1
                 LOAD_CONST               0 (None)
-        L2:     SEND                     3 (to L5)
+        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
 
@@ -633,10 +633,10 @@ dis_asyncwith = """\
                 CALL                     3
                 GET_AWAITABLE            2
                 LOAD_CONST               0 (None)
-        L8:     SEND                     3 (to L11)
+        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
 
@@ -646,17 +646,17 @@ dis_asyncwith = """\
                 RETURN_VALUE
 
 %4d   L12:     CLEANUP_THROW
-       L13:     JUMP_BACKWARD_NO_INTERRUPT 26 (to L5)
+       L13:     JUMP_BACKWARD_NO_INTERRUPT 27 (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)
+       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
@@ -880,7 +880,7 @@ Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>:
                RETURN_GENERATOR
                POP_TOP
        L1:     RESUME                   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)
@@ -888,7 +888,7 @@ Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>:
                YIELD_VALUE              0
                RESUME                   5
                POP_TOP
-               JUMP_BACKWARD           16 (to L2)
+               JUMP_BACKWARD           17 (to L2)
        L3:     END_FOR
                POP_ITER
                LOAD_CONST               0 (None)
@@ -909,7 +909,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)
@@ -926,7 +926,7 @@ 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               2 ((1, 2, 3))
@@ -1323,13 +1323,15 @@ 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               0 ('a')
               LOAD_ATTR_SLOT           0 (__class__)
@@ -1338,13 +1340,15 @@ class DisTests(DisTestBase):
         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
@@ -1355,7 +1359,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
@@ -1364,7 +1370,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
@@ -1431,7 +1439,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 = 22
                     empty_caches = 7
                     self.assertEqual(caches.count(""), empty_caches)
                     self.assertEqual(len(caches), total_caches)
@@ -1776,210 +1784,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=4, 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_CONST', arg=2, 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=3, 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_CONST', arg=0, 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=33, argval=94, 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='POP_TOP', arg=None, argval=None, argrepr='', offset=90, start_offset=90, starts_line=False, line_number=8),
-  make_inst(opname='JUMP_FORWARD', arg=13, argval=120, argrepr='to L5', offset=92, start_offset=92, starts_line=False, line_number=8),
-  make_inst(opname='END_FOR', arg=None, argval=None, argrepr='', offset=94, start_offset=94, starts_line=True, line_number=3, label=4),
-  make_inst(opname='POP_ITER', arg=None, argval=None, argrepr='', offset=96, start_offset=96, starts_line=False, line_number=3),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=98, start_offset=98, 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=108, start_offset=108, starts_line=False, line_number=10),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=110, start_offset=110, 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=118, start_offset=118, starts_line=False, line_number=10),
-  make_inst(opname='LOAD_FAST_CHECK', arg=0, argval='i', argrepr='i', offset=120, start_offset=120, starts_line=True, line_number=11, label=5),
-  make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=122, start_offset=122, 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=214, argrepr='to L8', offset=130, start_offset=130, starts_line=False, line_number=11, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=134, start_offset=134, starts_line=False, line_number=11),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=136, start_offset=136, 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=146, start_offset=146, starts_line=False, line_number=12),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=148, start_offset=148, 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=156, start_offset=156, starts_line=False, line_number=12),
-  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=True, line_number=13),
-  make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=160, start_offset=160, starts_line=False, line_number=13),
-  make_inst(opname='BINARY_OP', arg=23, argval=23, argrepr='-=', offset=162, start_offset=162, 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=174, start_offset=174, starts_line=False, line_number=13),
-  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=176, start_offset=176, starts_line=True, line_number=14),
-  make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=178, start_offset=178, starts_line=False, line_number=14),
-  make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=180, start_offset=180, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=194, argrepr='to L6', offset=184, start_offset=184, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=188, start_offset=188, starts_line=False, line_number=14),
-  make_inst(opname='JUMP_BACKWARD', arg=37, argval=120, argrepr='to L5', offset=190, start_offset=190, 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=194, start_offset=194, starts_line=True, line_number=16, label=6),
-  make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=196, start_offset=196, starts_line=False, line_number=16),
-  make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=198, start_offset=198, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=212, argrepr='to L7', offset=202, start_offset=202, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=206, start_offset=206, starts_line=False, line_number=16),
-  make_inst(opname='JUMP_BACKWARD', arg=46, argval=120, argrepr='to L5', offset=208, start_offset=208, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='JUMP_FORWARD', arg=11, argval=236, argrepr='to L9', offset=212, start_offset=212, starts_line=True, line_number=17, label=7),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=214, start_offset=214, 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=224, start_offset=224, starts_line=False, line_number=19),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=226, start_offset=226, 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=234, start_offset=234, starts_line=False, line_number=19),
-  make_inst(opname='NOP', arg=None, argval=None, argrepr='', offset=236, start_offset=236, starts_line=True, line_number=20, label=9),
-  make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=238, start_offset=238, starts_line=True, line_number=21),
-  make_inst(opname='LOAD_SMALL_INT', arg=0, argval=0, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=21),
-  make_inst(opname='BINARY_OP', arg=11, argval=11, argrepr='/', offset=242, start_offset=242, 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=254, start_offset=254, starts_line=False, line_number=21),
-  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=256, start_offset=256, starts_line=True, line_number=25),
-  make_inst(opname='COPY', arg=1, argval=1, argrepr='', offset=258, start_offset=258, starts_line=False, line_number=25),
-  make_inst(opname='LOAD_SPECIAL', arg=1, argval=1, argrepr='__exit__', offset=260, start_offset=260, starts_line=False, line_number=25),
-  make_inst(opname='SWAP', arg=2, argval=2, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=25),
-  make_inst(opname='SWAP', arg=3, argval=3, argrepr='', offset=264, start_offset=264, starts_line=False, line_number=25),
-  make_inst(opname='LOAD_SPECIAL', arg=0, argval=0, argrepr='__enter__', offset=266, start_offset=266, starts_line=False, line_number=25),
-  make_inst(opname='CALL', arg=0, argval=0, argrepr='', offset=268, start_offset=268, 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=276, start_offset=276, starts_line=False, line_number=25),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=278, start_offset=278, 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=288, start_offset=288, starts_line=False, line_number=26),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=290, start_offset=290, 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=298, start_offset=298, starts_line=False, line_number=26),
-  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=300, start_offset=300, starts_line=True, 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='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=None, argval=None, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=3),
+  make_inst(opname='FOR_ITER', arg=33, argval=96, argrepr='to L4', offset=26, start_offset=26, 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=30, start_offset=30, starts_line=False, line_number=3),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=32, start_offset=32, 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=42, start_offset=42, starts_line=False, line_number=4),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=44, start_offset=44, 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=52, start_offset=52, starts_line=False, line_number=4),
+  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=54, start_offset=54, starts_line=True, line_number=5),
+  make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5),
+  make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=58, start_offset=58, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=72, argrepr='to L2', offset=62, start_offset=62, starts_line=False, line_number=5, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=66, start_offset=66, starts_line=False, line_number=5),
+  make_inst(opname='JUMP_BACKWARD', arg=23, argval=26, argrepr='to L1', offset=68, start_offset=68, 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=72, start_offset=72, starts_line=True, line_number=7, label=2),
+  make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=74, start_offset=74, starts_line=False, line_number=7),
+  make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=76, start_offset=76, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=90, argrepr='to L3', offset=80, start_offset=80, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=False, line_number=7),
+  make_inst(opname='JUMP_BACKWARD', arg=32, argval=26, argrepr='to L1', offset=86, start_offset=86, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=90, start_offset=90, starts_line=True, line_number=8, label=3),
+  make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=92, start_offset=92, starts_line=False, line_number=8),
+  make_inst(opname='JUMP_FORWARD', arg=13, argval=122, argrepr='to L5', offset=94, start_offset=94, starts_line=False, line_number=8),
+  make_inst(opname='END_FOR', arg=None, argval=None, argrepr='', offset=96, start_offset=96, starts_line=True, line_number=3, label=4),
+  make_inst(opname='POP_ITER', arg=None, argval=None, argrepr='', offset=98, start_offset=98, starts_line=False, line_number=3),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=100, start_offset=100, 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=110, start_offset=110, starts_line=False, line_number=10),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=112, start_offset=112, 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=120, start_offset=120, starts_line=False, line_number=10),
+  make_inst(opname='LOAD_FAST_CHECK', arg=0, argval='i', argrepr='i', offset=122, start_offset=122, starts_line=True, line_number=11, label=5),
+  make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=124, start_offset=124, 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=216, argrepr='to L8', offset=132, start_offset=132, starts_line=False, line_number=11, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=136, start_offset=136, starts_line=False, line_number=11),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=138, start_offset=138, 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=148, start_offset=148, starts_line=False, line_number=12),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=150, start_offset=150, 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=158, start_offset=158, starts_line=False, line_number=12),
+  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=160, start_offset=160, starts_line=True, line_number=13),
+  make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=162, start_offset=162, starts_line=False, line_number=13),
+  make_inst(opname='BINARY_OP', arg=23, argval=23, argrepr='-=', offset=164, start_offset=164, 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=176, start_offset=176, starts_line=False, line_number=13),
+  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=True, line_number=14),
+  make_inst(opname='LOAD_SMALL_INT', arg=6, argval=6, argrepr='', offset=180, start_offset=180, starts_line=False, line_number=14),
+  make_inst(opname='COMPARE_OP', arg=148, argval='>', argrepr='bool(>)', offset=182, start_offset=182, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='POP_JUMP_IF_FALSE', arg=3, argval=196, argrepr='to L6', offset=186, start_offset=186, starts_line=False, line_number=14, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=190, start_offset=190, starts_line=False, line_number=14),
+  make_inst(opname='JUMP_BACKWARD', arg=37, argval=122, argrepr='to L5', offset=192, start_offset=192, 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=196, start_offset=196, starts_line=True, line_number=16, label=6),
+  make_inst(opname='LOAD_SMALL_INT', arg=4, argval=4, argrepr='', offset=198, start_offset=198, starts_line=False, line_number=16),
+  make_inst(opname='COMPARE_OP', arg=18, argval='<', argrepr='bool(<)', offset=200, start_offset=200, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='POP_JUMP_IF_TRUE', arg=3, argval=214, argrepr='to L7', offset=204, start_offset=204, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=208, start_offset=208, starts_line=False, line_number=16),
+  make_inst(opname='JUMP_BACKWARD', arg=46, argval=122, argrepr='to L5', offset=210, start_offset=210, starts_line=False, line_number=16, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='JUMP_FORWARD', arg=11, argval=238, argrepr='to L9', offset=214, start_offset=214, starts_line=True, line_number=17, label=7),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=216, start_offset=216, 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=226, start_offset=226, starts_line=False, line_number=19),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=228, start_offset=228, 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=236, start_offset=236, starts_line=False, line_number=19),
+  make_inst(opname='NOP', arg=None, argval=None, argrepr='', offset=238, start_offset=238, starts_line=True, line_number=20, label=9),
+  make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=240, start_offset=240, starts_line=True, line_number=21),
+  make_inst(opname='LOAD_SMALL_INT', arg=0, argval=0, argrepr='', offset=242, start_offset=242, starts_line=False, line_number=21),
+  make_inst(opname='BINARY_OP', arg=11, argval=11, argrepr='/', offset=244, start_offset=244, 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=256, start_offset=256, starts_line=False, line_number=21),
+  make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='i', argrepr='i', offset=258, start_offset=258, starts_line=True, line_number=25),
+  make_inst(opname='COPY', arg=1, argval=1, argrepr='', offset=260, start_offset=260, starts_line=False, line_number=25),
+  make_inst(opname='LOAD_SPECIAL', arg=1, argval=1, argrepr='__exit__', offset=262, start_offset=262, starts_line=False, line_number=25),
+  make_inst(opname='SWAP', arg=2, argval=2, argrepr='', offset=264, start_offset=264, starts_line=False, line_number=25),
+  make_inst(opname='SWAP', arg=3, argval=3, argrepr='', offset=266, start_offset=266, starts_line=False, line_number=25),
+  make_inst(opname='LOAD_SPECIAL', arg=0, argval=0, argrepr='__enter__', offset=268, start_offset=268, starts_line=False, line_number=25),
+  make_inst(opname='CALL', arg=0, argval=0, argrepr='', offset=270, start_offset=270, 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=278, start_offset=278, starts_line=False, line_number=25),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=280, start_offset=280, 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=290, start_offset=290, starts_line=False, line_number=26),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=292, start_offset=292, 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=300, start_offset=300, starts_line=False, line_number=26),
+  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=302, start_offset=302, starts_line=True, line_number=25),
   make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=304, start_offset=304, starts_line=False, line_number=25),
-  make_inst(opname='CALL', arg=3, argval=3, argrepr='', offset=306, start_offset=306, 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=314, start_offset=314, starts_line=False, line_number=25),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=316, start_offset=316, 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=326, start_offset=326, starts_line=False, line_number=28),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=328, start_offset=328, 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=336, start_offset=336, starts_line=False, line_number=28),
-  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=338, start_offset=338, starts_line=False, line_number=28),
-  make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=28),
-  make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=True, line_number=25),
-  make_inst(opname='WITH_EXCEPT_START', arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=25),
-  make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=346, start_offset=346, 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=362, argrepr='to L11', offset=354, start_offset=354, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=358, start_offset=358, starts_line=False, line_number=25),
-  make_inst(opname='RERAISE', arg=2, argval=2, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=25),
-  make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=25, label=11),
-  make_inst(opname='POP_EXCEPT', 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='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=306, start_offset=306, starts_line=False, line_number=25),
+  make_inst(opname='CALL', arg=3, argval=3, argrepr='', offset=308, start_offset=308, 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=316, start_offset=316, starts_line=False, line_number=25),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=318, start_offset=318, 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=328, start_offset=328, starts_line=False, line_number=28),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=330, start_offset=330, 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=338, start_offset=338, starts_line=False, line_number=28),
+  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=340, start_offset=340, starts_line=False, line_number=28),
+  make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=28),
+  make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=True, line_number=25),
+  make_inst(opname='WITH_EXCEPT_START', arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=False, line_number=25),
+  make_inst(opname='TO_BOOL', arg=None, argval=None, argrepr='', offset=348, start_offset=348, 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=364, argrepr='to L11', offset=356, start_offset=356, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=25),
+  make_inst(opname='RERAISE', arg=2, argval=2, 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, label=11),
+  make_inst(opname='POP_EXCEPT', 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='POP_TOP', arg=None, argval=None, argrepr='', offset=370, start_offset=370, starts_line=False, line_number=25),
-  make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=29, argval=316, argrepr='to L10', offset=372, start_offset=372, starts_line=False, line_number=25),
-  make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=374, start_offset=374, starts_line=True, line_number=None),
-  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=None),
-  make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=378, start_offset=378, starts_line=False, line_number=None),
-  make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=380, start_offset=380, starts_line=False, line_number=None),
-  make_inst(opname='LOAD_GLOBAL', arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=382, start_offset=382, 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=392, start_offset=392, starts_line=False, line_number=22),
-  make_inst(opname='POP_JUMP_IF_FALSE', arg=15, argval=428, argrepr='to L12', offset=394, start_offset=394, starts_line=False, line_number=22, cache_info=[('counter', 1, b'\x00\x00')]),
-  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=22),
-  make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=400, start_offset=400, starts_line=False, line_number=22),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=402, start_offset=402, 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=412, start_offset=412, starts_line=False, line_number=23),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=414, start_offset=414, 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=422, start_offset=422, starts_line=False, line_number=23),
-  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=424, start_offset=424, starts_line=False, line_number=23),
-  make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=56, argval=316, argrepr='to L10', offset=426, start_offset=426, starts_line=False, line_number=23),
-  make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=428, start_offset=428, starts_line=True, line_number=22, label=12),
-  make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=430, start_offset=430, starts_line=True, line_number=None),
-  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None),
-  make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None),
-  make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=436, start_offset=436, starts_line=False, line_number=None),
-  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=438, start_offset=438, 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=448, start_offset=448, starts_line=False, line_number=28),
-  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=450, start_offset=450, 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=458, start_offset=458, starts_line=False, line_number=28),
-  make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=460, start_offset=460, starts_line=False, line_number=28),
-  make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=462, start_offset=462, starts_line=True, line_number=None),
-  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=464, start_offset=464, starts_line=False, line_number=None),
-  make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=466, start_offset=466, starts_line=False, line_number=None),
+  make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=372, start_offset=372, starts_line=False, line_number=25),
+  make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=29, argval=318, argrepr='to L10', offset=374, start_offset=374, starts_line=False, line_number=25),
+  make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=376, start_offset=376, starts_line=True, line_number=None),
+  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=378, start_offset=378, starts_line=False, line_number=None),
+  make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=380, start_offset=380, starts_line=False, line_number=None),
+  make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=382, start_offset=382, starts_line=False, line_number=None),
+  make_inst(opname='LOAD_GLOBAL', arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=384, start_offset=384, 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=394, start_offset=394, starts_line=False, line_number=22),
+  make_inst(opname='POP_JUMP_IF_FALSE', arg=15, argval=430, argrepr='to L12', offset=396, start_offset=396, starts_line=False, line_number=22, cache_info=[('counter', 1, b'\x00\x00')]),
+  make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=400, start_offset=400, starts_line=False, line_number=22),
+  make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=402, start_offset=402, starts_line=False, line_number=22),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=404, start_offset=404, 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=414, start_offset=414, starts_line=False, line_number=23),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=416, start_offset=416, 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=424, start_offset=424, starts_line=False, line_number=23),
+  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=23),
+  make_inst(opname='JUMP_BACKWARD_NO_INTERRUPT', arg=56, argval=318, argrepr='to L10', offset=428, start_offset=428, starts_line=False, line_number=23),
+  make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=430, start_offset=430, starts_line=True, line_number=22, label=12),
+  make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=432, start_offset=432, starts_line=True, line_number=None),
+  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=434, start_offset=434, starts_line=False, line_number=None),
+  make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=436, start_offset=436, starts_line=False, line_number=None),
+  make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=438, start_offset=438, starts_line=False, line_number=None),
+  make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=440, start_offset=440, 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=450, start_offset=450, starts_line=False, line_number=28),
+  make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=452, start_offset=452, 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=460, start_offset=460, starts_line=False, line_number=28),
+  make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=462, start_offset=462, starts_line=False, line_number=28),
+  make_inst(opname='COPY', arg=3, argval=3, argrepr='', offset=464, start_offset=464, starts_line=True, line_number=None),
+  make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=466, start_offset=466, starts_line=False, line_number=None),
+  make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=468, start_offset=468, 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_CONST', arg=0, 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),
 ]
 
 
@@ -2370,8 +2378,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):
@@ -2439,7 +2449,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):
@@ -2576,6 +2586,7 @@ class TestDisCLI(unittest.TestCase):
         source = 'print()'
         expect = '''
             0           RESUME                   0
+                        CACHE                    0 (counter: 0)
 
             1           LOAD_NAME                0 (print)
                         PUSH_NULL
@@ -2596,8 +2607,8 @@ class TestDisCLI(unittest.TestCase):
         expect = '''
             0          0       RESUME                   0
 
-            1          2       LOAD_CONST               0 (None)
-                       4       RETURN_VALUE
+            1          4       LOAD_CONST               0 (None)
+                       6       RETURN_VALUE
         '''
         for flag in ['-O', '--show-offsets']:
             self.check_output(source, expect, flag)
index 1b22e0ec8759ac48dcf4612db07f40ef750c3591..116a8bac6fb7b8a4a7a3caa456243f410264df62 100644 (file)
@@ -1214,19 +1214,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):
 
@@ -1236,22 +1237,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):
 
@@ -1264,28 +1266,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():
@@ -1296,16 +1299,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()
@@ -1313,16 +1316,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):
@@ -1370,10 +1373,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 ]
@@ -1390,11 +1393,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)]
 
 
 
@@ -1609,11 +1612,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', 30, 34),
+            ('branch right', 'func', 46, 60),
+            ('branch left', 'func', 30, 34),
+            ('branch left', 'func', 46, 52),
+            ('branch right', 'func', 30, 72)])
 
     def test_except_star(self):
 
@@ -1640,8 +1643,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 = [
@@ -1655,8 +1658,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)])
 
@@ -1668,8 +1671,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,
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-13-09-48-57.gh-issue-127958.U-znTv.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-13-09-48-57.gh-issue-127958.U-znTv.rst
new file mode 100644 (file)
index 0000000..9808a27
--- /dev/null
@@ -0,0 +1 @@
+Support tracing from function entrypoints in the JIT. Patch by Ken Jin.
index 8c316b7c8ddda0492ce0307049ed4740a9aa6029..e1acce8f586685cdfbdc03b6b2f88ab650e4f759 100644 (file)
@@ -3021,6 +3021,14 @@ module_exec(PyObject *module)
         return 1;
     }
 
+    // + 1 to specialize from RESUME to RESUME_CHECK_JIT
+    // + 1 more due to one loop spent on tracing.
+    long resume_threshold = interp->opt_config.resume_initial_value + 2;
+    if (PyModule_Add(module, "TIER2_RESUME_THRESHOLD",
+                    PyLong_FromLong(resume_threshold)) < 0) {
+        return 1;
+    }
+
     if (PyModule_Add(module, "SPECIALIZATION_THRESHOLD",
                         PyLong_FromLong(ADAPTIVE_WARMUP_VALUE + 1)) < 0) {
         return 1;
index 2f6845399d9e168d6ac7cdd914402dd43308fb52..948a413d98ddcd5bb91ad26689e8ee7f36838e56 100644 (file)
             INSTRUCTION_STATS(ENTER_EXECUTOR);
             opcode = ENTER_EXECUTOR;
             #ifdef _Py_TIER2
+            PyCodeObject *code = _PyFrame_GetCode(frame);
+            _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             if (IS_JIT_TRACING()) {
+                int og_opcode = executor->vm_data.opcode;
+                int og_oparg = (oparg & ~255) | executor->vm_data.oparg;
                 next_instr = this_instr;
+                if (_PyJit_EnterExecutorShouldStopTracing(og_opcode)) {
+                    if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) {
+                        PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter);
+                    }
+                    opcode = og_opcode;
+                    oparg = og_oparg;
+                    DISPATCH_GOTO_NON_TRACING();
+                }
                 JUMP_TO_LABEL(stop_tracing);
             }
-            PyCodeObject *code = _PyFrame_GetCode(frame);
-            _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             assert(executor->vm_data.index == INSTR_OFFSET() - 1);
             assert(executor->vm_data.code == code);
             assert(executor->vm_data.valid);
             _Py_CODEUNIT* const this_instr = next_instr;
             (void)this_instr;
             frame->instr_ptr = next_instr;
-            next_instr += 1;
+            next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_RESUME);
+            /* Skip 1 cache entry */
             // _LOAD_BYTECODE
             {
                 #ifdef Py_GIL_DISABLED
             // _JIT
             {
                 #ifdef _Py_TIER2
+                bool is_resume = this_instr->op.code == RESUME_CHECK_JIT;
                 _Py_BackoffCounter counter = this_instr[1].counter;
-                if (!IS_JIT_TRACING() && backoff_counter_triggers(counter) &&
-                    this_instr->op.code == JUMP_BACKWARD_JIT &&
+                if ((backoff_counter_triggers(counter) &&
+                        !IS_JIT_TRACING() &&
+                        (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) &&
                     next_instr->op.code != ENTER_EXECUTOR) {
                     _Py_CODEUNIT *insert_exec_at = this_instr;
                     while (oparg > 255) {
                         oparg >>= 8;
                         insert_exec_at--;
                     }
-                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, stack_pointer, 0, NULL, oparg, NULL);
+                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,
+                        is_resume ? insert_exec_at : next_instr, stack_pointer, 0, NULL, oparg, NULL);
                     if (succ) {
                         ENTER_TRACING();
                     }
             (void)(opcode);
             #endif
             frame->instr_ptr = next_instr;
-            next_instr += 1;
+            next_instr += 2;
             INSTRUCTION_STATS(RESUME);
             PREDICTED_RESUME:;
-            _Py_CODEUNIT* const this_instr = next_instr - 1;
+            _Py_CODEUNIT* const this_instr = next_instr - 2;
             (void)this_instr;
             // _LOAD_BYTECODE
             {
             }
             // _QUICKEN_RESUME
             {
-                #if ENABLE_SPECIALIZATION
-                if (tstate->tracing == 0 && this_instr->op.code == RESUME) {
-                    FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK);
-                }
-                #endif  /* ENABLE_SPECIALIZATION */
+                uint16_t counter = read_u16(&this_instr[1].cache);
+                (void)counter;
+                _PyFrame_SetStackPointer(frame, stack_pointer);
+                _Py_Specialize_Resume(this_instr, tstate, frame);
+                stack_pointer = _PyFrame_GetStackPointer(frame);
             }
             // _CHECK_PERIODIC_IF_NOT_YIELD_FROM
             {
             _Py_CODEUNIT* const this_instr = next_instr;
             (void)this_instr;
             frame->instr_ptr = next_instr;
-            next_instr += 1;
+            next_instr += 2;
             INSTRUCTION_STATS(RESUME_CHECK);
-            static_assert(0 == 0, "incorrect cache size");
+            static_assert(1 == 1, "incorrect cache size");
+            /* Skip 1 cache entry */
             #if defined(__EMSCRIPTEN__)
             if (_Py_emscripten_signal_clock == 0) {
                 UPDATE_MISS_STATS(RESUME);
             DISPATCH();
         }
 
+        TARGET(RESUME_CHECK_JIT) {
+            #if _Py_TAIL_CALL_INTERP
+            int opcode = RESUME_CHECK_JIT;
+            (void)(opcode);
+            #endif
+            _Py_CODEUNIT* const this_instr = next_instr;
+            (void)this_instr;
+            frame->instr_ptr = next_instr;
+            next_instr += 2;
+            INSTRUCTION_STATS(RESUME_CHECK_JIT);
+            static_assert(1 == 1, "incorrect cache size");
+            /* Skip 1 cache entry */
+            // _RESUME_CHECK
+            {
+                #if defined(__EMSCRIPTEN__)
+                if (_Py_emscripten_signal_clock == 0) {
+                    UPDATE_MISS_STATS(RESUME);
+                    assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                    JUMP_TO_PREDICTED(RESUME);
+                }
+                _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING;
+                #endif
+                uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
+                uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
+                assert((version & _PY_EVAL_EVENTS_MASK) == 0);
+                if (eval_breaker != version) {
+                    UPDATE_MISS_STATS(RESUME);
+                    assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                    JUMP_TO_PREDICTED(RESUME);
+                }
+                #ifdef Py_GIL_DISABLED
+                if (frame->tlbc_index !=
+                    ((_PyThreadStateImpl *)tstate)->tlbc_index) {
+                    UPDATE_MISS_STATS(RESUME);
+                    assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                    JUMP_TO_PREDICTED(RESUME);
+                }
+                #endif
+            }
+            // _JIT
+            {
+                #ifdef _Py_TIER2
+                bool is_resume = this_instr->op.code == RESUME_CHECK_JIT;
+                _Py_BackoffCounter counter = this_instr[1].counter;
+                if ((backoff_counter_triggers(counter) &&
+                        !IS_JIT_TRACING() &&
+                        (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) &&
+                    next_instr->op.code != ENTER_EXECUTOR) {
+                    _Py_CODEUNIT *insert_exec_at = this_instr;
+                    while (oparg > 255) {
+                        oparg >>= 8;
+                        insert_exec_at--;
+                    }
+                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,
+                        is_resume ? insert_exec_at : next_instr, stack_pointer, 0, NULL, oparg, NULL);
+                    if (succ) {
+                        ENTER_TRACING();
+                    }
+                    else {
+                        this_instr[1].counter = restart_backoff_counter(counter);
+                    }
+                }
+                else {
+                    ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
+                }
+                #endif
+            }
+            DISPATCH();
+        }
+
         TARGET(RETURN_GENERATOR) {
             #if _Py_TAIL_CALL_INTERP
             int opcode = RETURN_GENERATOR;
index f57c33feec2ac291e1646433a21065f83e5e8429..def462bacec176d2cb02ab16e559a77e74ac753d 100644 (file)
@@ -198,6 +198,7 @@ static void *opcode_targets_table[256] = {
     &&TARGET_LOAD_SUPER_ATTR_ATTR,
     &&TARGET_LOAD_SUPER_ATTR_METHOD,
     &&TARGET_RESUME_CHECK,
+    &&TARGET_RESUME_CHECK_JIT,
     &&TARGET_SEND_GEN,
     &&TARGET_STORE_ATTR_INSTANCE_VALUE,
     &&TARGET_STORE_ATTR_SLOT,
@@ -232,7 +233,6 @@ static void *opcode_targets_table[256] = {
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
-    &&_unknown_opcode,
     &&TARGET_INSTRUMENTED_END_FOR,
     &&TARGET_INSTRUMENTED_POP_ITER,
     &&TARGET_INSTRUMENTED_END_SEND,
@@ -472,7 +472,7 @@ static void *opcode_tracing_targets_table[256] = {
     &&TARGET_TRACE_RECORD,
     &&TARGET_TRACE_RECORD,
     &&TARGET_TRACE_RECORD,
-    &&_unknown_opcode,
+    &&TARGET_TRACE_RECORD,
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
@@ -718,6 +718,7 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RERAISE(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESERVED(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK(TAIL_CALL_PARAMS);
+static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK_JIT(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND(TAIL_CALL_PARAMS);
@@ -959,6 +960,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
     [RESERVED] = _TAIL_CALL_RESERVED,
     [RESUME] = _TAIL_CALL_RESUME,
     [RESUME_CHECK] = _TAIL_CALL_RESUME_CHECK,
+    [RESUME_CHECK_JIT] = _TAIL_CALL_RESUME_CHECK_JIT,
     [RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR,
     [RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE,
     [SEND] = _TAIL_CALL_SEND,
@@ -1007,7 +1009,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
     [125] = _TAIL_CALL_UNKNOWN_OPCODE,
     [126] = _TAIL_CALL_UNKNOWN_OPCODE,
     [127] = _TAIL_CALL_UNKNOWN_OPCODE,
-    [213] = _TAIL_CALL_UNKNOWN_OPCODE,
     [214] = _TAIL_CALL_UNKNOWN_OPCODE,
     [215] = _TAIL_CALL_UNKNOWN_OPCODE,
     [216] = _TAIL_CALL_UNKNOWN_OPCODE,
@@ -1217,6 +1218,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
     [RESERVED] = _TAIL_CALL_TRACE_RECORD,
     [RESUME] = _TAIL_CALL_TRACE_RECORD,
     [RESUME_CHECK] = _TAIL_CALL_TRACE_RECORD,
+    [RESUME_CHECK_JIT] = _TAIL_CALL_TRACE_RECORD,
     [RETURN_GENERATOR] = _TAIL_CALL_TRACE_RECORD,
     [RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD,
     [SEND] = _TAIL_CALL_TRACE_RECORD,
@@ -1265,7 +1267,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
     [125] = _TAIL_CALL_UNKNOWN_OPCODE,
     [126] = _TAIL_CALL_UNKNOWN_OPCODE,
     [127] = _TAIL_CALL_UNKNOWN_OPCODE,
-    [213] = _TAIL_CALL_UNKNOWN_OPCODE,
     [214] = _TAIL_CALL_UNKNOWN_OPCODE,
     [215] = _TAIL_CALL_UNKNOWN_OPCODE,
     [216] = _TAIL_CALL_UNKNOWN_OPCODE,
index d26516f7c2ff66932edf85ef6c274109ea5b4fdd..fbf0985e9050dd1b3adac4895ce55c65a3ccb74b 100644 (file)
@@ -931,8 +931,9 @@ PyUnstable_Code_New(int argcount, int kwonlyargcount,
 // NOTE: When modifying the construction of PyCode_NewEmpty, please also change
 // test.test_code.CodeLocationTest.test_code_new_empty to keep it in sync!
 
-static const uint8_t assert0[6] = {
+static const uint8_t assert0[8] = {
     RESUME, RESUME_AT_FUNC_START,
+    CACHE, 0,
     LOAD_COMMON_CONSTANT, CONSTANT_ASSERTIONERROR,
     RAISE_VARARGS, 1
 };
@@ -940,7 +941,7 @@ static const uint8_t assert0[6] = {
 static const uint8_t linetable[2] = {
     (1 << 7)  // New entry.
     | (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3)
-    | (3 - 1),  // Three code units.
+    | (4 - 1),  // Four code units.
     0,  // Offset from co_firstlineno.
 };
 
@@ -966,7 +967,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
     if (filename_ob == NULL) {
         goto failed;
     }
-    code_ob = PyBytes_FromStringAndSize((const char *)assert0, 6);
+    code_ob = PyBytes_FromStringAndSize((const char *)assert0, 8);
     if (code_ob == NULL) {
         goto failed;
     }
index 5088500fc4142b8a3b170f5049f59ab8e64054fa..9dece8a7700cab0a86da27b55a9bf7a3fa7e8468 100644 (file)
@@ -454,6 +454,7 @@ is_resume(_Py_CODEUNIT *instr)
     return (
         code == RESUME ||
         code == RESUME_CHECK ||
+        code == RESUME_CHECK_JIT ||
         code == INSTRUMENTED_RESUME
     );
 }
index f808544045e1539d9f060c547487f5857d9b9755..1411eb1718b683be3dd09296dacf21920efeca3b 100644 (file)
@@ -1,39 +1,39 @@
 // Auto-generated by Programs/freeze_test_frozenmain.py
 unsigned char M_test_frozenmain[] = {
     227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,
-    0,0,0,0,0,243,184,0,0,0,128,0,94,0,82,1,
-    73,0,116,0,94,0,82,1,73,4,116,1,93,2,33,0,
-    82,2,52,1,0,0,0,0,0,0,31,0,93,2,33,0,
-    82,3,93,0,80,6,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,52,2,0,0,0,0,0,0,
-    31,0,93,1,80,8,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,33,0,52,0,0,0,0,0,
-    0,0,82,4,44,26,0,0,0,0,0,0,0,0,0,0,
-    116,5,82,7,16,0,70,24,0,0,116,6,93,2,33,0,
-    82,5,93,6,12,0,82,6,93,5,93,6,44,26,0,0,
-    0,0,0,0,0,0,0,0,12,0,50,4,52,1,0,0,
-    0,0,0,0,31,0,75,26,0,0,9,0,30,0,82,1,
-    35,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122,
-    101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8,
-    115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103,
-    122,7,99,111,110,102,105,103,32,122,2,58,32,41,5,218,
-    12,112,114,111,103,114,97,109,95,110,97,109,101,218,10,101,
-    120,101,99,117,116,97,98,108,101,218,15,117,115,101,95,101,
-    110,118,105,114,111,110,109,101,110,116,218,17,99,111,110,102,
-    105,103,117,114,101,95,99,95,115,116,100,105,111,218,14,98,
-    117,102,102,101,114,101,100,95,115,116,100,105,111,41,7,218,
-    3,115,121,115,218,17,95,116,101,115,116,105,110,116,101,114,
-    110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4,
-    97,114,103,118,218,11,103,101,116,95,99,111,110,102,105,103,
-    115,114,3,0,0,0,218,3,107,101,121,169,0,243,0,0,
-    0,0,218,18,116,101,115,116,95,102,114,111,122,101,110,109,
-    97,105,110,46,112,121,218,8,60,109,111,100,117,108,101,62,
-    114,18,0,0,0,1,0,0,0,115,94,0,0,0,240,3,
-    1,1,1,243,8,0,1,11,219,0,24,225,0,5,208,6,
-    26,212,0,27,217,0,5,128,106,144,35,151,40,145,40,212,
-    0,27,216,9,26,215,9,38,210,9,38,211,9,40,168,24,
-    213,9,50,128,6,243,2,6,12,2,128,67,241,14,0,5,
-    10,136,71,144,67,144,53,152,2,152,54,160,35,157,59,152,
-    45,208,10,40,214,4,41,243,15,6,12,2,114,16,0,0,
-    0,
+    0,0,0,0,0,243,186,0,0,0,128,0,0,0,94,0,
+    82,1,73,0,116,0,94,0,82,1,73,4,116,1,93,2,
+    33,0,82,2,52,1,0,0,0,0,0,0,31,0,93,2,
+    33,0,82,3,93,0,80,6,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,52,2,0,0,0,0,
+    0,0,31,0,93,1,80,8,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,33,0,52,0,0,0,
+    0,0,0,0,82,4,44,26,0,0,0,0,0,0,0,0,
+    0,0,116,5,82,7,16,0,70,24,0,0,116,6,93,2,
+    33,0,82,5,93,6,12,0,82,6,93,5,93,6,44,26,
+    0,0,0,0,0,0,0,0,0,0,12,0,50,4,52,1,
+    0,0,0,0,0,0,31,0,75,26,0,0,9,0,30,0,
+    82,1,35,0,41,8,233,0,0,0,0,78,122,18,70,114,
+    111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,100,
+    122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,102,
+    105,103,122,7,99,111,110,102,105,103,32,122,2,58,32,41,
+    5,218,12,112,114,111,103,114,97,109,95,110,97,109,101,218,
+    10,101,120,101,99,117,116,97,98,108,101,218,15,117,115,101,
+    95,101,110,118,105,114,111,110,109,101,110,116,218,17,99,111,
+    110,102,105,103,117,114,101,95,99,95,115,116,100,105,111,218,
+    14,98,117,102,102,101,114,101,100,95,115,116,100,105,111,41,
+    7,218,3,115,121,115,218,17,95,116,101,115,116,105,110,116,
+    101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,116,
+    218,4,97,114,103,118,218,11,103,101,116,95,99,111,110,102,
+    105,103,115,114,3,0,0,0,218,3,107,101,121,169,0,243,
+    0,0,0,0,218,18,116,101,115,116,95,102,114,111,122,101,
+    110,109,97,105,110,46,112,121,218,8,60,109,111,100,117,108,
+    101,62,114,18,0,0,0,1,0,0,0,115,94,0,0,0,
+    241,3,1,1,1,243,8,0,1,11,219,0,24,225,0,5,
+    208,6,26,212,0,27,217,0,5,128,106,144,35,151,40,145,
+    40,212,0,27,216,9,26,215,9,38,210,9,38,211,9,40,
+    168,24,213,9,50,128,6,243,2,6,12,2,128,67,241,14,
+    0,5,10,136,71,144,67,144,53,152,2,152,54,160,35,157,
+    59,152,45,208,10,40,214,4,41,243,15,6,12,2,114,16,
+    0,0,0,
 };
index 8cc2d50a3227f8a027ca75f0bc1edf5b8ff4e600..7c08488092de63920671c02bad96a6a39f7cc271 100644 (file)
@@ -669,7 +669,7 @@ error:
 
 
 // The offset (in code units) of the END_SEND from the SEND in the `yield from` sequence.
-#define END_SEND_OFFSET 5
+#define END_SEND_OFFSET 6
 
 static int
 resolve_jump_offsets(instr_sequence *instrs)
index c26ba89b5ab9c80699f2b51f79b6232ceb13b400..eaa123f88507a75e230b7bc4f7870188ea587800 100644 (file)
@@ -148,8 +148,9 @@ dummy_func(
         pure inst(NOP, (--)) {
         }
 
-        family(RESUME, 0) = {
+        family(RESUME, 1) = {
             RESUME_CHECK,
+            RESUME_CHECK_JIT,
         };
 
         macro(NOT_TAKEN) = NOP;
@@ -171,12 +172,8 @@ dummy_func(
             }
         }
 
-        op(_QUICKEN_RESUME, (--)) {
-            #if ENABLE_SPECIALIZATION
-            if (tstate->tracing == 0 && this_instr->op.code == RESUME) {
-                FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK);
-            }
-            #endif  /* ENABLE_SPECIALIZATION */
+        tier1 op(_QUICKEN_RESUME, (counter/1 --)) {
+            _Py_Specialize_Resume(this_instr, tstate, frame);
         }
 
         tier1 op(_MAYBE_INSTRUMENT, (--)) {
@@ -226,7 +223,11 @@ dummy_func(
             _QUICKEN_RESUME +
             _CHECK_PERIODIC_IF_NOT_YIELD_FROM;
 
-        inst(RESUME_CHECK, (--)) {
+        macro(RESUME_CHECK) =
+            unused/1 +
+            _RESUME_CHECK;
+
+        op(_RESUME_CHECK, (--)) {
 #if defined(__EMSCRIPTEN__)
             DEOPT_IF(_Py_emscripten_signal_clock == 0);
             _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING;
@@ -241,6 +242,11 @@ dummy_func(
             #endif
         }
 
+        macro(RESUME_CHECK_JIT) =
+            unused/1 +
+            _RESUME_CHECK +
+            _JIT;
+
         op(_MONITOR_RESUME, (--)) {
             int err = _Py_call_instrumentation(
                     tstate, oparg == 0 ? PY_MONITORING_EVENT_PY_START : PY_MONITORING_EVENT_PY_RESUME, frame, this_instr);
@@ -252,6 +258,7 @@ dummy_func(
         }
 
         macro(INSTRUMENTED_RESUME) =
+            unused/1 +
             _LOAD_BYTECODE +
             _MAYBE_INSTRUMENT +
             _CHECK_PERIODIC_IF_NOT_YIELD_FROM +
@@ -3114,9 +3121,11 @@ dummy_func(
 
         tier1 op(_JIT, (--)) {
         #ifdef _Py_TIER2
+            bool is_resume = this_instr->op.code == RESUME_CHECK_JIT;
             _Py_BackoffCounter counter = this_instr[1].counter;
-            if (!IS_JIT_TRACING() && backoff_counter_triggers(counter) &&
-                this_instr->op.code == JUMP_BACKWARD_JIT &&
+            if ((backoff_counter_triggers(counter) &&
+                !IS_JIT_TRACING() &&
+                (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) &&
                 next_instr->op.code != ENTER_EXECUTOR) {
                 /* Back up over EXTENDED_ARGs so executor is inserted at the correct place */
                 _Py_CODEUNIT *insert_exec_at = this_instr;
@@ -3124,7 +3133,8 @@ dummy_func(
                     oparg >>= 8;
                     insert_exec_at--;
                 }
-                int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, stack_pointer, 0, NULL, oparg, NULL);
+                int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,
+                    is_resume ? insert_exec_at : next_instr, stack_pointer, 0, NULL, oparg, NULL);
                 if (succ) {
                     ENTER_TRACING();
                 }
@@ -3175,12 +3185,22 @@ dummy_func(
 
         tier1 inst(ENTER_EXECUTOR, (--)) {
             #ifdef _Py_TIER2
+            PyCodeObject *code = _PyFrame_GetCode(frame);
+            _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             if (IS_JIT_TRACING()) {
+                int og_opcode = executor->vm_data.opcode;
+                int og_oparg = (oparg & ~255) | executor->vm_data.oparg;
                 next_instr = this_instr;
+                if (_PyJit_EnterExecutorShouldStopTracing(og_opcode)) {
+                    if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) {
+                        PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter);
+                    }
+                    opcode = og_opcode;
+                    oparg = og_oparg;
+                    DISPATCH_GOTO_NON_TRACING();
+                }
                 goto stop_tracing;
             }
-            PyCodeObject *code = _PyFrame_GetCode(frame);
-            _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             assert(executor->vm_data.index == INSTR_OFFSET() - 1);
             assert(executor->vm_data.code == code);
             assert(executor->vm_data.valid);
index 950050a602711646c0f63d2d3a15393561fb580f..da41851e7448a6af0751e189b649e950b5d0059f 100644 (file)
@@ -1095,7 +1095,8 @@ static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = {
     { .op.code = INTERPRETER_EXIT, .op.arg = 0 },  /* reached on return */
     { .op.code = NOP, .op.arg = 0 },
     { .op.code = INTERPRETER_EXIT, .op.arg = 0 },  /* reached on yield */
-    { .op.code = RESUME, .op.arg = RESUME_OPARG_DEPTH1_MASK | RESUME_AT_FUNC_START }
+    { .op.code = RESUME, .op.arg = RESUME_OPARG_DEPTH1_MASK | RESUME_AT_FUNC_START },
+    { .op.code = CACHE, .op.arg = 0 } /* RESUME's CACHE */
 };
 
 const _Py_CODEUNIT *_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR = (_Py_CODEUNIT*)&_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS;
@@ -1371,7 +1372,7 @@ tier2_dispatch:
     for (;;) {
         uopcode = next_uop->opcode;
 #ifdef Py_DEBUG
-        if (frame->lltrace >= 3) {
+        if (frame->lltrace >= 4) {
             dump_stack(frame, stack_pointer);
             printf("    cache=[");
             dump_cache_item(_tos_cache0, 0, current_cached_values);
index f00913cd359c1ede331b3c939d2b16ac2a484cf2..e57bdd686dc338eec614e03991816e01cd735fb5 100644 (file)
@@ -93,8 +93,6 @@
             break;
         }
 
-        /* _QUICKEN_RESUME is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
-
         /* _LOAD_BYTECODE is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
 
         case _RESUME_CHECK_r00: {
index 30f0101d2ed0e349dbf410f26b83f1fcd95fc5ec..a66d6ccff2d82db372eb39fcad363230a06b7802 100644 (file)
             INSTRUCTION_STATS(ENTER_EXECUTOR);
             opcode = ENTER_EXECUTOR;
             #ifdef _Py_TIER2
+            PyCodeObject *code = _PyFrame_GetCode(frame);
+            _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             if (IS_JIT_TRACING()) {
+                int og_opcode = executor->vm_data.opcode;
+                int og_oparg = (oparg & ~255) | executor->vm_data.oparg;
                 next_instr = this_instr;
+                if (_PyJit_EnterExecutorShouldStopTracing(og_opcode)) {
+                    if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) {
+                        PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter);
+                    }
+                    opcode = og_opcode;
+                    oparg = og_oparg;
+                    DISPATCH_GOTO_NON_TRACING();
+                }
                 JUMP_TO_LABEL(stop_tracing);
             }
-            PyCodeObject *code = _PyFrame_GetCode(frame);
-            _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             assert(executor->vm_data.index == INSTR_OFFSET() - 1);
             assert(executor->vm_data.code == code);
             assert(executor->vm_data.valid);
             _Py_CODEUNIT* const this_instr = next_instr;
             (void)this_instr;
             frame->instr_ptr = next_instr;
-            next_instr += 1;
+            next_instr += 2;
             INSTRUCTION_STATS(INSTRUMENTED_RESUME);
+            /* Skip 1 cache entry */
             // _LOAD_BYTECODE
             {
                 #ifdef Py_GIL_DISABLED
             // _JIT
             {
                 #ifdef _Py_TIER2
+                bool is_resume = this_instr->op.code == RESUME_CHECK_JIT;
                 _Py_BackoffCounter counter = this_instr[1].counter;
-                if (!IS_JIT_TRACING() && backoff_counter_triggers(counter) &&
-                    this_instr->op.code == JUMP_BACKWARD_JIT &&
+                if ((backoff_counter_triggers(counter) &&
+                        !IS_JIT_TRACING() &&
+                        (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) &&
                     next_instr->op.code != ENTER_EXECUTOR) {
                     _Py_CODEUNIT *insert_exec_at = this_instr;
                     while (oparg > 255) {
                         oparg >>= 8;
                         insert_exec_at--;
                     }
-                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, stack_pointer, 0, NULL, oparg, NULL);
+                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,
+                        is_resume ? insert_exec_at : next_instr, stack_pointer, 0, NULL, oparg, NULL);
                     if (succ) {
                         ENTER_TRACING();
                     }
             (void)(opcode);
             #endif
             frame->instr_ptr = next_instr;
-            next_instr += 1;
+            next_instr += 2;
             INSTRUCTION_STATS(RESUME);
             PREDICTED_RESUME:;
-            _Py_CODEUNIT* const this_instr = next_instr - 1;
+            _Py_CODEUNIT* const this_instr = next_instr - 2;
             (void)this_instr;
             // _LOAD_BYTECODE
             {
             }
             // _QUICKEN_RESUME
             {
-                #if ENABLE_SPECIALIZATION
-                if (tstate->tracing == 0 && this_instr->op.code == RESUME) {
-                    FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK);
-                }
-                #endif  /* ENABLE_SPECIALIZATION */
+                uint16_t counter = read_u16(&this_instr[1].cache);
+                (void)counter;
+                _PyFrame_SetStackPointer(frame, stack_pointer);
+                _Py_Specialize_Resume(this_instr, tstate, frame);
+                stack_pointer = _PyFrame_GetStackPointer(frame);
             }
             // _CHECK_PERIODIC_IF_NOT_YIELD_FROM
             {
             _Py_CODEUNIT* const this_instr = next_instr;
             (void)this_instr;
             frame->instr_ptr = next_instr;
-            next_instr += 1;
+            next_instr += 2;
             INSTRUCTION_STATS(RESUME_CHECK);
-            static_assert(0 == 0, "incorrect cache size");
+            static_assert(1 == 1, "incorrect cache size");
+            /* Skip 1 cache entry */
             #if defined(__EMSCRIPTEN__)
             if (_Py_emscripten_signal_clock == 0) {
                 UPDATE_MISS_STATS(RESUME);
             DISPATCH();
         }
 
+        TARGET(RESUME_CHECK_JIT) {
+            #if _Py_TAIL_CALL_INTERP
+            int opcode = RESUME_CHECK_JIT;
+            (void)(opcode);
+            #endif
+            _Py_CODEUNIT* const this_instr = next_instr;
+            (void)this_instr;
+            frame->instr_ptr = next_instr;
+            next_instr += 2;
+            INSTRUCTION_STATS(RESUME_CHECK_JIT);
+            static_assert(1 == 1, "incorrect cache size");
+            /* Skip 1 cache entry */
+            // _RESUME_CHECK
+            {
+                #if defined(__EMSCRIPTEN__)
+                if (_Py_emscripten_signal_clock == 0) {
+                    UPDATE_MISS_STATS(RESUME);
+                    assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                    JUMP_TO_PREDICTED(RESUME);
+                }
+                _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING;
+                #endif
+                uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
+                uintptr_t version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
+                assert((version & _PY_EVAL_EVENTS_MASK) == 0);
+                if (eval_breaker != version) {
+                    UPDATE_MISS_STATS(RESUME);
+                    assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                    JUMP_TO_PREDICTED(RESUME);
+                }
+                #ifdef Py_GIL_DISABLED
+                if (frame->tlbc_index !=
+                    ((_PyThreadStateImpl *)tstate)->tlbc_index) {
+                    UPDATE_MISS_STATS(RESUME);
+                    assert(_PyOpcode_Deopt[opcode] == (RESUME));
+                    JUMP_TO_PREDICTED(RESUME);
+                }
+                #endif
+            }
+            // _JIT
+            {
+                #ifdef _Py_TIER2
+                bool is_resume = this_instr->op.code == RESUME_CHECK_JIT;
+                _Py_BackoffCounter counter = this_instr[1].counter;
+                if ((backoff_counter_triggers(counter) &&
+                        !IS_JIT_TRACING() &&
+                        (this_instr->op.code == JUMP_BACKWARD_JIT || is_resume)) &&
+                    next_instr->op.code != ENTER_EXECUTOR) {
+                    _Py_CODEUNIT *insert_exec_at = this_instr;
+                    while (oparg > 255) {
+                        oparg >>= 8;
+                        insert_exec_at--;
+                    }
+                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,
+                        is_resume ? insert_exec_at : next_instr, stack_pointer, 0, NULL, oparg, NULL);
+                    if (succ) {
+                        ENTER_TRACING();
+                    }
+                    else {
+                        this_instr[1].counter = restart_backoff_counter(counter);
+                    }
+                }
+                else {
+                    ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
+                }
+                #endif
+            }
+            DISPATCH();
+        }
+
         TARGET(RETURN_GENERATOR) {
             #if _Py_TAIL_CALL_INTERP
             int opcode = RETURN_GENERATOR;
index b074d23277878bf1d68ade9d2ff36b54f4a6d9f8..1aed6769d217fe2dd856ede2f0f23b8390ebf358 100644 (file)
@@ -576,6 +576,7 @@ sanity_check_instrumentation(PyCodeObject *code)
             CHECK(opcode != END_FOR);
             CHECK(opcode != RESUME);
             CHECK(opcode != RESUME_CHECK);
+            CHECK(opcode != RESUME_CHECK_JIT);
             CHECK(opcode != INSTRUMENTED_RESUME);
             if (!is_instrumented(opcode)) {
                 CHECK(_PyOpcode_Deopt[opcode] == opcode);
index f57c33feec2ac291e1646433a21065f83e5e8429..def462bacec176d2cb02ab16e559a77e74ac753d 100644 (file)
@@ -198,6 +198,7 @@ static void *opcode_targets_table[256] = {
     &&TARGET_LOAD_SUPER_ATTR_ATTR,
     &&TARGET_LOAD_SUPER_ATTR_METHOD,
     &&TARGET_RESUME_CHECK,
+    &&TARGET_RESUME_CHECK_JIT,
     &&TARGET_SEND_GEN,
     &&TARGET_STORE_ATTR_INSTANCE_VALUE,
     &&TARGET_STORE_ATTR_SLOT,
@@ -232,7 +233,6 @@ static void *opcode_targets_table[256] = {
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
-    &&_unknown_opcode,
     &&TARGET_INSTRUMENTED_END_FOR,
     &&TARGET_INSTRUMENTED_POP_ITER,
     &&TARGET_INSTRUMENTED_END_SEND,
@@ -472,7 +472,7 @@ static void *opcode_tracing_targets_table[256] = {
     &&TARGET_TRACE_RECORD,
     &&TARGET_TRACE_RECORD,
     &&TARGET_TRACE_RECORD,
-    &&_unknown_opcode,
+    &&TARGET_TRACE_RECORD,
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
@@ -718,6 +718,7 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RERAISE(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESERVED(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK(TAIL_CALL_PARAMS);
+static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK_JIT(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS);
 static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND(TAIL_CALL_PARAMS);
@@ -959,6 +960,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
     [RESERVED] = _TAIL_CALL_RESERVED,
     [RESUME] = _TAIL_CALL_RESUME,
     [RESUME_CHECK] = _TAIL_CALL_RESUME_CHECK,
+    [RESUME_CHECK_JIT] = _TAIL_CALL_RESUME_CHECK_JIT,
     [RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR,
     [RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE,
     [SEND] = _TAIL_CALL_SEND,
@@ -1007,7 +1009,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
     [125] = _TAIL_CALL_UNKNOWN_OPCODE,
     [126] = _TAIL_CALL_UNKNOWN_OPCODE,
     [127] = _TAIL_CALL_UNKNOWN_OPCODE,
-    [213] = _TAIL_CALL_UNKNOWN_OPCODE,
     [214] = _TAIL_CALL_UNKNOWN_OPCODE,
     [215] = _TAIL_CALL_UNKNOWN_OPCODE,
     [216] = _TAIL_CALL_UNKNOWN_OPCODE,
@@ -1217,6 +1218,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
     [RESERVED] = _TAIL_CALL_TRACE_RECORD,
     [RESUME] = _TAIL_CALL_TRACE_RECORD,
     [RESUME_CHECK] = _TAIL_CALL_TRACE_RECORD,
+    [RESUME_CHECK_JIT] = _TAIL_CALL_TRACE_RECORD,
     [RETURN_GENERATOR] = _TAIL_CALL_TRACE_RECORD,
     [RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD,
     [SEND] = _TAIL_CALL_TRACE_RECORD,
@@ -1265,7 +1267,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
     [125] = _TAIL_CALL_UNKNOWN_OPCODE,
     [126] = _TAIL_CALL_UNKNOWN_OPCODE,
     [127] = _TAIL_CALL_UNKNOWN_OPCODE,
-    [213] = _TAIL_CALL_UNKNOWN_OPCODE,
     [214] = _TAIL_CALL_UNKNOWN_OPCODE,
     [215] = _TAIL_CALL_UNKNOWN_OPCODE,
     [216] = _TAIL_CALL_UNKNOWN_OPCODE,
index a9e788d0dcb1d5fe139ac6b1866d326646730f3e..f350b82397f5756e990199e52990368c98e483ce 100644 (file)
@@ -632,6 +632,12 @@ _PyJit_translate_single_bytecode_to_trace(
         target--;
     }
 
+    if (opcode == ENTER_EXECUTOR) {
+        _PyExecutorObject *executor = old_code->co_executors->executors[oparg & 255];
+        opcode = executor->vm_data.opcode;
+        oparg = (oparg & ~255) | executor->vm_data.oparg;
+    }
+
     if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]] > 0) {
         uint16_t backoff = (this_instr + 1)->counter.value_and_backoff;
         // adaptive_counter_cooldown is a fresh specialization.
@@ -823,6 +829,7 @@ _PyJit_translate_single_bytecode_to_trace(
 
         case RESUME:
         case RESUME_CHECK:
+        case RESUME_CHECK_JIT:
             /* Use a special tier 2 version of RESUME_CHECK to allow traces to
              *  start with RESUME_CHECK */
             ADD_TO_TRACE(_TIER2_RESUME_CHECK, 0, 0, target);
@@ -1038,12 +1045,9 @@ _PyJit_TryInitializeTracing(
         _Py_RecordFuncPtr record_func = _PyOpcode_RecordFunctions[record_func_index];
         record_func(frame, stack_pointer, oparg, &tracer->prev_state.recorded_value);
     }
-    assert(curr_instr->op.code == JUMP_BACKWARD_JIT || (exit != NULL));
+    assert(curr_instr->op.code == JUMP_BACKWARD_JIT || curr_instr->op.code == RESUME_CHECK_JIT || (exit != NULL));
     tracer->initial_state.jump_backward_instr = curr_instr;
 
-    if (_PyOpcode_Caches[_PyOpcode_Deopt[close_loop_instr->op.code]]) {
-        close_loop_instr[1].counter = trigger_backoff_counter();
-    }
     tracer->is_tracing = true;
     return 1;
 }
@@ -1063,7 +1067,12 @@ _PyJit_FinalizeTracing(PyThreadState *tstate, int err)
             tracer->initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter);
         }
         else {
-            tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&tstate->interp->opt_config);
+            if (tracer->initial_state.jump_backward_instr[0].op.code == JUMP_BACKWARD_JIT) {
+                tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&tstate->interp->opt_config);
+            }
+            else {
+                tracer->initial_state.jump_backward_instr[1].counter = initial_resume_backoff_counter(&tstate->interp->opt_config);
+            }
         }
     }
     else if (tracer->initial_state.executor->vm_data.valid) {
@@ -1092,6 +1101,19 @@ _PyJit_FinalizeTracing(PyThreadState *tstate, int err)
     tracer->is_tracing = false;
 }
 
+bool
+_PyJit_EnterExecutorShouldStopTracing(int og_opcode)
+{
+    // Continue tracing (skip over the executor). If it's a RESUME
+    // trace to form longer, more optimizeable traces.
+    // We want to trace over RESUME traces. Otherwise, functions with lots of RESUME
+    // end up with many fragmented traces which perform badly.
+    // See for example, the richards benchmark in pyperformance.
+    // For consideration: We may want to consider tracing over side traces
+    // inserted into bytecode as well in the future.
+    return og_opcode == RESUME_CHECK_JIT;
+}
+
 void
 _PyJit_TracerFree(_PyThreadStateImpl *_tstate)
 {
@@ -1780,7 +1802,7 @@ _Py_ExecutorDetach(_PyExecutorObject *executor)
     assert(instruction->op.code == ENTER_EXECUTOR);
     int index = instruction->op.arg;
     assert(code->co_executors->executors[index] == executor);
-    instruction->op.code = executor->vm_data.opcode;
+    instruction->op.code = _PyOpcode_Deopt[executor->vm_data.opcode];
     instruction->op.arg = executor->vm_data.oparg;
     executor->vm_data.code = NULL;
     code->co_executors->executors[index] = NULL;
index 942a730e4faccfc656080d1b8b3101aaa2155608..52a0c08ac677b71633bd74d18b7db608ae4aa926 100644 (file)
@@ -17,8 +17,6 @@
             break;
         }
 
-        /* _QUICKEN_RESUME is not a viable micro-op for tier 2 */
-
         /* _LOAD_BYTECODE is not a viable micro-op for tier 2 */
 
         case _RESUME_CHECK: {
index fcb73b4dcefe1d0f58b31df50a55269f3ff10582..143175da0f45c775fbf7927ec34196a5d843f543 100644 (file)
@@ -607,11 +607,13 @@ init_interpreter(PyInterpreterState *interp,
     // Initialize optimization configuration from environment variables
     // PYTHON_JIT_STRESS sets aggressive defaults for testing, but can be overridden
     uint16_t jump_default = JUMP_BACKWARD_INITIAL_VALUE;
+    uint16_t resume_default = RESUME_INITIAL_VALUE;
     uint16_t side_exit_default = SIDE_EXIT_INITIAL_VALUE;
 
     if (is_env_enabled("PYTHON_JIT_STRESS")) {
         jump_default = 63;
         side_exit_default = 63;
+        resume_default = 127;
     }
 
     init_policy(&interp->opt_config.jump_backward_initial_value,
@@ -620,6 +622,12 @@ init_interpreter(PyInterpreterState *interp,
     init_policy(&interp->opt_config.jump_backward_initial_backoff,
                 "PYTHON_JIT_JUMP_BACKWARD_INITIAL_BACKOFF",
                 JUMP_BACKWARD_INITIAL_BACKOFF, 0, MAX_BACKOFF);
+    init_policy(&interp->opt_config.resume_initial_value,
+                "PYTHON_JIT_RESUME_INITIAL_VALUE",
+                resume_default, 1, MAX_VALUE);
+    init_policy(&interp->opt_config.resume_initial_backoff,
+                "PYTHON_JIT_RESUME_INITIAL_BACKOFF",
+                RESUME_INITIAL_BACKOFF, 0, MAX_BACKOFF);
     init_policy(&interp->opt_config.side_exit_initial_value,
                 "PYTHON_JIT_SIDE_EXIT_INITIAL_VALUE",
                 side_exit_default, 1, MAX_VALUE);
index 1eabdb1b5b194e8008b78200ebc3eafcf9e1dfe2..4ef8b27795650ca3a78f3d5499e7b2fde852675a 100644 (file)
@@ -46,16 +46,18 @@ void
 _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters)
 {
     #if ENABLE_SPECIALIZATION
-    _Py_BackoffCounter jump_counter, adaptive_counter;
+    _Py_BackoffCounter jump_counter, adaptive_counter, resume_counter;
     if (enable_counters) {
         PyThreadState *tstate = _PyThreadState_GET();
         PyInterpreterState *interp = tstate->interp;
         jump_counter = initial_jump_backoff_counter(&interp->opt_config);
         adaptive_counter = adaptive_counter_warmup();
+        resume_counter = initial_resume_backoff_counter(&interp->opt_config);
     }
     else {
         jump_counter = initial_unreachable_backoff_counter();
         adaptive_counter = initial_unreachable_backoff_counter();
+        resume_counter = initial_unreachable_backoff_counter();
     }
     int opcode = 0;
     int oparg = 0;
@@ -70,6 +72,9 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters
                 case JUMP_BACKWARD:
                     instructions[i + 1].counter = jump_counter;
                     break;
+                case RESUME:
+                    instructions[i + 1].counter = resume_counter;
+                    break;
                 case POP_JUMP_IF_FALSE:
                 case POP_JUMP_IF_TRUE:
                 case POP_JUMP_IF_NONE:
@@ -2781,6 +2786,28 @@ _Py_Specialize_ContainsOp(_PyStackRef value_st, _Py_CODEUNIT *instr)
     return;
 }
 
+
+void
+_Py_Specialize_Resume(_Py_CODEUNIT *instr, PyThreadState *tstate, _PyInterpreterFrame *frame)
+{
+    if (tstate->tracing == 0 && instr->op.code == RESUME) {
+        if (tstate->interp->jit) {
+            PyCodeObject *co = (PyCodeObject *)PyStackRef_AsPyObjectBorrow(frame->f_executable);
+            if (co != NULL &&
+                PyCode_Check(co) &&
+                (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) == 0) {
+                specialize(instr, RESUME_CHECK_JIT);
+                set_counter((_Py_BackoffCounter *)instr + 1, initial_resume_backoff_counter(&tstate->interp->opt_config));
+                return;
+            }
+        }
+        specialize(instr, RESUME_CHECK);
+        return;
+    }
+    unspecialize(instr);
+    return;
+}
+
 #ifdef Py_STATS
 void
 _Py_GatherStats_GetIter(_PyStackRef iterable)
@@ -2883,5 +2910,6 @@ const struct _PyCode8 _Py_InitCleanup = {
         EXIT_INIT_CHECK, 0,
         RETURN_VALUE, 0,
         RESUME, RESUME_AT_FUNC_START,
+        CACHE, 0, /* RESUME's cache */
     }
 };