From 4e34e27ae4d152ba24623cfa4923d492e8f27aea Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 30 Apr 2025 12:37:13 +0100 Subject: [PATCH 01/15] Specialize GET_ITER --- Include/internal/pycore_code.h | 1 + Include/internal/pycore_magic_number.h | 6 +- Include/internal/pycore_opcode_metadata.h | 23 +- Include/internal/pycore_uop_ids.h | 318 +++++++++++----------- Include/internal/pycore_uop_metadata.h | 8 + Include/opcode_ids.h | 72 ++--- Lib/_opcode_metadata.py | 76 +++--- Lib/opcode.py | 3 + Lib/test/test_dis.py | 248 ++++++++--------- Lib/test/test_monitoring.py | 10 +- Programs/test_frozenmain.h | 56 ++-- Python/bytecodes.c | 36 ++- Python/executor_cases.c.h | 34 +++ Python/generated_cases.c.h | 131 +++++++-- Python/opcode_targets.h | 10 +- Python/optimizer_cases.c.h | 18 ++ Python/specialize.c | 19 ++ 17 files changed, 647 insertions(+), 422 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 8e1415f27b63f3..c1368d07b09257 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -313,6 +313,7 @@ extern void _Py_Specialize_CompareOp(_PyStackRef lhs, _PyStackRef rhs, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_UnpackSequence(_PyStackRef seq, _Py_CODEUNIT *instr, int oparg); +extern void _Py_Specialize_GetIter(_PyStackRef iter, _Py_CODEUNIT *instr); extern void _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_Send(_PyStackRef receiver, _Py_CODEUNIT *instr); extern void _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr); diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index cd1fc873623ed1..475fbe08c9fc10 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -279,7 +279,9 @@ Known values: Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST) Python 3.15a0 3650 (Initial version) Python 3.15a1 3651 (Simplify LOAD_CONST) - Python 3.15a1 3652 (Virtual iterators) + + Python 3.14a7 3652 (Virtual iterators) + Python 3.14a7 3653 (Specialize GET_ITER) Python 3.16 will start with 3700 @@ -293,7 +295,7 @@ PC/launcher.c must also be updated. */ -#define PYC_MAGIC_NUMBER 3652 +#define PYC_MAGIC_NUMBER 3653 /* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes (little-endian) and then appending b'\r\n'. */ #define PYC_MAGIC_NUMBER_TOKEN \ diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 00e918cb8f0cd1..9641d571a13e33 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -222,6 +222,10 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 1; case GET_ITER: return 1; + case GET_ITER_LIST_OR_TUPLE: + return 1; + case GET_ITER_SELF: + return 1; case GET_LEN: return 1; case GET_YIELD_FROM_ITER: @@ -705,6 +709,10 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case GET_ITER: return 2; + case GET_ITER_LIST_OR_TUPLE: + return 2; + case GET_ITER_SELF: + return 2; case GET_LEN: return 2; case GET_YIELD_FROM_ITER: @@ -1161,7 +1169,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [GET_AITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_ANEXT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [GET_ITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [GET_ITER] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [GET_ITER_LIST_OR_TUPLE] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, + [GET_ITER_SELF] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, [GET_LEN] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1403,6 +1413,8 @@ _PyOpcode_macro_expansion[256] = { [GET_ANEXT] = { .nuops = 1, .uops = { { _GET_ANEXT, OPARG_SIMPLE, 0 } } }, [GET_AWAITABLE] = { .nuops = 1, .uops = { { _GET_AWAITABLE, OPARG_SIMPLE, 0 } } }, [GET_ITER] = { .nuops = 1, .uops = { { _GET_ITER, OPARG_SIMPLE, 0 } } }, + [GET_ITER_LIST_OR_TUPLE] = { .nuops = 1, .uops = { { _GET_ITER_LIST_OR_TUPLE, OPARG_SIMPLE, 1 } } }, + [GET_ITER_SELF] = { .nuops = 1, .uops = { { _GET_ITER_SELF, OPARG_SIMPLE, 1 } } }, [GET_LEN] = { .nuops = 1, .uops = { { _GET_LEN, OPARG_SIMPLE, 0 } } }, [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { _GET_YIELD_FROM_ITER, OPARG_SIMPLE, 0 } } }, [IMPORT_FROM] = { .nuops = 1, .uops = { { _IMPORT_FROM, OPARG_SIMPLE, 0 } } }, @@ -1600,6 +1612,8 @@ const char *_PyOpcode_OpName[267] = { [GET_ANEXT] = "GET_ANEXT", [GET_AWAITABLE] = "GET_AWAITABLE", [GET_ITER] = "GET_ITER", + [GET_ITER_LIST_OR_TUPLE] = "GET_ITER_LIST_OR_TUPLE", + [GET_ITER_SELF] = "GET_ITER_SELF", [GET_LEN] = "GET_LEN", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [IMPORT_FROM] = "IMPORT_FROM", @@ -1764,6 +1778,7 @@ const uint8_t _PyOpcode_Caches[256] = { [POP_JUMP_IF_FALSE] = 1, [POP_JUMP_IF_NONE] = 1, [POP_JUMP_IF_NOT_NONE] = 1, + [GET_ITER] = 1, [FOR_ITER] = 1, [CALL] = 3, [CALL_KW] = 3, @@ -1781,8 +1796,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [125] = 125, [126] = 126, [127] = 127, - [210] = 210, - [211] = 211, [212] = 212, [213] = 213, [214] = 214, @@ -1897,6 +1910,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [GET_ANEXT] = GET_ANEXT, [GET_AWAITABLE] = GET_AWAITABLE, [GET_ITER] = GET_ITER, + [GET_ITER_LIST_OR_TUPLE] = GET_ITER, + [GET_ITER_SELF] = GET_ITER, [GET_LEN] = GET_LEN, [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER, [IMPORT_FROM] = IMPORT_FROM, @@ -2042,8 +2057,6 @@ const uint8_t _PyOpcode_Deopt[256] = { case 125: \ case 126: \ case 127: \ - case 210: \ - case 211: \ case 212: \ case 213: \ case 214: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 2b845527cf2ed5..2ac575c5e8cc7d 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -116,56 +116,58 @@ extern "C" { #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE -#define _GET_ITER GET_ITER +#define _GET_ITER 376 +#define _GET_ITER_LIST_OR_TUPLE GET_ITER_LIST_OR_TUPLE +#define _GET_ITER_SELF GET_ITER_SELF #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BINARY_OP_EXTEND 376 -#define _GUARD_CALLABLE_ISINSTANCE 377 -#define _GUARD_CALLABLE_LEN 378 -#define _GUARD_CALLABLE_LIST_APPEND 379 -#define _GUARD_CALLABLE_STR_1 380 -#define _GUARD_CALLABLE_TUPLE_1 381 -#define _GUARD_CALLABLE_TYPE_1 382 -#define _GUARD_DORV_NO_DICT 383 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 384 -#define _GUARD_GLOBALS_VERSION 385 -#define _GUARD_IS_FALSE_POP 386 -#define _GUARD_IS_NONE_POP 387 -#define _GUARD_IS_NOT_NONE_POP 388 -#define _GUARD_IS_TRUE_POP 389 -#define _GUARD_KEYS_VERSION 390 -#define _GUARD_NOS_DICT 391 -#define _GUARD_NOS_FLOAT 392 -#define _GUARD_NOS_INT 393 -#define _GUARD_NOS_LIST 394 -#define _GUARD_NOS_NOT_NULL 395 -#define _GUARD_NOS_NULL 396 -#define _GUARD_NOS_TUPLE 397 -#define _GUARD_NOS_UNICODE 398 -#define _GUARD_NOT_EXHAUSTED_LIST 399 -#define _GUARD_NOT_EXHAUSTED_RANGE 400 -#define _GUARD_NOT_EXHAUSTED_TUPLE 401 -#define _GUARD_THIRD_NULL 402 -#define _GUARD_TOS_ANY_SET 403 -#define _GUARD_TOS_DICT 404 -#define _GUARD_TOS_FLOAT 405 -#define _GUARD_TOS_INT 406 -#define _GUARD_TOS_LIST 407 -#define _GUARD_TOS_SLICE 408 -#define _GUARD_TOS_TUPLE 409 -#define _GUARD_TOS_UNICODE 410 -#define _GUARD_TYPE_VERSION 411 -#define _GUARD_TYPE_VERSION_AND_LOCK 412 +#define _GUARD_BINARY_OP_EXTEND 377 +#define _GUARD_CALLABLE_ISINSTANCE 378 +#define _GUARD_CALLABLE_LEN 379 +#define _GUARD_CALLABLE_LIST_APPEND 380 +#define _GUARD_CALLABLE_STR_1 381 +#define _GUARD_CALLABLE_TUPLE_1 382 +#define _GUARD_CALLABLE_TYPE_1 383 +#define _GUARD_DORV_NO_DICT 384 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 385 +#define _GUARD_GLOBALS_VERSION 386 +#define _GUARD_IS_FALSE_POP 387 +#define _GUARD_IS_NONE_POP 388 +#define _GUARD_IS_NOT_NONE_POP 389 +#define _GUARD_IS_TRUE_POP 390 +#define _GUARD_KEYS_VERSION 391 +#define _GUARD_NOS_DICT 392 +#define _GUARD_NOS_FLOAT 393 +#define _GUARD_NOS_INT 394 +#define _GUARD_NOS_LIST 395 +#define _GUARD_NOS_NOT_NULL 396 +#define _GUARD_NOS_NULL 397 +#define _GUARD_NOS_TUPLE 398 +#define _GUARD_NOS_UNICODE 399 +#define _GUARD_NOT_EXHAUSTED_LIST 400 +#define _GUARD_NOT_EXHAUSTED_RANGE 401 +#define _GUARD_NOT_EXHAUSTED_TUPLE 402 +#define _GUARD_THIRD_NULL 403 +#define _GUARD_TOS_ANY_SET 404 +#define _GUARD_TOS_DICT 405 +#define _GUARD_TOS_FLOAT 406 +#define _GUARD_TOS_INT 407 +#define _GUARD_TOS_LIST 408 +#define _GUARD_TOS_SLICE 409 +#define _GUARD_TOS_TUPLE 410 +#define _GUARD_TOS_UNICODE 411 +#define _GUARD_TYPE_VERSION 412 +#define _GUARD_TYPE_VERSION_AND_LOCK 413 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 413 -#define _INIT_CALL_PY_EXACT_ARGS 414 -#define _INIT_CALL_PY_EXACT_ARGS_0 415 -#define _INIT_CALL_PY_EXACT_ARGS_1 416 -#define _INIT_CALL_PY_EXACT_ARGS_2 417 -#define _INIT_CALL_PY_EXACT_ARGS_3 418 -#define _INIT_CALL_PY_EXACT_ARGS_4 419 -#define _INSERT_NULL 420 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 414 +#define _INIT_CALL_PY_EXACT_ARGS 415 +#define _INIT_CALL_PY_EXACT_ARGS_0 416 +#define _INIT_CALL_PY_EXACT_ARGS_1 417 +#define _INIT_CALL_PY_EXACT_ARGS_2 418 +#define _INIT_CALL_PY_EXACT_ARGS_3 419 +#define _INIT_CALL_PY_EXACT_ARGS_4 420 +#define _INSERT_NULL 421 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -175,171 +177,171 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 421 +#define _IS_NONE 422 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 422 -#define _ITER_CHECK_RANGE 423 -#define _ITER_CHECK_TUPLE 424 -#define _ITER_JUMP_LIST 425 -#define _ITER_JUMP_RANGE 426 -#define _ITER_JUMP_TUPLE 427 -#define _ITER_NEXT_LIST 428 -#define _ITER_NEXT_LIST_TIER_TWO 429 -#define _ITER_NEXT_RANGE 430 -#define _ITER_NEXT_TUPLE 431 -#define _JUMP_TO_TOP 432 +#define _ITER_CHECK_LIST 423 +#define _ITER_CHECK_RANGE 424 +#define _ITER_CHECK_TUPLE 425 +#define _ITER_JUMP_LIST 426 +#define _ITER_JUMP_RANGE 427 +#define _ITER_JUMP_TUPLE 428 +#define _ITER_NEXT_LIST 429 +#define _ITER_NEXT_LIST_TIER_TWO 430 +#define _ITER_NEXT_RANGE 431 +#define _ITER_NEXT_TUPLE 432 +#define _JUMP_TO_TOP 433 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 433 -#define _LOAD_ATTR_CLASS 434 +#define _LOAD_ATTR 434 +#define _LOAD_ATTR_CLASS 435 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 435 -#define _LOAD_ATTR_METHOD_LAZY_DICT 436 -#define _LOAD_ATTR_METHOD_NO_DICT 437 -#define _LOAD_ATTR_METHOD_WITH_VALUES 438 -#define _LOAD_ATTR_MODULE 439 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 440 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 441 -#define _LOAD_ATTR_PROPERTY_FRAME 442 -#define _LOAD_ATTR_SLOT 443 -#define _LOAD_ATTR_WITH_HINT 444 +#define _LOAD_ATTR_INSTANCE_VALUE 436 +#define _LOAD_ATTR_METHOD_LAZY_DICT 437 +#define _LOAD_ATTR_METHOD_NO_DICT 438 +#define _LOAD_ATTR_METHOD_WITH_VALUES 439 +#define _LOAD_ATTR_MODULE 440 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 441 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 442 +#define _LOAD_ATTR_PROPERTY_FRAME 443 +#define _LOAD_ATTR_SLOT 444 +#define _LOAD_ATTR_WITH_HINT 445 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 445 +#define _LOAD_BYTECODE 446 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 446 -#define _LOAD_CONST_INLINE_BORROW 447 -#define _LOAD_CONST_UNDER_INLINE 448 -#define _LOAD_CONST_UNDER_INLINE_BORROW 449 +#define _LOAD_CONST_INLINE 447 +#define _LOAD_CONST_INLINE_BORROW 448 +#define _LOAD_CONST_UNDER_INLINE 449 +#define _LOAD_CONST_UNDER_INLINE_BORROW 450 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 450 -#define _LOAD_FAST_0 451 -#define _LOAD_FAST_1 452 -#define _LOAD_FAST_2 453 -#define _LOAD_FAST_3 454 -#define _LOAD_FAST_4 455 -#define _LOAD_FAST_5 456 -#define _LOAD_FAST_6 457 -#define _LOAD_FAST_7 458 +#define _LOAD_FAST 451 +#define _LOAD_FAST_0 452 +#define _LOAD_FAST_1 453 +#define _LOAD_FAST_2 454 +#define _LOAD_FAST_3 455 +#define _LOAD_FAST_4 456 +#define _LOAD_FAST_5 457 +#define _LOAD_FAST_6 458 +#define _LOAD_FAST_7 459 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 459 -#define _LOAD_FAST_BORROW_0 460 -#define _LOAD_FAST_BORROW_1 461 -#define _LOAD_FAST_BORROW_2 462 -#define _LOAD_FAST_BORROW_3 463 -#define _LOAD_FAST_BORROW_4 464 -#define _LOAD_FAST_BORROW_5 465 -#define _LOAD_FAST_BORROW_6 466 -#define _LOAD_FAST_BORROW_7 467 +#define _LOAD_FAST_BORROW 460 +#define _LOAD_FAST_BORROW_0 461 +#define _LOAD_FAST_BORROW_1 462 +#define _LOAD_FAST_BORROW_2 463 +#define _LOAD_FAST_BORROW_3 464 +#define _LOAD_FAST_BORROW_4 465 +#define _LOAD_FAST_BORROW_5 466 +#define _LOAD_FAST_BORROW_6 467 +#define _LOAD_FAST_BORROW_7 468 #define _LOAD_FAST_BORROW_LOAD_FAST_BORROW LOAD_FAST_BORROW_LOAD_FAST_BORROW #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 468 -#define _LOAD_GLOBAL_BUILTINS 469 -#define _LOAD_GLOBAL_MODULE 470 +#define _LOAD_GLOBAL 469 +#define _LOAD_GLOBAL_BUILTINS 470 +#define _LOAD_GLOBAL_MODULE 471 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 471 -#define _LOAD_SMALL_INT_0 472 -#define _LOAD_SMALL_INT_1 473 -#define _LOAD_SMALL_INT_2 474 -#define _LOAD_SMALL_INT_3 475 -#define _LOAD_SPECIAL 476 +#define _LOAD_SMALL_INT 472 +#define _LOAD_SMALL_INT_0 473 +#define _LOAD_SMALL_INT_1 474 +#define _LOAD_SMALL_INT_2 475 +#define _LOAD_SMALL_INT_3 476 +#define _LOAD_SPECIAL 477 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 477 +#define _MAKE_CALLARGS_A_TUPLE 478 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 478 +#define _MAKE_WARM 479 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 479 -#define _MAYBE_EXPAND_METHOD_KW 480 -#define _MONITOR_CALL 481 -#define _MONITOR_CALL_KW 482 -#define _MONITOR_JUMP_BACKWARD 483 -#define _MONITOR_RESUME 484 +#define _MAYBE_EXPAND_METHOD 480 +#define _MAYBE_EXPAND_METHOD_KW 481 +#define _MONITOR_CALL 482 +#define _MONITOR_CALL_KW 483 +#define _MONITOR_JUMP_BACKWARD 484 +#define _MONITOR_RESUME 485 #define _NOP NOP -#define _POP_CALL 485 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW 486 -#define _POP_CALL_ONE 487 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 488 -#define _POP_CALL_TWO 489 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 490 +#define _POP_CALL 486 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW 487 +#define _POP_CALL_ONE 488 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 489 +#define _POP_CALL_TWO 490 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 491 #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 491 -#define _POP_JUMP_IF_TRUE 492 +#define _POP_JUMP_IF_FALSE 492 +#define _POP_JUMP_IF_TRUE 493 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE 493 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 494 -#define _POP_TWO 495 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 496 +#define _POP_TOP_LOAD_CONST_INLINE 494 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 495 +#define _POP_TWO 496 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 497 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 497 +#define _PUSH_FRAME 498 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 498 -#define _PY_FRAME_GENERAL 499 -#define _PY_FRAME_KW 500 -#define _QUICKEN_RESUME 501 -#define _REPLACE_WITH_TRUE 502 +#define _PUSH_NULL_CONDITIONAL 499 +#define _PY_FRAME_GENERAL 500 +#define _PY_FRAME_KW 501 +#define _QUICKEN_RESUME 502 +#define _REPLACE_WITH_TRUE 503 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 503 -#define _SEND 504 -#define _SEND_GEN_FRAME 505 +#define _SAVE_RETURN_OFFSET 504 +#define _SEND 505 +#define _SEND_GEN_FRAME 506 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 506 -#define _STORE_ATTR 507 -#define _STORE_ATTR_INSTANCE_VALUE 508 -#define _STORE_ATTR_SLOT 509 -#define _STORE_ATTR_WITH_HINT 510 +#define _START_EXECUTOR 507 +#define _STORE_ATTR 508 +#define _STORE_ATTR_INSTANCE_VALUE 509 +#define _STORE_ATTR_SLOT 510 +#define _STORE_ATTR_WITH_HINT 511 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 511 -#define _STORE_FAST_0 512 -#define _STORE_FAST_1 513 -#define _STORE_FAST_2 514 -#define _STORE_FAST_3 515 -#define _STORE_FAST_4 516 -#define _STORE_FAST_5 517 -#define _STORE_FAST_6 518 -#define _STORE_FAST_7 519 +#define _STORE_FAST 512 +#define _STORE_FAST_0 513 +#define _STORE_FAST_1 514 +#define _STORE_FAST_2 515 +#define _STORE_FAST_3 516 +#define _STORE_FAST_4 517 +#define _STORE_FAST_5 518 +#define _STORE_FAST_6 519 +#define _STORE_FAST_7 520 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 520 -#define _STORE_SUBSCR 521 -#define _STORE_SUBSCR_DICT 522 -#define _STORE_SUBSCR_LIST_INT 523 +#define _STORE_SLICE 521 +#define _STORE_SUBSCR 522 +#define _STORE_SUBSCR_DICT 523 +#define _STORE_SUBSCR_LIST_INT 524 #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 524 -#define _TO_BOOL 525 +#define _TIER2_RESUME_CHECK 525 +#define _TO_BOOL 526 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST 526 +#define _TO_BOOL_LIST 527 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 527 +#define _TO_BOOL_STR 528 #define _UNARY_INVERT UNARY_INVERT #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 528 -#define _UNPACK_SEQUENCE_LIST 529 -#define _UNPACK_SEQUENCE_TUPLE 530 -#define _UNPACK_SEQUENCE_TWO_TUPLE 531 +#define _UNPACK_SEQUENCE 529 +#define _UNPACK_SEQUENCE_LIST 530 +#define _UNPACK_SEQUENCE_TUPLE 531 +#define _UNPACK_SEQUENCE_TWO_TUPLE 532 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 531 +#define MAX_UOP_ID 532 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index b08909e72c4f43..462f2fdb5de19f 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -202,6 +202,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_MATCH_SEQUENCE] = 0, [_MATCH_KEYS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GET_ITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_GET_ITER_SELF] = HAS_DEOPT_FLAG, + [_GET_ITER_LIST_OR_TUPLE] = HAS_DEOPT_FLAG, [_GET_YIELD_FROM_ITER] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_FOR_ITER_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_ITER_CHECK_LIST] = HAS_EXIT_FLAG, @@ -435,6 +437,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GET_ANEXT] = "_GET_ANEXT", [_GET_AWAITABLE] = "_GET_AWAITABLE", [_GET_ITER] = "_GET_ITER", + [_GET_ITER_LIST_OR_TUPLE] = "_GET_ITER_LIST_OR_TUPLE", + [_GET_ITER_SELF] = "_GET_ITER_SELF", [_GET_LEN] = "_GET_LEN", [_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER", [_GUARD_BINARY_OP_EXTEND] = "_GUARD_BINARY_OP_EXTEND", @@ -1004,6 +1008,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _GET_ITER: return 1; + case _GET_ITER_SELF: + return 0; + case _GET_ITER_LIST_OR_TUPLE: + return 0; case _GET_YIELD_FROM_ITER: return 1; case _FOR_ITER_TIER_TWO: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 1d5c74adefcd35..ee01006bba3052 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -178,41 +178,43 @@ extern "C" { #define FOR_ITER_LIST 172 #define FOR_ITER_RANGE 173 #define FOR_ITER_TUPLE 174 -#define JUMP_BACKWARD_JIT 175 -#define JUMP_BACKWARD_NO_JIT 176 -#define LOAD_ATTR_CLASS 177 -#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 178 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 179 -#define LOAD_ATTR_INSTANCE_VALUE 180 -#define LOAD_ATTR_METHOD_LAZY_DICT 181 -#define LOAD_ATTR_METHOD_NO_DICT 182 -#define LOAD_ATTR_METHOD_WITH_VALUES 183 -#define LOAD_ATTR_MODULE 184 -#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 185 -#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 186 -#define LOAD_ATTR_PROPERTY 187 -#define LOAD_ATTR_SLOT 188 -#define LOAD_ATTR_WITH_HINT 189 -#define LOAD_GLOBAL_BUILTIN 190 -#define LOAD_GLOBAL_MODULE 191 -#define LOAD_SUPER_ATTR_ATTR 192 -#define LOAD_SUPER_ATTR_METHOD 193 -#define RESUME_CHECK 194 -#define SEND_GEN 195 -#define STORE_ATTR_INSTANCE_VALUE 196 -#define STORE_ATTR_SLOT 197 -#define STORE_ATTR_WITH_HINT 198 -#define STORE_SUBSCR_DICT 199 -#define STORE_SUBSCR_LIST_INT 200 -#define TO_BOOL_ALWAYS_TRUE 201 -#define TO_BOOL_BOOL 202 -#define TO_BOOL_INT 203 -#define TO_BOOL_LIST 204 -#define TO_BOOL_NONE 205 -#define TO_BOOL_STR 206 -#define UNPACK_SEQUENCE_LIST 207 -#define UNPACK_SEQUENCE_TUPLE 208 -#define UNPACK_SEQUENCE_TWO_TUPLE 209 +#define GET_ITER_LIST_OR_TUPLE 175 +#define GET_ITER_SELF 176 +#define JUMP_BACKWARD_JIT 177 +#define JUMP_BACKWARD_NO_JIT 178 +#define LOAD_ATTR_CLASS 179 +#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 180 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 181 +#define LOAD_ATTR_INSTANCE_VALUE 182 +#define LOAD_ATTR_METHOD_LAZY_DICT 183 +#define LOAD_ATTR_METHOD_NO_DICT 184 +#define LOAD_ATTR_METHOD_WITH_VALUES 185 +#define LOAD_ATTR_MODULE 186 +#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 187 +#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 188 +#define LOAD_ATTR_PROPERTY 189 +#define LOAD_ATTR_SLOT 190 +#define LOAD_ATTR_WITH_HINT 191 +#define LOAD_GLOBAL_BUILTIN 192 +#define LOAD_GLOBAL_MODULE 193 +#define LOAD_SUPER_ATTR_ATTR 194 +#define LOAD_SUPER_ATTR_METHOD 195 +#define RESUME_CHECK 196 +#define SEND_GEN 197 +#define STORE_ATTR_INSTANCE_VALUE 198 +#define STORE_ATTR_SLOT 199 +#define STORE_ATTR_WITH_HINT 200 +#define STORE_SUBSCR_DICT 201 +#define STORE_SUBSCR_LIST_INT 202 +#define TO_BOOL_ALWAYS_TRUE 203 +#define TO_BOOL_BOOL 204 +#define TO_BOOL_INT 205 +#define TO_BOOL_LIST 206 +#define TO_BOOL_NONE 207 +#define TO_BOOL_STR 208 +#define UNPACK_SEQUENCE_LIST 209 +#define UNPACK_SEQUENCE_TUPLE 210 +#define UNPACK_SEQUENCE_TWO_TUPLE 211 #define INSTRUMENTED_END_FOR 234 #define INSTRUMENTED_POP_ITER 235 #define INSTRUMENTED_END_SEND 236 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index f168d169a32948..e70350590f3529 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -84,6 +84,10 @@ "JUMP_BACKWARD_NO_JIT", "JUMP_BACKWARD_JIT", ], + "GET_ITER": [ + "GET_ITER_LIST_OR_TUPLE", + "GET_ITER_SELF", + ], "FOR_ITER": [ "FOR_ITER_LIST", "FOR_ITER_TUPLE", @@ -167,41 +171,43 @@ 'FOR_ITER_LIST': 172, 'FOR_ITER_RANGE': 173, 'FOR_ITER_TUPLE': 174, - 'JUMP_BACKWARD_JIT': 175, - 'JUMP_BACKWARD_NO_JIT': 176, - 'LOAD_ATTR_CLASS': 177, - 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 178, - 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 179, - 'LOAD_ATTR_INSTANCE_VALUE': 180, - 'LOAD_ATTR_METHOD_LAZY_DICT': 181, - 'LOAD_ATTR_METHOD_NO_DICT': 182, - 'LOAD_ATTR_METHOD_WITH_VALUES': 183, - 'LOAD_ATTR_MODULE': 184, - 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 185, - 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 186, - 'LOAD_ATTR_PROPERTY': 187, - 'LOAD_ATTR_SLOT': 188, - 'LOAD_ATTR_WITH_HINT': 189, - 'LOAD_GLOBAL_BUILTIN': 190, - 'LOAD_GLOBAL_MODULE': 191, - 'LOAD_SUPER_ATTR_ATTR': 192, - 'LOAD_SUPER_ATTR_METHOD': 193, - 'RESUME_CHECK': 194, - 'SEND_GEN': 195, - 'STORE_ATTR_INSTANCE_VALUE': 196, - 'STORE_ATTR_SLOT': 197, - 'STORE_ATTR_WITH_HINT': 198, - 'STORE_SUBSCR_DICT': 199, - 'STORE_SUBSCR_LIST_INT': 200, - 'TO_BOOL_ALWAYS_TRUE': 201, - 'TO_BOOL_BOOL': 202, - 'TO_BOOL_INT': 203, - 'TO_BOOL_LIST': 204, - 'TO_BOOL_NONE': 205, - 'TO_BOOL_STR': 206, - 'UNPACK_SEQUENCE_LIST': 207, - 'UNPACK_SEQUENCE_TUPLE': 208, - 'UNPACK_SEQUENCE_TWO_TUPLE': 209, + 'GET_ITER_LIST_OR_TUPLE': 175, + 'GET_ITER_SELF': 176, + 'JUMP_BACKWARD_JIT': 177, + 'JUMP_BACKWARD_NO_JIT': 178, + 'LOAD_ATTR_CLASS': 179, + 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 180, + 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 181, + 'LOAD_ATTR_INSTANCE_VALUE': 182, + 'LOAD_ATTR_METHOD_LAZY_DICT': 183, + 'LOAD_ATTR_METHOD_NO_DICT': 184, + 'LOAD_ATTR_METHOD_WITH_VALUES': 185, + 'LOAD_ATTR_MODULE': 186, + 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 187, + 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 188, + 'LOAD_ATTR_PROPERTY': 189, + 'LOAD_ATTR_SLOT': 190, + 'LOAD_ATTR_WITH_HINT': 191, + 'LOAD_GLOBAL_BUILTIN': 192, + 'LOAD_GLOBAL_MODULE': 193, + 'LOAD_SUPER_ATTR_ATTR': 194, + 'LOAD_SUPER_ATTR_METHOD': 195, + 'RESUME_CHECK': 196, + 'SEND_GEN': 197, + 'STORE_ATTR_INSTANCE_VALUE': 198, + 'STORE_ATTR_SLOT': 199, + 'STORE_ATTR_WITH_HINT': 200, + 'STORE_SUBSCR_DICT': 201, + 'STORE_SUBSCR_LIST_INT': 202, + 'TO_BOOL_ALWAYS_TRUE': 203, + 'TO_BOOL_BOOL': 204, + 'TO_BOOL_INT': 205, + 'TO_BOOL_LIST': 206, + 'TO_BOOL_NONE': 207, + 'TO_BOOL_STR': 208, + 'UNPACK_SEQUENCE_LIST': 209, + 'UNPACK_SEQUENCE_TUPLE': 210, + 'UNPACK_SEQUENCE_TWO_TUPLE': 211, } opmap = { diff --git a/Lib/opcode.py b/Lib/opcode.py index 0e9520b6832499..ecce6d1ac2702a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -68,6 +68,9 @@ "FOR_ITER": { "counter": 1, }, + "GET_ITER": { + "counter": 1, + }, "LOAD_SUPER_ATTR": { "counter": 1, }, diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index ec930a728aa5b3..24a72d506a7945 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -906,7 +906,7 @@ def loop_test(): LIST_EXTEND 1 LOAD_SMALL_INT 3 BINARY_OP 5 (*) - GET_ITER + GET_ITER_LIST_OR_TUPLE L1: FOR_ITER_LIST 14 (to L2) STORE_FAST 0 (i) @@ -1404,7 +1404,7 @@ def test_show_caches(self): 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) @@ -1820,131 +1820,131 @@ def _prepare_test_cases(): 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='GET_ITER', arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, cache_info=[('counter', 1, b'\x00\x00')]), + 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 diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index a932ac80117d27..35d3fe46a1b8bd 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1589,11 +1589,11 @@ def whilefunc(n=0): ('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): diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index dbeedb7ffe0ce6..f962a56cd47c09 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,7 +1,7 @@ // 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, + 0,0,0,0,0,243,186,0,0,0,128,0,94,0,82,1, 73,0,116,0,94,0,82,1,73,1,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, @@ -9,31 +9,31 @@ unsigned char M_test_frozenmain[] = { 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, + 116,5,82,7,16,0,0,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,244,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, }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f02e32fd1d312a..4966008a137312 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3048,7 +3048,25 @@ dummy_func( values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o); } - inst(GET_ITER, (iterable -- iter, index_or_null)) { + + family(GET_ITER, 1) = { + GET_ITER_LIST_OR_TUPLE, + GET_ITER_SELF, + }; + + specializing op(_SPECIALIZE_GET_ITER, (counter/1, iter -- iter)) { + #if ENABLE_SPECIALIZATION_FT + if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { + next_instr = this_instr; + _Py_Specialize_GetIter(iter, next_instr); + DISPATCH_SAME_OPARG(); + } + OPCODE_DEFERRED_INC(FOR_ITER); + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); + #endif /* ENABLE_SPECIALIZATION_FT */ + } + + op(_GET_ITER, (iterable -- iter, index_or_null)) { #ifdef Py_STATS _Py_GatherStats_GetIter(iterable); #endif @@ -3068,6 +3086,22 @@ dummy_func( } } + macro(GET_ITER) = _SPECIALIZE_GET_ITER + _GET_ITER; + + inst(GET_ITER_SELF, (unused/1, iter -- iter, null)) { + PyTypeObject *tp = PyStackRef_TYPE(iter); + DEOPT_IF(tp->tp_iter != PyObject_SelfIter); + null = PyStackRef_NULL; + } + + inst(GET_ITER_LIST_OR_TUPLE, (unused/1, iter -- iter, index0)) { + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp != &PyList_Type) { + DEOPT_IF(tp != &PyTuple_Type); + } + index0 = PyStackRef_TagInt(0); + } + inst(GET_YIELD_FROM_ITER, (iterable -- iter)) { /* before: [obj]; after [getiter(obj)] */ PyObject *iterable_o = PyStackRef_AsPyObjectBorrow(iterable); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 35b29940cb4a15..6784233b404049 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4222,6 +4222,40 @@ break; } + case _GET_ITER_SELF: { + _PyStackRef iter; + _PyStackRef null; + iter = stack_pointer[-1]; + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp->tp_iter != PyObject_SelfIter) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + null = PyStackRef_NULL; + stack_pointer[0] = null; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _GET_ITER_LIST_OR_TUPLE: { + _PyStackRef iter; + _PyStackRef index0; + iter = stack_pointer[-1]; + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp != &PyList_Type) { + if (tp != &PyTuple_Type) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + } + index0 = PyStackRef_TagInt(0); + stack_pointer[0] = index0; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + case _GET_YIELD_FROM_ITER: { _PyStackRef iterable; _PyStackRef iter; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e3cd3b71a1de08..6a89819a7c80e0 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -6193,38 +6193,61 @@ (void)(opcode); #endif frame->instr_ptr = next_instr; - next_instr += 1; + next_instr += 2; INSTRUCTION_STATS(GET_ITER); - _PyStackRef iterable; + PREDICTED_GET_ITER:; + _Py_CODEUNIT* const this_instr = next_instr - 2; + (void)this_instr; _PyStackRef iter; + _PyStackRef iterable; _PyStackRef index_or_null; - iterable = stack_pointer[-1]; - #ifdef Py_STATS - _PyFrame_SetStackPointer(frame, stack_pointer); - _Py_GatherStats_GetIter(iterable); - stack_pointer = _PyFrame_GetStackPointer(frame); - #endif - - PyTypeObject *tp = PyStackRef_TYPE(iterable); - if (tp == &PyTuple_Type || tp == &PyList_Type) { - iter = iterable; - index_or_null = PyStackRef_TagInt(0); + // _SPECIALIZE_GET_ITER + { + iter = stack_pointer[-1]; + uint16_t counter = read_u16(&this_instr[1].cache); + (void)counter; + #if ENABLE_SPECIALIZATION_FT + if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { + next_instr = this_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_Specialize_GetIter(iter, next_instr); + stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH_SAME_OPARG(); + } + OPCODE_DEFERRED_INC(FOR_ITER); + ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); + #endif /* ENABLE_SPECIALIZATION_FT */ } - else { - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); + // _GET_ITER + { + iterable = iter; + #ifdef Py_STATS _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(iterable); + _Py_GatherStats_GetIter(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); - if (iter_o == NULL) { - JUMP_TO_LABEL(error); + #endif + + PyTypeObject *tp = PyStackRef_TYPE(iterable); + if (tp == &PyTuple_Type || tp == &PyList_Type) { + iter = iterable; + index_or_null = PyStackRef_TagInt(0); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (iter_o == NULL) { + JUMP_TO_LABEL(error); + } + iter = PyStackRef_FromPyObjectSteal(iter_o); + index_or_null = PyStackRef_NULL; + stack_pointer += 1; } - iter = PyStackRef_FromPyObjectSteal(iter_o); - index_or_null = PyStackRef_NULL; - stack_pointer += 1; } stack_pointer[-1] = iter; stack_pointer[0] = index_or_null; @@ -6233,6 +6256,64 @@ DISPATCH(); } + TARGET(GET_ITER_LIST_OR_TUPLE) { + #if Py_TAIL_CALL_INTERP + int opcode = GET_ITER_LIST_OR_TUPLE; + (void)(opcode); + #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(GET_ITER_LIST_OR_TUPLE); + static_assert(1 == 1, "incorrect cache size"); + _PyStackRef iter; + _PyStackRef index0; + /* Skip 1 cache entry */ + iter = stack_pointer[-1]; + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp != &PyList_Type) { + if (tp != &PyTuple_Type) { + UPDATE_MISS_STATS(GET_ITER); + assert(_PyOpcode_Deopt[opcode] == (GET_ITER)); + JUMP_TO_PREDICTED(GET_ITER); + } + } + index0 = PyStackRef_TagInt(0); + stack_pointer[0] = index0; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + + TARGET(GET_ITER_SELF) { + #if Py_TAIL_CALL_INTERP + int opcode = GET_ITER_SELF; + (void)(opcode); + #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(GET_ITER_SELF); + static_assert(1 == 1, "incorrect cache size"); + _PyStackRef iter; + _PyStackRef null; + /* Skip 1 cache entry */ + iter = stack_pointer[-1]; + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp->tp_iter != PyObject_SelfIter) { + UPDATE_MISS_STATS(GET_ITER); + assert(_PyOpcode_Deopt[opcode] == (GET_ITER)); + JUMP_TO_PREDICTED(GET_ITER); + } + null = PyStackRef_NULL; + stack_pointer[0] = null; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); + } + TARGET(GET_LEN) { #if Py_TAIL_CALL_INTERP int opcode = GET_LEN; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 1d6dcddab4b12d..141546219158b3 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -175,6 +175,8 @@ static void *opcode_targets[256] = { &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_TUPLE, + &&TARGET_GET_ITER_LIST_OR_TUPLE, + &&TARGET_GET_ITER_SELF, &&TARGET_JUMP_BACKWARD_JIT, &&TARGET_JUMP_BACKWARD_NO_JIT, &&TARGET_LOAD_ATTR_CLASS, @@ -232,8 +234,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_END_SEND, @@ -359,6 +359,8 @@ Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AITER(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS); +Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER_LIST_OR_TUPLE(TAIL_CALL_PARAMS); +Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER_SELF(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_IMPORT_FROM(TAIL_CALL_PARAMS); @@ -596,6 +598,8 @@ static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { [GET_ANEXT] = _TAIL_CALL_GET_ANEXT, [GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE, [GET_ITER] = _TAIL_CALL_GET_ITER, + [GET_ITER_LIST_OR_TUPLE] = _TAIL_CALL_GET_ITER_LIST_OR_TUPLE, + [GET_ITER_SELF] = _TAIL_CALL_GET_ITER_SELF, [GET_LEN] = _TAIL_CALL_GET_LEN, [GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER, [IMPORT_FROM] = _TAIL_CALL_IMPORT_FROM, @@ -736,8 +740,6 @@ static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { [125] = _TAIL_CALL_UNKNOWN_OPCODE, [126] = _TAIL_CALL_UNKNOWN_OPCODE, [127] = _TAIL_CALL_UNKNOWN_OPCODE, - [210] = _TAIL_CALL_UNKNOWN_OPCODE, - [211] = _TAIL_CALL_UNKNOWN_OPCODE, [212] = _TAIL_CALL_UNKNOWN_OPCODE, [213] = _TAIL_CALL_UNKNOWN_OPCODE, [214] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index db86edcc7859b5..142284325da788 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1573,6 +1573,24 @@ break; } + case _GET_ITER_SELF: { + JitOptSymbol *null; + null = sym_new_null(ctx); + stack_pointer[0] = null; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + + case _GET_ITER_LIST_OR_TUPLE: { + JitOptSymbol *index0; + index0 = sym_new_not_null(ctx); + stack_pointer[0] = index0; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + case _GET_YIELD_FROM_ITER: { JitOptSymbol *iter; iter = sym_new_not_null(ctx); diff --git a/Python/specialize.c b/Python/specialize.c index 92f79d39d55208..4b04a2c33d943c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -3174,6 +3174,25 @@ _Py_GatherStats_GetIter(_PyStackRef iterable) #endif +Py_NO_INLINE void +_Py_Specialize_GetIter(_PyStackRef iterable, _Py_CODEUNIT *instr) +{ + PyTypeObject *tp = PyStackRef_TYPE(iterable); + if (tp->tp_iter == PyObject_SelfIter) { + specialize(instr, GET_ITER_SELF); + return; + } + if (tp == &PyList_Type || tp == &PyTuple_Type) { + specialize(instr, GET_ITER_LIST_OR_TUPLE); + return; + } +#ifdef Py_STATS + _Py_GatherStats_GetIter(iterable); +#endif + unspecialize(instr); + return; +} + /* Code init cleanup. * CALL_ALLOC_AND_ENTER_INIT will set up * the frame to execute the EXIT_INIT_CHECK From 37757c635ccf225ed9cf4585a0043eeeeb695203 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 30 Apr 2025 12:41:21 +0100 Subject: [PATCH 02/15] Add news --- .../2025-04-30-12-41-14.gh-issue-132554.7yVP6_.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-12-41-14.gh-issue-132554.7yVP6_.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-12-41-14.gh-issue-132554.7yVP6_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-12-41-14.gh-issue-132554.7yVP6_.rst new file mode 100644 index 00000000000000..9f815c42152c9e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-30-12-41-14.gh-issue-132554.7yVP6_.rst @@ -0,0 +1 @@ +Specialize :opcode:`GET_ITER` for lists, tuples and any iterator. From 658a4225669e6fab85ffdecf3b19bfc847914672 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 30 Apr 2025 17:02:28 +0100 Subject: [PATCH 03/15] Specialize FOR_ITER for ranges using tagged ints --- Include/internal/pycore_long.h | 9 ++ Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_range.h | 4 + Include/internal/pycore_stackref.h | 2 + Include/internal/pycore_uop_metadata.h | 2 +- Objects/longobject.c | 17 +++ Objects/rangeobject.c | 20 +++ Python/bytecodes.c | 114 ++++++++++------- Python/executor_cases.c.h | 83 ++++++------- Python/generated_cases.c.h | 143 +++++++++++++--------- Python/specialize.c | 14 +-- Tools/cases_generator/analyzer.py | 4 + 12 files changed, 255 insertions(+), 159 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 3196d1b82084b9..056288ac358e13 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -207,6 +207,15 @@ _PyLong_IsNonNegativeCompact(const PyLongObject* op) { } +/* Return the value of a non-negative compact as a machine int */ +static inline Py_ssize_t +_PyLong_GetNonNegativeCompactValue(const PyLongObject* op) { + assert(PyLong_Check(op)); + assert (_PyLong_IsNonNegativeCompact(op)); + return op->long_value.ob_digit[0]; +} + + static inline int _PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { assert(PyLong_Check(a)); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 9641d571a13e33..0c730d51ee958c 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1164,7 +1164,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG }, [GET_AITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_ANEXT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, diff --git a/Include/internal/pycore_range.h b/Include/internal/pycore_range.h index bf045ec4fd8332..19b13203afca10 100644 --- a/Include/internal/pycore_range.h +++ b/Include/internal/pycore_range.h @@ -15,6 +15,10 @@ typedef struct { long len; } _PyRangeIterObject; +// Does this range have start == 0, step == 1 and step in compact int range? +int _PyRange_IsSimpleCompact(PyObject *range); +Py_ssize_t _PyRange_GetStopIfCompact(PyObject *range); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index f2ecc30b053568..b5670dd9697f07 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -276,6 +276,8 @@ PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref) #define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0) +extern _PyStackRef PyStackRef_BoxInt(_PyStackRef i); + #ifdef Py_GIL_DISABLED #define Py_TAG_DEFERRED Py_TAG_REFCNT diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 462f2fdb5de19f..b24f8d62f9836f 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -214,7 +214,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_ITER_NEXT_TUPLE] = 0, [_ITER_CHECK_RANGE] = HAS_EXIT_FLAG, [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_EXIT_FLAG, - [_ITER_NEXT_RANGE] = HAS_ERROR_FLAG, + [_ITER_NEXT_RANGE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, [_FOR_ITER_GEN_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_INSERT_NULL] = 0, [_LOAD_SPECIAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, diff --git a/Objects/longobject.c b/Objects/longobject.c index 2b533312fee673..6ff1e84aae69b4 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -10,6 +10,7 @@ #include "pycore_long.h" // _Py_SmallInts #include "pycore_object.h" // _PyObject_Init() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS +#include "pycore_stackref.h" #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include "pycore_unicodeobject.h" // _PyUnicode_Equal() @@ -6872,3 +6873,19 @@ PyLongWriter_Finish(PyLongWriter *writer) return (PyObject*)obj; } + +// Tagged int support + +_PyStackRef +PyStackRef_BoxInt(_PyStackRef i) +{ + assert((i.bits & Py_INT_TAG) == Py_INT_TAG); + intptr_t val = (intptr_t)i.bits; + val = Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 2); + PyObject *boxed = PyLong_FromSsize_t(val); + if (boxed == NULL) { + return PyStackRef_NULL; + } + return PyStackRef_FromPyObjectSteal(boxed); +} + diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index f8cdfe68a6435e..e533114a846208 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -156,6 +156,26 @@ range_vectorcall(PyObject *rangetype, PyObject *const *args, return range_from_array((PyTypeObject *)rangetype, args, nargs); } +int +_PyRange_IsSimpleCompact(PyObject *range) { + assert(PyRange_Check(range)); + rangeobject *r = (rangeobject*)range; + if (r->start == _PyLong_GetZero() && r->step == _PyLong_GetOne() && + _PyLong_IsNonNegativeCompact((PyLongObject *)r->stop) + ) { + return 1; + } + return 0; +} + +Py_ssize_t +_PyRange_GetStopIfCompact(PyObject *range) { + assert(PyRange_Check(range)); + rangeobject *r = (rangeobject*)range; + assert(_PyLong_IsNonNegativeCompact((PyLongObject *)r->stop)); + return _PyLong_GetNonNegativeCompactValue((PyLongObject *)r->stop); +} + PyDoc_STRVAR(range_doc, "range(stop) -> range object\n\ range(start, stop[, step]) -> range object\n\ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4966008a137312..7da61931238aff 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3078,11 +3078,20 @@ dummy_func( index_or_null = PyStackRef_TagInt(0); } else { - PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); - PyStackRef_CLOSE(iterable); - ERROR_IF(iter_o == NULL); - iter = PyStackRef_FromPyObjectSteal(iter_o); - index_or_null = PyStackRef_NULL; + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable); + if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) { + Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o); + PyStackRef_CLOSE(iterable); + iter = PyStackRef_TagInt(stop); + index_or_null = PyStackRef_TagInt(0); + } + else { + iter_o = PyObject_GetIter(iter_o); + PyStackRef_CLOSE(iterable); + ERROR_IF(iter_o == NULL); + iter = PyStackRef_FromPyObjectSteal(iter_o); + index_or_null = PyStackRef_NULL; + } } } @@ -3160,16 +3169,32 @@ dummy_func( replaced op(_FOR_ITER, (iter, null_or_index -- iter, null_or_index, next)) { /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (PyStackRef_IsTaggedInt(null_or_index)) { - next = _PyForIter_NextWithIndex(iter_o, null_or_index); - if (PyStackRef_IsNull(next)) { - JUMPBY(oparg + 1); - DISPATCH(); + if (PyStackRef_IsTaggedInt(iter)) { + if (PyStackRef_Is(iter, null_or_index)) { + null_or_index = PyStackRef_TagInt(-1); + JUMPBY(oparg + 1); + DISPATCH(); + + } + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { + ERROR_NO_POP(); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + } + else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + next = _PyForIter_NextWithIndex(iter_o, null_or_index); + if (PyStackRef_IsNull(next)) { + JUMPBY(oparg + 1); + DISPATCH(); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { @@ -3219,10 +3244,25 @@ dummy_func( inst(INSTRUMENTED_FOR_ITER, (unused/1, iter, null_or_index -- iter, null_or_index, next)) { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (PyStackRef_IsTaggedInt(null_or_index)) { - next = _PyForIter_NextWithIndex(iter_o, null_or_index); - if (PyStackRef_IsNull(next)) { - JUMPBY(oparg + 1); - DISPATCH(); + if (PyStackRef_IsTaggedInt(iter)) { + if (PyStackRef_Is(iter, null_or_index)) { + null_or_index = PyStackRef_TagInt(-1); + JUMPBY(oparg + 1); + DISPATCH(); + + } + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { + ERROR_NO_POP(); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + } + else { + next = _PyForIter_NextWithIndex(iter_o, null_or_index); + if (PyStackRef_IsNull(next)) { + JUMPBY(oparg + 1); + DISPATCH(); + } } null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); @@ -3254,10 +3294,10 @@ dummy_func( op(_ITER_CHECK_LIST, (iter, null_or_index -- iter, null_or_index)) { - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - EXIT_IF(Py_TYPE(iter_o) != &PyList_Type); + EXIT_IF(PyStackRef_TYPE(iter) != &PyList_Type); assert(PyStackRef_IsTaggedInt(null_or_index)); #ifdef Py_GIL_DISABLED + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); EXIT_IF(!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)); #endif } @@ -3339,8 +3379,7 @@ dummy_func( _ITER_NEXT_LIST; op(_ITER_CHECK_TUPLE, (iter, null_or_index -- iter, null_or_index)) { - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - EXIT_IF(Py_TYPE(iter_o) != &PyTuple_Type); + EXIT_IF(PyStackRef_TYPE(iter) != &PyTuple_Type); assert(PyStackRef_IsTaggedInt(null_or_index)); } @@ -3380,21 +3419,11 @@ dummy_func( _ITER_NEXT_TUPLE; op(_ITER_CHECK_RANGE, (iter, null_or_index -- iter, null_or_index)) { - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - EXIT_IF(Py_TYPE(r) != &PyRangeIter_Type); -#ifdef Py_GIL_DISABLED - EXIT_IF(!_PyObject_IsUniquelyReferenced((PyObject *)r)); -#endif + EXIT_IF(!PyStackRef_IsTaggedInt(iter)); } replaced op(_ITER_JUMP_RANGE, (iter, null_or_index -- iter, null_or_index)) { - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); -#ifdef Py_GIL_DISABLED - assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); -#endif - STAT_INC(FOR_ITER, hit); - if (r->len <= 0) { + if (PyStackRef_Is(iter, null_or_index)) { // Jump over END_FOR instruction. JUMPBY(oparg + 1); DISPATCH(); @@ -3403,24 +3432,15 @@ dummy_func( // Only used by Tier 2 op(_GUARD_NOT_EXHAUSTED_RANGE, (iter, null_or_index -- iter, null_or_index)) { - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); - EXIT_IF(r->len <= 0); + EXIT_IF(PyStackRef_Is(iter, null_or_index)); } op(_ITER_NEXT_RANGE, (iter, null_or_index -- iter, null_or_index, next)) { - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); -#ifdef Py_GIL_DISABLED - assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); -#endif - assert(r->len > 0); - long value = r->start; - r->start = value + r->step; - r->len--; - PyObject *res = PyLong_FromLong(value); - ERROR_IF(res == NULL); - next = PyStackRef_FromPyObjectSteal(res); + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { + ERROR_NO_POP(); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } macro(FOR_ITER_RANGE) = @@ -3430,8 +3450,8 @@ dummy_func( _ITER_NEXT_RANGE; op(_FOR_ITER_GEN_FRAME, (iter, null -- iter, null, gen_frame: _PyInterpreterFrame*)) { + DEOPT_IF(PyStackRef_TYPE(iter) != &PyGen_Type); PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); - DEOPT_IF(Py_TYPE(gen) != &PyGen_Type); #ifdef Py_GIL_DISABLED // Since generators can't be used by multiple threads anyway we // don't need to deopt here, but this lets us work on making diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 6784233b404049..5708cd4a6c04cd 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4200,19 +4200,32 @@ index_or_null = PyStackRef_TagInt(0); } else { - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(iterable); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (iter_o == NULL) { - JUMP_TO_ERROR(); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable); + if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) { + Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + iter = PyStackRef_TagInt(stop); + index_or_null = PyStackRef_TagInt(0); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + iter_o = PyObject_GetIter(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (iter_o == NULL) { + JUMP_TO_ERROR(); + } + iter = PyStackRef_FromPyObjectSteal(iter_o); + index_or_null = PyStackRef_NULL; } - iter = PyStackRef_FromPyObjectSteal(iter_o); - index_or_null = PyStackRef_NULL; stack_pointer += 1; } stack_pointer[-1] = iter; @@ -4342,13 +4355,13 @@ _PyStackRef iter; null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(iter_o) != &PyList_Type) { + if (PyStackRef_TYPE(iter) != &PyList_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } assert(PyStackRef_IsTaggedInt(null_or_index)); #ifdef Py_GIL_DISABLED + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -4413,8 +4426,7 @@ _PyStackRef iter; null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(iter_o) != &PyTuple_Type) { + if (PyStackRef_TYPE(iter) != &PyTuple_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } @@ -4460,28 +4472,21 @@ case _ITER_CHECK_RANGE: { _PyStackRef iter; iter = stack_pointer[-2]; - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(r) != &PyRangeIter_Type) { + if (!PyStackRef_IsTaggedInt(iter)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - #ifdef Py_GIL_DISABLED - if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } - #endif break; } /* _ITER_JUMP_RANGE is not a viable micro-op for tier 2 because it is replaced */ case _GUARD_NOT_EXHAUSTED_RANGE: { + _PyStackRef null_or_index; _PyStackRef iter; + null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); - if (r->len <= 0) { + if (PyStackRef_Is(iter, null_or_index)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } @@ -4489,23 +4494,15 @@ } case _ITER_NEXT_RANGE: { - _PyStackRef iter; + _PyStackRef null_or_index; _PyStackRef next; - iter = stack_pointer[-2]; - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); - #ifdef Py_GIL_DISABLED - assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); - #endif - assert(r->len > 0); - long value = r->start; - r->start = value + r->step; - r->len--; - PyObject *res = PyLong_FromLong(value); - if (res == NULL) { + null_or_index = stack_pointer[-1]; + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { JUMP_TO_ERROR(); } - next = PyStackRef_FromPyObjectSteal(res); + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + stack_pointer[-1] = null_or_index; stack_pointer[0] = next; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -4517,11 +4514,11 @@ _PyInterpreterFrame *gen_frame; oparg = CURRENT_OPARG(); iter = stack_pointer[-2]; - PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(gen) != &PyGen_Type) { + if (PyStackRef_TYPE(iter) != &PyGen_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } + PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); #ifdef Py_GIL_DISABLED if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6a89819a7c80e0..f6913b63b643b0 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5753,18 +5753,34 @@ } // _FOR_ITER { - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (PyStackRef_IsTaggedInt(null_or_index)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - next = _PyForIter_NextWithIndex(iter_o, null_or_index); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(next)) { - JUMPBY(oparg + 1); - DISPATCH(); + if (PyStackRef_IsTaggedInt(iter)) { + if (PyStackRef_Is(iter, null_or_index)) { + null_or_index = PyStackRef_TagInt(-1); + JUMPBY(oparg + 1); + stack_pointer[-1] = null_or_index; + DISPATCH(); + } + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { + JUMP_TO_LABEL(error); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + } + else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + _PyFrame_SetStackPointer(frame, stack_pointer); + next = _PyForIter_NextWithIndex(iter_o, null_or_index); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyStackRef_IsNull(next)) { + JUMPBY(oparg + 1); + DISPATCH(); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5822,12 +5838,12 @@ // _FOR_ITER_GEN_FRAME { iter = stack_pointer[-2]; - PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(gen) != &PyGen_Type) { + if (PyStackRef_TYPE(iter) != &PyGen_Type) { UPDATE_MISS_STATS(FOR_ITER); assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); JUMP_TO_PREDICTED(FOR_ITER); } + PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); #ifdef Py_GIL_DISABLED if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) { UPDATE_MISS_STATS(FOR_ITER); @@ -5885,14 +5901,14 @@ { null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(iter_o) != &PyList_Type) { + if (PyStackRef_TYPE(iter) != &PyList_Type) { UPDATE_MISS_STATS(FOR_ITER); assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); JUMP_TO_PREDICTED(FOR_ITER); } assert(PyStackRef_IsTaggedInt(null_or_index)); #ifdef Py_GIL_DISABLED + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { UPDATE_MISS_STATS(FOR_ITER); assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); @@ -5962,55 +5978,35 @@ INSTRUCTION_STATS(FOR_ITER_RANGE); static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); _PyStackRef iter; + _PyStackRef null_or_index; _PyStackRef next; /* Skip 1 cache entry */ // _ITER_CHECK_RANGE { iter = stack_pointer[-2]; - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(r) != &PyRangeIter_Type) { - UPDATE_MISS_STATS(FOR_ITER); - assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); - JUMP_TO_PREDICTED(FOR_ITER); - } - #ifdef Py_GIL_DISABLED - if (!_PyObject_IsUniquelyReferenced((PyObject *)r)) { + if (!PyStackRef_IsTaggedInt(iter)) { UPDATE_MISS_STATS(FOR_ITER); assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); JUMP_TO_PREDICTED(FOR_ITER); } - #endif } // _ITER_JUMP_RANGE { - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); - #ifdef Py_GIL_DISABLED - assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); - #endif - STAT_INC(FOR_ITER, hit); - if (r->len <= 0) { + null_or_index = stack_pointer[-1]; + if (PyStackRef_Is(iter, null_or_index)) { JUMPBY(oparg + 1); DISPATCH(); } } // _ITER_NEXT_RANGE { - _PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter); - assert(Py_TYPE(r) == &PyRangeIter_Type); - #ifdef Py_GIL_DISABLED - assert(_PyObject_IsUniquelyReferenced((PyObject *)r)); - #endif - assert(r->len > 0); - long value = r->start; - r->start = value + r->step; - r->len--; - PyObject *res = PyLong_FromLong(value); - if (res == NULL) { + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { JUMP_TO_LABEL(error); } - next = PyStackRef_FromPyObjectSteal(res); + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } + stack_pointer[-1] = null_or_index; stack_pointer[0] = next; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); @@ -6036,8 +6032,7 @@ { null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - if (Py_TYPE(iter_o) != &PyTuple_Type) { + if (PyStackRef_TYPE(iter) != &PyTuple_Type) { UPDATE_MISS_STATS(FOR_ITER); assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); JUMP_TO_PREDICTED(FOR_ITER); @@ -6233,19 +6228,32 @@ index_or_null = PyStackRef_TagInt(0); } else { - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(iterable); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (iter_o == NULL) { - JUMP_TO_LABEL(error); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable); + if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) { + Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + iter = PyStackRef_TagInt(stop); + index_or_null = PyStackRef_TagInt(0); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + iter_o = PyObject_GetIter(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (iter_o == NULL) { + JUMP_TO_LABEL(error); + } + iter = PyStackRef_FromPyObjectSteal(iter_o); + index_or_null = PyStackRef_NULL; } - iter = PyStackRef_FromPyObjectSteal(iter_o); - index_or_null = PyStackRef_NULL; stack_pointer += 1; } } @@ -7142,12 +7150,27 @@ iter = stack_pointer[-2]; PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (PyStackRef_IsTaggedInt(null_or_index)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - next = _PyForIter_NextWithIndex(iter_o, null_or_index); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (PyStackRef_IsNull(next)) { - JUMPBY(oparg + 1); - DISPATCH(); + if (PyStackRef_IsTaggedInt(iter)) { + if (PyStackRef_Is(iter, null_or_index)) { + null_or_index = PyStackRef_TagInt(-1); + JUMPBY(oparg + 1); + stack_pointer[-1] = null_or_index; + DISPATCH(); + } + next = PyStackRef_BoxInt(null_or_index); + if (PyStackRef_IsNull(next)) { + JUMP_TO_LABEL(error); + } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + next = _PyForIter_NextWithIndex(iter_o, null_or_index); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyStackRef_IsNull(next)) { + JUMPBY(oparg + 1); + DISPATCH(); + } } null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); diff --git a/Python/specialize.c b/Python/specialize.c index 4b04a2c33d943c..beca021a554880 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2908,8 +2908,7 @@ _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT { assert(ENABLE_SPECIALIZATION_FT); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); - PyTypeObject *tp = Py_TYPE(iter_o); + PyTypeObject *tp = PyStackRef_TYPE(iter); if (PyStackRef_IsNull(null_or_index)) { #ifdef Py_GIL_DISABLED @@ -2922,11 +2921,7 @@ _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT goto failure; } #endif - if (tp == &PyRangeIter_Type) { - specialize(instr, FOR_ITER_RANGE); - return; - } - else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { + if (tp == &PyGen_Type && oparg <= SHRT_MAX) { // Generators are very much not thread-safe, so don't worry about // the specialization not being thread-safe. assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR || @@ -2941,8 +2936,13 @@ _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT } } else { + if (tp == &PyLong_Type) { + specialize(instr, FOR_ITER_RANGE); + return; + } if (tp == &PyList_Type) { #ifdef Py_GIL_DISABLED + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); // Only specialize for lists owned by this thread or shared if (!_Py_IsOwnedByCurrentThread(iter_o) && !_PyObject_GC_IS_SHARED(iter_o)) { goto failure; diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 3070559db8ae57..58b2284ec41da7 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -681,6 +681,10 @@ def has_error_without_pop(op: parser.CodeDef) -> bool: "PyStackRef_UntagInt", "PyStackRef_IncrementTaggedIntNoOverflow", "PyStackRef_IsNullOrInt", + "_PyRange_IsSimpleCompact", + "_PyRange_GetStopIfCompact", + "PyStackRef_BoxInt", + "PyStackRef_TYPE", ) From 8cf4e6ece44daf1259285f71b7bca3c6f48c37a4 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 27 May 2025 14:55:06 +0100 Subject: [PATCH 04/15] Allow range starts other than zero --- Include/internal/pycore_range.h | 1 + Include/internal/pycore_stackref.h | 16 ++++++++++ Lib/test/test_opcache.py | 47 ++++++++++++++++++++++++------ Objects/rangeobject.c | 17 ++++++++--- Python/bytecodes.c | 17 +++++------ Python/executor_cases.c.h | 7 +++-- Python/generated_cases.c.h | 18 ++++++------ Python/specialize.c | 1 + Python/stackrefs.c | 8 +++++ Tools/cases_generator/analyzer.py | 1 + 10 files changed, 100 insertions(+), 33 deletions(-) diff --git a/Include/internal/pycore_range.h b/Include/internal/pycore_range.h index 19b13203afca10..5e50698ddbb14e 100644 --- a/Include/internal/pycore_range.h +++ b/Include/internal/pycore_range.h @@ -17,6 +17,7 @@ typedef struct { // Does this range have start == 0, step == 1 and step in compact int range? int _PyRange_IsSimpleCompact(PyObject *range); +Py_ssize_t _PyRange_GetStartIfCompact(PyObject *range); Py_ssize_t _PyRange_GetStopIfCompact(PyObject *range); #ifdef __cplusplus diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index b5670dd9697f07..5f1bc2a95d4dda 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -101,6 +101,14 @@ PyStackRef_IsTaggedInt(_PyStackRef ref) return (ref.index & 1) == 1; } +static inline bool +PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b) +{ + assert(PyStackRef_IsTaggedInt(a)); + assert(PyStackRef_IsTaggedInt(b)); + return ((intptr_t)a.bits) < ((intptr_t)b.bits); +} + static inline PyObject * _PyStackRef_AsPyObjectBorrow(_PyStackRef ref, const char *filename, int linenumber) { @@ -274,6 +282,14 @@ PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref) return (_PyStackRef){ .bits = ref.bits + 4 }; } +static inline bool +PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b) +{ + assert(PyStackRef_IsTaggedInt(a)); + assert(PyStackRef_IsTaggedInt(b)); + return ((intptr_t)a.bits) < ((intptr_t)b.bits); +} + #define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0) extern _PyStackRef PyStackRef_BoxInt(_PyStackRef i); diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 30baa09048616c..bd51ba8f81cd18 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1832,15 +1832,6 @@ def for_iter_tuple(): self.assert_specialized(for_iter_tuple, "FOR_ITER_TUPLE") self.assert_no_opcode(for_iter_tuple, "FOR_ITER") - r = range(10) - def for_iter_range(): - for i in r: - self.assertIn(i, r) - - for_iter_range() - self.assert_specialized(for_iter_range, "FOR_ITER_RANGE") - self.assert_no_opcode(for_iter_range, "FOR_ITER") - def for_iter_generator(): for i in (i for i in range(10)): i + 1 @@ -1849,6 +1840,44 @@ def for_iter_generator(): self.assert_specialized(for_iter_generator, "FOR_ITER_GEN") self.assert_no_opcode(for_iter_generator, "FOR_ITER") + @cpython_only + @requires_specialization_ft + def test_for_iter_range(self): + r = range(10) + def for_iter1(): + for i in r: + self.assertIn(i, r) + + for_iter1() + self.assert_specialized(for_iter1, "FOR_ITER_RANGE") + self.assert_no_opcode(for_iter1, "FOR_ITER") + + r = range(-10, 0) + def for_iter2(): + for i in r: + self.assertIn(i, r) + + for_iter2() + self.assert_specialized(for_iter2, "FOR_ITER_RANGE") + self.assert_no_opcode(for_iter2, "FOR_ITER") + + r = range(100_000, 100_010) + def for_iter3(): + for i in r: + self.assertIn(i, r) + + for_iter3() + self.assert_specialized(for_iter3, "FOR_ITER_RANGE") + self.assert_no_opcode(for_iter3, "FOR_ITER") + + r = range((1 << 65), (1 << 65)+10) + def for_iter4(): + for i in r: + self.assertIn(i, r) + + for_iter4() + self.assert_specialized(for_iter4, "FOR_ITER") + if __name__ == "__main__": unittest.main() diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index e533114a846208..e365c8ec36e3df 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -160,20 +160,29 @@ int _PyRange_IsSimpleCompact(PyObject *range) { assert(PyRange_Check(range)); rangeobject *r = (rangeobject*)range; - if (r->start == _PyLong_GetZero() && r->step == _PyLong_GetOne() && - _PyLong_IsNonNegativeCompact((PyLongObject *)r->stop) + if (_PyLong_IsCompact((PyLongObject *)r->start) && + _PyLong_IsCompact((PyLongObject *)r->stop) && + r->step == _PyLong_GetOne() ) { return 1; } return 0; } +Py_ssize_t +_PyRange_GetStartIfCompact(PyObject *range) { + assert(PyRange_Check(range)); + rangeobject *r = (rangeobject*)range; + assert(_PyLong_IsCompact((PyLongObject *)r->start)); + return _PyLong_CompactValue((PyLongObject *)r->start); +} + Py_ssize_t _PyRange_GetStopIfCompact(PyObject *range) { assert(PyRange_Check(range)); rangeobject *r = (rangeobject*)range; - assert(_PyLong_IsNonNegativeCompact((PyLongObject *)r->stop)); - return _PyLong_GetNonNegativeCompactValue((PyLongObject *)r->stop); + assert(_PyLong_IsCompact((PyLongObject *)r->stop)); + return _PyLong_CompactValue((PyLongObject *)r->stop); } PyDoc_STRVAR(range_doc, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7da61931238aff..07729721e86bcb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3080,10 +3080,11 @@ dummy_func( else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable); if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) { + Py_ssize_t start = _PyRange_GetStartIfCompact(iter_o); Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o); PyStackRef_CLOSE(iterable); iter = PyStackRef_TagInt(stop); - index_or_null = PyStackRef_TagInt(0); + index_or_null = PyStackRef_TagInt(start); } else { iter_o = PyObject_GetIter(iter_o); @@ -3171,8 +3172,7 @@ dummy_func( /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ if (PyStackRef_IsTaggedInt(null_or_index)) { if (PyStackRef_IsTaggedInt(iter)) { - if (PyStackRef_Is(iter, null_or_index)) { - null_or_index = PyStackRef_TagInt(-1); + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { JUMPBY(oparg + 1); DISPATCH(); @@ -3242,14 +3242,11 @@ dummy_func( inst(INSTRUMENTED_FOR_ITER, (unused/1, iter, null_or_index -- iter, null_or_index, next)) { - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (PyStackRef_IsTaggedInt(null_or_index)) { if (PyStackRef_IsTaggedInt(iter)) { - if (PyStackRef_Is(iter, null_or_index)) { - null_or_index = PyStackRef_TagInt(-1); + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { JUMPBY(oparg + 1); DISPATCH(); - } next = PyStackRef_BoxInt(null_or_index); if (PyStackRef_IsNull(next)) { @@ -3258,6 +3255,7 @@ dummy_func( null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); next = _PyForIter_NextWithIndex(iter_o, null_or_index); if (PyStackRef_IsNull(next)) { JUMPBY(oparg + 1); @@ -3268,6 +3266,7 @@ dummy_func( INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); } else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); if (next_o != NULL) { next = PyStackRef_FromPyObjectSteal(next_o); @@ -3423,7 +3422,7 @@ dummy_func( } replaced op(_ITER_JUMP_RANGE, (iter, null_or_index -- iter, null_or_index)) { - if (PyStackRef_Is(iter, null_or_index)) { + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { // Jump over END_FOR instruction. JUMPBY(oparg + 1); DISPATCH(); @@ -3432,7 +3431,7 @@ dummy_func( // Only used by Tier 2 op(_GUARD_NOT_EXHAUSTED_RANGE, (iter, null_or_index -- iter, null_or_index)) { - EXIT_IF(PyStackRef_Is(iter, null_or_index)); + EXIT_IF(!PyStackRef_TaggedIntLessThan(null_or_index, iter)); } op(_ITER_NEXT_RANGE, (iter, null_or_index -- iter, null_or_index, next)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 5708cd4a6c04cd..0f9dce96dda506 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4202,6 +4202,9 @@ else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable); if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_ssize_t start = _PyRange_GetStartIfCompact(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -4209,7 +4212,7 @@ PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); iter = PyStackRef_TagInt(stop); - index_or_null = PyStackRef_TagInt(0); + index_or_null = PyStackRef_TagInt(start); } else { _PyFrame_SetStackPointer(frame, stack_pointer); @@ -4486,7 +4489,7 @@ _PyStackRef iter; null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - if (PyStackRef_Is(iter, null_or_index)) { + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f6913b63b643b0..f17d9c39cdf019 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5755,10 +5755,8 @@ { if (PyStackRef_IsTaggedInt(null_or_index)) { if (PyStackRef_IsTaggedInt(iter)) { - if (PyStackRef_Is(iter, null_or_index)) { - null_or_index = PyStackRef_TagInt(-1); + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { JUMPBY(oparg + 1); - stack_pointer[-1] = null_or_index; DISPATCH(); } next = PyStackRef_BoxInt(null_or_index); @@ -5993,7 +5991,7 @@ // _ITER_JUMP_RANGE { null_or_index = stack_pointer[-1]; - if (PyStackRef_Is(iter, null_or_index)) { + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { JUMPBY(oparg + 1); DISPATCH(); } @@ -6230,6 +6228,9 @@ else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iterable); if (tp == &PyRange_Type && _PyRange_IsSimpleCompact(iter_o)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_ssize_t start = _PyRange_GetStartIfCompact(iter_o); + stack_pointer = _PyFrame_GetStackPointer(frame); Py_ssize_t stop = _PyRange_GetStopIfCompact(iter_o); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); @@ -6237,7 +6238,7 @@ PyStackRef_CLOSE(iterable); stack_pointer = _PyFrame_GetStackPointer(frame); iter = PyStackRef_TagInt(stop); - index_or_null = PyStackRef_TagInt(0); + index_or_null = PyStackRef_TagInt(start); } else { _PyFrame_SetStackPointer(frame, stack_pointer); @@ -7148,13 +7149,10 @@ /* Skip 1 cache entry */ null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (PyStackRef_IsTaggedInt(null_or_index)) { if (PyStackRef_IsTaggedInt(iter)) { - if (PyStackRef_Is(iter, null_or_index)) { - null_or_index = PyStackRef_TagInt(-1); + if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { JUMPBY(oparg + 1); - stack_pointer[-1] = null_or_index; DISPATCH(); } next = PyStackRef_BoxInt(null_or_index); @@ -7164,6 +7162,7 @@ null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); _PyFrame_SetStackPointer(frame, stack_pointer); next = _PyForIter_NextWithIndex(iter_o, null_or_index); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -7176,6 +7175,7 @@ INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT); } else { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); stack_pointer = _PyFrame_GetStackPointer(frame); diff --git a/Python/specialize.c b/Python/specialize.c index beca021a554880..5f505d86f5d13d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2912,6 +2912,7 @@ _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT if (PyStackRef_IsNull(null_or_index)) { #ifdef Py_GIL_DISABLED + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); // Only specialize for uniquely referenced iterators, so that we know // they're only referenced by this one thread. This is more limiting // than we need (even `it = iter(mylist); for item in it:` won't get diff --git a/Python/stackrefs.c b/Python/stackrefs.c index b2a1369031ad2b..ed6d2f07dd4917 100644 --- a/Python/stackrefs.c +++ b/Python/stackrefs.c @@ -202,6 +202,14 @@ _PyStackRef PyStackRef_TagInt(intptr_t i) return (_PyStackRef){ .index = (i << 1) + 1 }; } +bool +PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b) +{ + assert(PyStackRef_IsTaggedInt(a)); + assert(PyStackRef_IsTaggedInt(b)); + return a.bits < b.bits; +} + intptr_t PyStackRef_UntagInt(_PyStackRef i) { diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 58b2284ec41da7..705978bf86fb70 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -685,6 +685,7 @@ def has_error_without_pop(op: parser.CodeDef) -> bool: "_PyRange_GetStopIfCompact", "PyStackRef_BoxInt", "PyStackRef_TYPE", + "PyStackRef_TaggedIntLessThan", ) From 11117b4506e16ba4d8e2478bf795d36684589755 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 28 May 2025 09:26:26 +0100 Subject: [PATCH 05/15] Specialize GET_ITER for range --- Include/internal/pycore_magic_number.h | 5 +- Include/internal/pycore_opcode_metadata.h | 10 ++- Include/internal/pycore_uop_ids.h | 1 + Include/internal/pycore_uop_metadata.h | 4 ++ Include/opcode_ids.h | 73 +++++++++++----------- Lib/_opcode_metadata.py | 74 ++++++++++++----------- Lib/test/test_opcache.py | 51 +++++++++++++++- Python/bytecodes.c | 11 ++++ Python/executor_cases.c.h | 29 +++++++++ Python/generated_cases.c.h | 42 +++++++++++++ Python/opcode_targets.h | 5 +- Python/optimizer_cases.c.h | 12 ++++ Python/specialize.c | 7 +++ 13 files changed, 244 insertions(+), 80 deletions(-) diff --git a/Include/internal/pycore_magic_number.h b/Include/internal/pycore_magic_number.h index 475fbe08c9fc10..ae2d1ca0a614f8 100644 --- a/Include/internal/pycore_magic_number.h +++ b/Include/internal/pycore_magic_number.h @@ -279,9 +279,8 @@ Known values: Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST) Python 3.15a0 3650 (Initial version) Python 3.15a1 3651 (Simplify LOAD_CONST) - - Python 3.14a7 3652 (Virtual iterators) - Python 3.14a7 3653 (Specialize GET_ITER) + Python 3.15a1 3652 (Virtual iterators) + Python 3.15a1 3653 (Specialize GET_ITER) Python 3.16 will start with 3700 diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 0c730d51ee958c..d243bd9038c899 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -224,6 +224,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 1; case GET_ITER_LIST_OR_TUPLE: return 1; + case GET_ITER_RANGE: + return 1; case GET_ITER_SELF: return 1; case GET_LEN: @@ -711,6 +713,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 2; case GET_ITER_LIST_OR_TUPLE: return 2; + case GET_ITER_RANGE: + return 2; case GET_ITER_SELF: return 2; case GET_LEN: @@ -1171,6 +1175,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_ITER] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_ITER_LIST_OR_TUPLE] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, + [GET_ITER_RANGE] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [GET_ITER_SELF] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG }, [GET_LEN] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, @@ -1414,6 +1419,7 @@ _PyOpcode_macro_expansion[256] = { [GET_AWAITABLE] = { .nuops = 1, .uops = { { _GET_AWAITABLE, OPARG_SIMPLE, 0 } } }, [GET_ITER] = { .nuops = 1, .uops = { { _GET_ITER, OPARG_SIMPLE, 0 } } }, [GET_ITER_LIST_OR_TUPLE] = { .nuops = 1, .uops = { { _GET_ITER_LIST_OR_TUPLE, OPARG_SIMPLE, 1 } } }, + [GET_ITER_RANGE] = { .nuops = 1, .uops = { { _GET_ITER_RANGE, OPARG_SIMPLE, 1 } } }, [GET_ITER_SELF] = { .nuops = 1, .uops = { { _GET_ITER_SELF, OPARG_SIMPLE, 1 } } }, [GET_LEN] = { .nuops = 1, .uops = { { _GET_LEN, OPARG_SIMPLE, 0 } } }, [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { _GET_YIELD_FROM_ITER, OPARG_SIMPLE, 0 } } }, @@ -1613,6 +1619,7 @@ const char *_PyOpcode_OpName[267] = { [GET_AWAITABLE] = "GET_AWAITABLE", [GET_ITER] = "GET_ITER", [GET_ITER_LIST_OR_TUPLE] = "GET_ITER_LIST_OR_TUPLE", + [GET_ITER_RANGE] = "GET_ITER_RANGE", [GET_ITER_SELF] = "GET_ITER_SELF", [GET_LEN] = "GET_LEN", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", @@ -1796,7 +1803,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [125] = 125, [126] = 126, [127] = 127, - [212] = 212, [213] = 213, [214] = 214, [215] = 215, @@ -1911,6 +1917,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [GET_AWAITABLE] = GET_AWAITABLE, [GET_ITER] = GET_ITER, [GET_ITER_LIST_OR_TUPLE] = GET_ITER, + [GET_ITER_RANGE] = GET_ITER, [GET_ITER_SELF] = GET_ITER, [GET_LEN] = GET_LEN, [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER, @@ -2057,7 +2064,6 @@ const uint8_t _PyOpcode_Deopt[256] = { case 125: \ case 126: \ case 127: \ - case 212: \ case 213: \ case 214: \ case 215: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 2ac575c5e8cc7d..b771b56858e8bd 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -118,6 +118,7 @@ extern "C" { #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER 376 #define _GET_ITER_LIST_OR_TUPLE GET_ITER_LIST_OR_TUPLE +#define _GET_ITER_RANGE GET_ITER_RANGE #define _GET_ITER_SELF GET_ITER_SELF #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index b24f8d62f9836f..45e2d5bb60cb56 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -204,6 +204,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GET_ITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GET_ITER_SELF] = HAS_DEOPT_FLAG, [_GET_ITER_LIST_OR_TUPLE] = HAS_DEOPT_FLAG, + [_GET_ITER_RANGE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_GET_YIELD_FROM_ITER] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_FOR_ITER_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_ITER_CHECK_LIST] = HAS_EXIT_FLAG, @@ -438,6 +439,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GET_AWAITABLE] = "_GET_AWAITABLE", [_GET_ITER] = "_GET_ITER", [_GET_ITER_LIST_OR_TUPLE] = "_GET_ITER_LIST_OR_TUPLE", + [_GET_ITER_RANGE] = "_GET_ITER_RANGE", [_GET_ITER_SELF] = "_GET_ITER_SELF", [_GET_LEN] = "_GET_LEN", [_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER", @@ -1012,6 +1014,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _GET_ITER_LIST_OR_TUPLE: return 0; + case _GET_ITER_RANGE: + return 1; case _GET_YIELD_FROM_ITER: return 1; case _FOR_ITER_TIER_TWO: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index ee01006bba3052..1a2c1754ad7e13 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -179,42 +179,43 @@ extern "C" { #define FOR_ITER_RANGE 173 #define FOR_ITER_TUPLE 174 #define GET_ITER_LIST_OR_TUPLE 175 -#define GET_ITER_SELF 176 -#define JUMP_BACKWARD_JIT 177 -#define JUMP_BACKWARD_NO_JIT 178 -#define LOAD_ATTR_CLASS 179 -#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 180 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 181 -#define LOAD_ATTR_INSTANCE_VALUE 182 -#define LOAD_ATTR_METHOD_LAZY_DICT 183 -#define LOAD_ATTR_METHOD_NO_DICT 184 -#define LOAD_ATTR_METHOD_WITH_VALUES 185 -#define LOAD_ATTR_MODULE 186 -#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 187 -#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 188 -#define LOAD_ATTR_PROPERTY 189 -#define LOAD_ATTR_SLOT 190 -#define LOAD_ATTR_WITH_HINT 191 -#define LOAD_GLOBAL_BUILTIN 192 -#define LOAD_GLOBAL_MODULE 193 -#define LOAD_SUPER_ATTR_ATTR 194 -#define LOAD_SUPER_ATTR_METHOD 195 -#define RESUME_CHECK 196 -#define SEND_GEN 197 -#define STORE_ATTR_INSTANCE_VALUE 198 -#define STORE_ATTR_SLOT 199 -#define STORE_ATTR_WITH_HINT 200 -#define STORE_SUBSCR_DICT 201 -#define STORE_SUBSCR_LIST_INT 202 -#define TO_BOOL_ALWAYS_TRUE 203 -#define TO_BOOL_BOOL 204 -#define TO_BOOL_INT 205 -#define TO_BOOL_LIST 206 -#define TO_BOOL_NONE 207 -#define TO_BOOL_STR 208 -#define UNPACK_SEQUENCE_LIST 209 -#define UNPACK_SEQUENCE_TUPLE 210 -#define UNPACK_SEQUENCE_TWO_TUPLE 211 +#define GET_ITER_RANGE 176 +#define GET_ITER_SELF 177 +#define JUMP_BACKWARD_JIT 178 +#define JUMP_BACKWARD_NO_JIT 179 +#define LOAD_ATTR_CLASS 180 +#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 181 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 182 +#define LOAD_ATTR_INSTANCE_VALUE 183 +#define LOAD_ATTR_METHOD_LAZY_DICT 184 +#define LOAD_ATTR_METHOD_NO_DICT 185 +#define LOAD_ATTR_METHOD_WITH_VALUES 186 +#define LOAD_ATTR_MODULE 187 +#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 188 +#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 189 +#define LOAD_ATTR_PROPERTY 190 +#define LOAD_ATTR_SLOT 191 +#define LOAD_ATTR_WITH_HINT 192 +#define LOAD_GLOBAL_BUILTIN 193 +#define LOAD_GLOBAL_MODULE 194 +#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 INSTRUMENTED_END_FOR 234 #define INSTRUMENTED_POP_ITER 235 #define INSTRUMENTED_END_SEND 236 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index e70350590f3529..78cf06d73db5c4 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -87,6 +87,7 @@ "GET_ITER": [ "GET_ITER_LIST_OR_TUPLE", "GET_ITER_SELF", + "GET_ITER_RANGE", ], "FOR_ITER": [ "FOR_ITER_LIST", @@ -172,42 +173,43 @@ 'FOR_ITER_RANGE': 173, 'FOR_ITER_TUPLE': 174, 'GET_ITER_LIST_OR_TUPLE': 175, - 'GET_ITER_SELF': 176, - 'JUMP_BACKWARD_JIT': 177, - 'JUMP_BACKWARD_NO_JIT': 178, - 'LOAD_ATTR_CLASS': 179, - 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 180, - 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 181, - 'LOAD_ATTR_INSTANCE_VALUE': 182, - 'LOAD_ATTR_METHOD_LAZY_DICT': 183, - 'LOAD_ATTR_METHOD_NO_DICT': 184, - 'LOAD_ATTR_METHOD_WITH_VALUES': 185, - 'LOAD_ATTR_MODULE': 186, - 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 187, - 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 188, - 'LOAD_ATTR_PROPERTY': 189, - 'LOAD_ATTR_SLOT': 190, - 'LOAD_ATTR_WITH_HINT': 191, - 'LOAD_GLOBAL_BUILTIN': 192, - 'LOAD_GLOBAL_MODULE': 193, - 'LOAD_SUPER_ATTR_ATTR': 194, - 'LOAD_SUPER_ATTR_METHOD': 195, - 'RESUME_CHECK': 196, - 'SEND_GEN': 197, - 'STORE_ATTR_INSTANCE_VALUE': 198, - 'STORE_ATTR_SLOT': 199, - 'STORE_ATTR_WITH_HINT': 200, - 'STORE_SUBSCR_DICT': 201, - 'STORE_SUBSCR_LIST_INT': 202, - 'TO_BOOL_ALWAYS_TRUE': 203, - 'TO_BOOL_BOOL': 204, - 'TO_BOOL_INT': 205, - 'TO_BOOL_LIST': 206, - 'TO_BOOL_NONE': 207, - 'TO_BOOL_STR': 208, - 'UNPACK_SEQUENCE_LIST': 209, - 'UNPACK_SEQUENCE_TUPLE': 210, - 'UNPACK_SEQUENCE_TWO_TUPLE': 211, + 'GET_ITER_RANGE': 176, + 'GET_ITER_SELF': 177, + 'JUMP_BACKWARD_JIT': 178, + 'JUMP_BACKWARD_NO_JIT': 179, + 'LOAD_ATTR_CLASS': 180, + 'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 181, + 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 182, + 'LOAD_ATTR_INSTANCE_VALUE': 183, + 'LOAD_ATTR_METHOD_LAZY_DICT': 184, + 'LOAD_ATTR_METHOD_NO_DICT': 185, + 'LOAD_ATTR_METHOD_WITH_VALUES': 186, + 'LOAD_ATTR_MODULE': 187, + 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 188, + 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 189, + 'LOAD_ATTR_PROPERTY': 190, + 'LOAD_ATTR_SLOT': 191, + 'LOAD_ATTR_WITH_HINT': 192, + 'LOAD_GLOBAL_BUILTIN': 193, + 'LOAD_GLOBAL_MODULE': 194, + '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, } opmap = { diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index bd51ba8f81cd18..915b9ba139e636 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1852,7 +1852,7 @@ def for_iter1(): self.assert_specialized(for_iter1, "FOR_ITER_RANGE") self.assert_no_opcode(for_iter1, "FOR_ITER") - r = range(-10, 0) + r = range(-20, -10) def for_iter2(): for i in r: self.assertIn(i, r) @@ -1878,6 +1878,55 @@ def for_iter4(): for_iter4() self.assert_specialized(for_iter4, "FOR_ITER") + @cpython_only + @requires_specialization_ft + def test_get_iter(self): + + L = list(range(2)) + def for_iter_list(): + n = 0 + while n < _testinternalcapi.SPECIALIZATION_THRESHOLD: + n += 1 + for i in L: + self.assertIn(i, L) + + for_iter_list() + self.assert_specialized(for_iter_list, "GET_ITER_LIST_OR_TUPLE") + self.assert_no_opcode(for_iter_list, "GET_ITER") + + t = tuple(range(2)) + def for_iter_tuple(): + n = 0 + while n < _testinternalcapi.SPECIALIZATION_THRESHOLD: + n += 1 + for i in t: + self.assertIn(i, t) + + for_iter_tuple() + self.assert_specialized(for_iter_tuple, "GET_ITER_LIST_OR_TUPLE") + self.assert_no_opcode(for_iter_tuple, "GET_ITER") + + def for_iter_generator(): + n = 0 + while n < _testinternalcapi.SPECIALIZATION_THRESHOLD: + n += 1 + for i in (i for i in range(2)): + i + 1 + + for_iter_generator() + self.assert_specialized(for_iter_generator, "GET_ITER_SELF") + self.assert_no_opcode(for_iter_generator, "GET_ITER") + + def for_iter_range(): + n = 0 + while n < _testinternalcapi.SPECIALIZATION_THRESHOLD: + n += 1 + for i in range(2): + i + 1 + + for_iter_range() + self.assert_specialized(for_iter_range, "GET_ITER_RANGE") + self.assert_no_opcode(for_iter_range, "GET_ITER") if __name__ == "__main__": unittest.main() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 07729721e86bcb..712035ffcf9abc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3052,6 +3052,7 @@ dummy_func( family(GET_ITER, 1) = { GET_ITER_LIST_OR_TUPLE, GET_ITER_SELF, + GET_ITER_RANGE, }; specializing op(_SPECIALIZE_GET_ITER, (counter/1, iter -- iter)) { @@ -3112,6 +3113,16 @@ dummy_func( index0 = PyStackRef_TagInt(0); } + inst(GET_ITER_RANGE, (unused/1, iter -- stop, index)) { + PyTypeObject *tp = PyStackRef_TYPE(iter); + DEOPT_IF(tp != &PyRange_Type); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + DEOPT_IF(!_PyRange_IsSimpleCompact(iter_o)); + index = PyStackRef_TagInt(_PyRange_GetStartIfCompact(iter_o)); + stop = PyStackRef_TagInt(_PyRange_GetStopIfCompact(iter_o)); + PyStackRef_CLOSE(iter); + } + inst(GET_YIELD_FROM_ITER, (iterable -- iter)) { /* before: [obj]; after [getiter(obj)] */ PyObject *iterable_o = PyStackRef_AsPyObjectBorrow(iterable); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 0f9dce96dda506..f1cd3bfe4dec9f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4272,6 +4272,35 @@ break; } + case _GET_ITER_RANGE: { + _PyStackRef iter; + _PyStackRef stop; + _PyStackRef index; + iter = stack_pointer[-1]; + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp != &PyRange_Type) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (!_PyRange_IsSimpleCompact(iter_o)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + index = PyStackRef_TagInt(_PyRange_GetStartIfCompact(iter_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); + stop = PyStackRef_TagInt(_PyRange_GetStopIfCompact(iter_o)); + stack_pointer[-1] = stop; + stack_pointer[0] = index; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iter); + stack_pointer = _PyFrame_GetStackPointer(frame); + break; + } + case _GET_YIELD_FROM_ITER: { _PyStackRef iterable; _PyStackRef iter; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f17d9c39cdf019..2e3ed73aeaa44e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -6295,6 +6295,48 @@ DISPATCH(); } + TARGET(GET_ITER_RANGE) { + #if Py_TAIL_CALL_INTERP + int opcode = GET_ITER_RANGE; + (void)(opcode); + #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 2; + INSTRUCTION_STATS(GET_ITER_RANGE); + static_assert(1 == 1, "incorrect cache size"); + _PyStackRef iter; + _PyStackRef stop; + _PyStackRef index; + /* Skip 1 cache entry */ + iter = stack_pointer[-1]; + PyTypeObject *tp = PyStackRef_TYPE(iter); + if (tp != &PyRange_Type) { + UPDATE_MISS_STATS(GET_ITER); + assert(_PyOpcode_Deopt[opcode] == (GET_ITER)); + JUMP_TO_PREDICTED(GET_ITER); + } + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (!_PyRange_IsSimpleCompact(iter_o)) { + UPDATE_MISS_STATS(GET_ITER); + assert(_PyOpcode_Deopt[opcode] == (GET_ITER)); + JUMP_TO_PREDICTED(GET_ITER); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + index = PyStackRef_TagInt(_PyRange_GetStartIfCompact(iter_o)); + stack_pointer = _PyFrame_GetStackPointer(frame); + stop = PyStackRef_TagInt(_PyRange_GetStopIfCompact(iter_o)); + stack_pointer[-1] = stop; + stack_pointer[0] = index; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(iter); + stack_pointer = _PyFrame_GetStackPointer(frame); + DISPATCH(); + } + TARGET(GET_ITER_SELF) { #if Py_TAIL_CALL_INTERP int opcode = GET_ITER_SELF; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 141546219158b3..338afdf4532a4c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -176,6 +176,7 @@ static void *opcode_targets[256] = { &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_TUPLE, &&TARGET_GET_ITER_LIST_OR_TUPLE, + &&TARGET_GET_ITER_RANGE, &&TARGET_GET_ITER_SELF, &&TARGET_JUMP_BACKWARD_JIT, &&TARGET_JUMP_BACKWARD_NO_JIT, @@ -233,7 +234,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_END_SEND, @@ -360,6 +360,7 @@ Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ANEXT(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_AWAITABLE(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER_LIST_OR_TUPLE(TAIL_CALL_PARAMS); +Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER_RANGE(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_ITER_SELF(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_LEN(TAIL_CALL_PARAMS); Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_GET_YIELD_FROM_ITER(TAIL_CALL_PARAMS); @@ -599,6 +600,7 @@ static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { [GET_AWAITABLE] = _TAIL_CALL_GET_AWAITABLE, [GET_ITER] = _TAIL_CALL_GET_ITER, [GET_ITER_LIST_OR_TUPLE] = _TAIL_CALL_GET_ITER_LIST_OR_TUPLE, + [GET_ITER_RANGE] = _TAIL_CALL_GET_ITER_RANGE, [GET_ITER_SELF] = _TAIL_CALL_GET_ITER_SELF, [GET_LEN] = _TAIL_CALL_GET_LEN, [GET_YIELD_FROM_ITER] = _TAIL_CALL_GET_YIELD_FROM_ITER, @@ -740,7 +742,6 @@ static py_tail_call_funcptr INSTRUCTION_TABLE[256] = { [125] = _TAIL_CALL_UNKNOWN_OPCODE, [126] = _TAIL_CALL_UNKNOWN_OPCODE, [127] = _TAIL_CALL_UNKNOWN_OPCODE, - [212] = _TAIL_CALL_UNKNOWN_OPCODE, [213] = _TAIL_CALL_UNKNOWN_OPCODE, [214] = _TAIL_CALL_UNKNOWN_OPCODE, [215] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 142284325da788..270ee86f9142b8 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1591,6 +1591,18 @@ break; } + case _GET_ITER_RANGE: { + JitOptSymbol *stop; + JitOptSymbol *index; + stop = sym_new_not_null(ctx); + index = sym_new_not_null(ctx); + stack_pointer[-1] = stop; + stack_pointer[0] = index; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + case _GET_YIELD_FROM_ITER: { JitOptSymbol *iter; iter = sym_new_not_null(ctx); diff --git a/Python/specialize.c b/Python/specialize.c index 5f505d86f5d13d..88fb339a99b7da 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -17,6 +17,7 @@ #include "pycore_uop_ids.h" // MAX_UOP_ID #include "pycore_opcode_utils.h" // RESUME_AT_FUNC_START #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() +#include "pycore_range.h" // _PyRange_IsSimpleCompact() #include "pycore_runtime.h" // _Py_ID() #include "pycore_unicodeobject.h" // _PyUnicodeASCIIIter_Type @@ -3187,6 +3188,12 @@ _Py_Specialize_GetIter(_PyStackRef iterable, _Py_CODEUNIT *instr) specialize(instr, GET_ITER_LIST_OR_TUPLE); return; } + if (tp == &PyRange_Type) { + if (_PyRange_IsSimpleCompact(PyStackRef_AsPyObjectBorrow(iterable))) { + specialize(instr, GET_ITER_RANGE); + return; + } + } #ifdef Py_STATS _Py_GatherStats_GetIter(iterable); #endif From d6f033fe8a0b1426bfd1b84de3f139ce5bb91695 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 28 May 2025 10:11:48 +0100 Subject: [PATCH 06/15] Fix assert --- Include/internal/pycore_stackref.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 5f1bc2a95d4dda..a32df79c698b20 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -278,7 +278,7 @@ static inline _PyStackRef PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref) { assert((ref.bits & Py_TAG_BITS) == Py_INT_TAG); // Is tagged int - assert((ref.bits & (~Py_TAG_BITS)) != (INT_MAX & (~Py_TAG_BITS))); // Isn't about to overflow + assert((ref.bits & (~Py_TAG_BITS)) != (INTPTR_MAX & (~Py_TAG_BITS))); // Isn't about to overflow return (_PyStackRef){ .bits = ref.bits + 4 }; } From 4679ccc736d716486ec13bbc2a0dcd1394a90ed7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 29 May 2025 09:30:40 +0100 Subject: [PATCH 07/15] Fix GET_ITER stats --- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 712035ffcf9abc..855e5bffaec2ae 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3062,7 +3062,7 @@ dummy_func( _Py_Specialize_GetIter(iter, next_instr); DISPATCH_SAME_OPARG(); } - OPCODE_DEFERRED_INC(FOR_ITER); + OPCODE_DEFERRED_INC(GET_ITER); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); #endif /* ENABLE_SPECIALIZATION_FT */ } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2e3ed73aeaa44e..6452b4ce5f7709 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -6207,7 +6207,7 @@ stack_pointer = _PyFrame_GetStackPointer(frame); DISPATCH_SAME_OPARG(); } - OPCODE_DEFERRED_INC(FOR_ITER); + OPCODE_DEFERRED_INC(GET_ITER); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); #endif /* ENABLE_SPECIALIZATION_FT */ } From 06c168076077e21e346e6f332aae72ea6bc1425a Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 10:56:16 +0100 Subject: [PATCH 08/15] Fix stats for FOR_ITER specialization --- Python/specialize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index 88fb339a99b7da..310e0f894f74cd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2960,7 +2960,7 @@ _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT } failure: SPECIALIZATION_FAIL(FOR_ITER, - _PySpecialization_ClassifyIterator(iter_o)); + _PySpecialization_ClassifyIterator(PyStackRef_AsPyObjectBorrow(iter))); unspecialize(instr); } From 15cb250968457040c23f35bfd9ff41d887f20ed5 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 11:15:11 +0100 Subject: [PATCH 09/15] Remove unused function --- Include/internal/pycore_long.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 056288ac358e13..3196d1b82084b9 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -207,15 +207,6 @@ _PyLong_IsNonNegativeCompact(const PyLongObject* op) { } -/* Return the value of a non-negative compact as a machine int */ -static inline Py_ssize_t -_PyLong_GetNonNegativeCompactValue(const PyLongObject* op) { - assert(PyLong_Check(op)); - assert (_PyLong_IsNonNegativeCompact(op)); - return op->long_value.ob_digit[0]; -} - - static inline int _PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { assert(PyLong_Check(a)); From 89d5d8538970816a232fbe058ba5a44637741243 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 11:19:43 +0100 Subject: [PATCH 10/15] Correct comment --- Include/internal/pycore_range.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_range.h b/Include/internal/pycore_range.h index 5e50698ddbb14e..a3c1891692dd21 100644 --- a/Include/internal/pycore_range.h +++ b/Include/internal/pycore_range.h @@ -15,7 +15,7 @@ typedef struct { long len; } _PyRangeIterObject; -// Does this range have start == 0, step == 1 and step in compact int range? +// Does this range have step == 1 and both start and stop in compact int range? int _PyRange_IsSimpleCompact(PyObject *range); Py_ssize_t _PyRange_GetStartIfCompact(PyObject *range); Py_ssize_t _PyRange_GetStopIfCompact(PyObject *range); From 9f688e720ee10e26ae028c386b6d7f5a85b2960a Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 11:58:17 +0100 Subject: [PATCH 11/15] Fix merge glitch --- Python/bytecodes.c | 5 +---- Python/generated_cases.c.h | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 855e5bffaec2ae..905c6f5392784d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3180,7 +3180,6 @@ dummy_func( } replaced op(_FOR_ITER, (iter, null_or_index -- iter, null_or_index, next)) { - /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ if (PyStackRef_IsTaggedInt(null_or_index)) { if (PyStackRef_IsTaggedInt(iter)) { if (!PyStackRef_TaggedIntLessThan(null_or_index, iter)) { @@ -3192,7 +3191,6 @@ dummy_func( if (PyStackRef_IsNull(next)) { ERROR_NO_POP(); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); @@ -3201,8 +3199,8 @@ dummy_func( JUMPBY(oparg + 1); DISPATCH(); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); @@ -3263,7 +3261,6 @@ dummy_func( if (PyStackRef_IsNull(next)) { ERROR_NO_POP(); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6452b4ce5f7709..004f0c5e59a799 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5763,7 +5763,6 @@ if (PyStackRef_IsNull(next)) { JUMP_TO_LABEL(error); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); @@ -5774,8 +5773,8 @@ JUMPBY(oparg + 1); DISPATCH(); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } + null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); @@ -7201,7 +7200,6 @@ if (PyStackRef_IsNull(next)) { JUMP_TO_LABEL(error); } - null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index); } else { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); From 7325b44665bfd7c8303302f7fad13ae3569cd982 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 12:57:05 +0100 Subject: [PATCH 12/15] Fix tier 2 unspecialized iteration over ranges --- Python/bytecodes.c | 3 +-- Python/executor_cases.c.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 905c6f5392784d..572cb6c1ad8533 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3226,9 +3226,8 @@ dummy_func( } op(_FOR_ITER_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) { - /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); EXIT_IF(!PyStackRef_IsNull(null_or_index)); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); if (next_o == NULL) { if (_PyErr_Occurred(tstate)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index f1cd3bfe4dec9f..88ff2b6a11ed68 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4347,11 +4347,11 @@ _PyStackRef next; null_or_index = stack_pointer[-1]; iter = stack_pointer[-2]; - PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); if (!PyStackRef_IsNull(null_or_index)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o); stack_pointer = _PyFrame_GetStackPointer(frame); From e5f666d49c0cfefc46851b25e01b67db537fa6b3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 13:30:25 +0100 Subject: [PATCH 13/15] Make functions inline for the JIT --- Include/internal/pycore_range.h | 40 +++++++++++++++++++++++++++--- Objects/rangeobject.c | 43 --------------------------------- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/Include/internal/pycore_range.h b/Include/internal/pycore_range.h index a3c1891692dd21..b547dff6a10dca 100644 --- a/Include/internal/pycore_range.h +++ b/Include/internal/pycore_range.h @@ -8,6 +8,14 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +typedef struct { + PyObject_HEAD + PyObject *start; + PyObject *stop; + PyObject *step; + PyObject *length; +} rangeobject; + typedef struct { PyObject_HEAD long start; @@ -16,9 +24,35 @@ typedef struct { } _PyRangeIterObject; // Does this range have step == 1 and both start and stop in compact int range? -int _PyRange_IsSimpleCompact(PyObject *range); -Py_ssize_t _PyRange_GetStartIfCompact(PyObject *range); -Py_ssize_t _PyRange_GetStopIfCompact(PyObject *range); +static inline int +_PyRange_IsSimpleCompact(PyObject *range) { + assert(PyRange_Check(range)); + rangeobject *r = (rangeobject*)range; + if (_PyLong_IsCompact((PyLongObject *)r->start) && + _PyLong_IsCompact((PyLongObject *)r->stop) && + r->step == _PyLong_GetOne() + ) { + return 1; + } + return 0; +} + +static inline Py_ssize_t +_PyRange_GetStartIfCompact(PyObject *range) +{ + assert(PyRange_Check(range)); + rangeobject *r = (rangeobject*)range; + assert(_PyLong_IsCompact((PyLongObject *)r->start)); + return _PyLong_CompactValue((PyLongObject *)r->start); +} + +static inline Py_ssize_t +_PyRange_GetStopIfCompact(PyObject *range) { + assert(PyRange_Check(range)); + rangeobject *r = (rangeobject*)range; + assert(_PyLong_IsCompact((PyLongObject *)r->stop)); + return _PyLong_CompactValue((PyLongObject *)r->stop); +} #ifdef __cplusplus } diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index e365c8ec36e3df..d074b1b1ce70ff 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -10,21 +10,6 @@ #include "pycore_tuple.h" // _PyTuple_ITEMS() -/* Support objects whose length is > PY_SSIZE_T_MAX. - - This could be sped up for small PyLongs if they fit in a Py_ssize_t. - This only matters on Win64. Though we could use long long which - would presumably help perf. -*/ - -typedef struct { - PyObject_HEAD - PyObject *start; - PyObject *stop; - PyObject *step; - PyObject *length; -} rangeobject; - /* Helper function for validating step. Always returns a new reference or NULL on error. */ @@ -156,34 +141,6 @@ range_vectorcall(PyObject *rangetype, PyObject *const *args, return range_from_array((PyTypeObject *)rangetype, args, nargs); } -int -_PyRange_IsSimpleCompact(PyObject *range) { - assert(PyRange_Check(range)); - rangeobject *r = (rangeobject*)range; - if (_PyLong_IsCompact((PyLongObject *)r->start) && - _PyLong_IsCompact((PyLongObject *)r->stop) && - r->step == _PyLong_GetOne() - ) { - return 1; - } - return 0; -} - -Py_ssize_t -_PyRange_GetStartIfCompact(PyObject *range) { - assert(PyRange_Check(range)); - rangeobject *r = (rangeobject*)range; - assert(_PyLong_IsCompact((PyLongObject *)r->start)); - return _PyLong_CompactValue((PyLongObject *)r->start); -} - -Py_ssize_t -_PyRange_GetStopIfCompact(PyObject *range) { - assert(PyRange_Check(range)); - rangeobject *r = (rangeobject*)range; - assert(_PyLong_IsCompact((PyLongObject *)r->stop)); - return _PyLong_CompactValue((PyLongObject *)r->stop); -} PyDoc_STRVAR(range_doc, "range(stop) -> range object\n\ From 8efce0a27197d87170589a68c92e8227fa8aa6d2 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 3 Jun 2025 15:10:14 +0100 Subject: [PATCH 14/15] Make PyStackRef_BoxInt inline for JIT --- Include/internal/pycore_stackref.h | 16 ++++++++++++++-- Objects/longobject.c | 16 ---------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index a32df79c698b20..dd642717e3cc6a 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -292,8 +292,6 @@ PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b) #define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0) -extern _PyStackRef PyStackRef_BoxInt(_PyStackRef i); - #ifdef Py_GIL_DISABLED #define Py_TAG_DEFERRED Py_TAG_REFCNT @@ -807,6 +805,20 @@ _Py_TryXGetStackRef(PyObject **src, _PyStackRef *out) } \ } while (0) + +static inline _PyStackRef +PyStackRef_BoxInt(_PyStackRef i) +{ + assert(PyStackRef_IsTaggedInt(i)); + intptr_t val = PyStackRef_UntagInt(i); + PyObject *boxed = PyLong_FromSsize_t(val); + if (boxed == NULL) { + return PyStackRef_NULL; + } + return PyStackRef_FromPyObjectSteal(boxed); +} + + #ifdef __cplusplus } #endif diff --git a/Objects/longobject.c b/Objects/longobject.c index 6ff1e84aae69b4..c99a6e995515c6 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6873,19 +6873,3 @@ PyLongWriter_Finish(PyLongWriter *writer) return (PyObject*)obj; } - -// Tagged int support - -_PyStackRef -PyStackRef_BoxInt(_PyStackRef i) -{ - assert((i.bits & Py_INT_TAG) == Py_INT_TAG); - intptr_t val = (intptr_t)i.bits; - val = Py_ARITHMETIC_RIGHT_SHIFT(intptr_t, val, 2); - PyObject *boxed = PyLong_FromSsize_t(val); - if (boxed == NULL) { - return PyStackRef_NULL; - } - return PyStackRef_FromPyObjectSteal(boxed); -} - From 7ba5753feaa475833e4a595bd99bf9da2ddf921b Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 6 Jun 2025 11:28:39 +0100 Subject: [PATCH 15/15] Fix PyStackRef_TaggedIntLessThan for Py_STACKREF_DEBUG --- Python/stackrefs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/stackrefs.c b/Python/stackrefs.c index 023a456d44318d..be517778c67f93 100644 --- a/Python/stackrefs.c +++ b/Python/stackrefs.c @@ -211,7 +211,7 @@ PyStackRef_TaggedIntLessThan(_PyStackRef a, _PyStackRef b) { assert(PyStackRef_IsTaggedInt(a)); assert(PyStackRef_IsTaggedInt(b)); - return a.bits < b.bits; + return ((intptr_t)a.index) < ((intptr_t)b.index); } intptr_t