diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 08e6c736d3e3c9d..48058f60090ae2d 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1014,12 +1014,15 @@ iterations of the loop. The oparg is now a relative delta rather than an absolute target. -.. opcode:: FOR_ITER (delta) +.. opcode:: FOR_END (delta) TOS is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If this yields a new value, push it on the stack (leaving the iterator below - it). If the iterator indicates it is exhausted, TOS is popped, and the byte - code counter is incremented by *delta*. + it), then decrement the bytecode counter by *delta*. If the iterator + indicates it is exhausted, then pop TOS and do not decrement the bytecode + counter. + + .. versionadded:: 3.11 .. opcode:: LOAD_GLOBAL (namei) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index ba85b7896b2c0e1..21f2da598d692bd 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -978,6 +978,12 @@ CPython bytecode changes relative rather than absolute. +* Replaced :opcode:`FOR_ITER` (jumps if iterator exhausted) + with :opcode:`FOR_END` (jumps if iterator is not exhausted). + At the end of each ``for``-loop iteration, instead of an unconditional + jump targeted at a conditional jump, there is now + only one (conditional) jump. + Deprecated ========== diff --git a/Include/opcode.h b/Include/opcode.h index 89f56e27ed43725..f2496d285af98fc 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -49,7 +49,6 @@ extern "C" { #define STORE_NAME 90 #define DELETE_NAME 91 #define UNPACK_SEQUENCE 92 -#define FOR_ITER 93 #define UNPACK_EX 94 #define STORE_ATTR 95 #define DELETE_ATTR 96 @@ -118,6 +117,7 @@ extern "C" { #define POP_JUMP_BACKWARD_IF_NONE 174 #define POP_JUMP_BACKWARD_IF_FALSE 175 #define POP_JUMP_BACKWARD_IF_TRUE 176 +#define FOR_END 177 #define BINARY_OP_ADAPTIVE 3 #define BINARY_OP_ADD_FLOAT 4 #define BINARY_OP_ADD_INT 5 @@ -140,36 +140,37 @@ extern "C" { #define COMPARE_OP_INT_JUMP 28 #define COMPARE_OP_STR_JUMP 29 #define JUMP_BACKWARD_QUICK 34 -#define LOAD_ATTR_ADAPTIVE 38 -#define LOAD_ATTR_INSTANCE_VALUE 39 -#define LOAD_ATTR_MODULE 40 -#define LOAD_ATTR_SLOT 41 -#define LOAD_ATTR_WITH_HINT 42 -#define LOAD_CONST__LOAD_FAST 43 -#define LOAD_FAST__LOAD_CONST 44 -#define LOAD_FAST__LOAD_FAST 45 -#define LOAD_GLOBAL_ADAPTIVE 46 -#define LOAD_GLOBAL_BUILTIN 47 -#define LOAD_GLOBAL_MODULE 48 -#define LOAD_METHOD_ADAPTIVE 55 -#define LOAD_METHOD_CLASS 56 -#define LOAD_METHOD_MODULE 57 -#define LOAD_METHOD_NO_DICT 58 -#define LOAD_METHOD_WITH_DICT 59 -#define LOAD_METHOD_WITH_VALUES 62 -#define PRECALL_ADAPTIVE 63 -#define PRECALL_BOUND_METHOD 64 -#define PRECALL_BUILTIN_CLASS 65 -#define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 66 -#define PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 67 -#define PRECALL_NO_KW_BUILTIN_FAST 72 -#define PRECALL_NO_KW_BUILTIN_O 73 -#define PRECALL_NO_KW_ISINSTANCE 76 -#define PRECALL_NO_KW_LEN 77 -#define PRECALL_NO_KW_LIST_APPEND 78 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 79 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 80 -#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 81 +#define FOR_END_QUICK 38 +#define LOAD_ATTR_ADAPTIVE 39 +#define LOAD_ATTR_INSTANCE_VALUE 40 +#define LOAD_ATTR_MODULE 41 +#define LOAD_ATTR_SLOT 42 +#define LOAD_ATTR_WITH_HINT 43 +#define LOAD_CONST__LOAD_FAST 44 +#define LOAD_FAST__LOAD_CONST 45 +#define LOAD_FAST__LOAD_FAST 46 +#define LOAD_GLOBAL_ADAPTIVE 47 +#define LOAD_GLOBAL_BUILTIN 48 +#define LOAD_GLOBAL_MODULE 55 +#define LOAD_METHOD_ADAPTIVE 56 +#define LOAD_METHOD_CLASS 57 +#define LOAD_METHOD_MODULE 58 +#define LOAD_METHOD_NO_DICT 59 +#define LOAD_METHOD_WITH_DICT 62 +#define LOAD_METHOD_WITH_VALUES 63 +#define PRECALL_ADAPTIVE 64 +#define PRECALL_BOUND_METHOD 65 +#define PRECALL_BUILTIN_CLASS 66 +#define PRECALL_BUILTIN_FAST_WITH_KEYWORDS 67 +#define PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 72 +#define PRECALL_NO_KW_BUILTIN_FAST 73 +#define PRECALL_NO_KW_BUILTIN_O 76 +#define PRECALL_NO_KW_ISINSTANCE 77 +#define PRECALL_NO_KW_LEN 78 +#define PRECALL_NO_KW_LIST_APPEND 79 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 80 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 81 +#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 93 #define PRECALL_NO_KW_STR_1 113 #define PRECALL_NO_KW_TUPLE_1 121 #define PRECALL_NO_KW_TYPE_1 127 @@ -185,9 +186,9 @@ extern "C" { #define STORE_SUBSCR_DICT 168 #define STORE_SUBSCR_LIST_INT 169 #define UNPACK_SEQUENCE_ADAPTIVE 170 -#define UNPACK_SEQUENCE_LIST 177 -#define UNPACK_SEQUENCE_TUPLE 178 -#define UNPACK_SEQUENCE_TWO_TUPLE 179 +#define UNPACK_SEQUENCE_LIST 178 +#define UNPACK_SEQUENCE_TUPLE 179 +#define UNPACK_SEQUENCE_TWO_TUPLE 180 #define DO_TRACING 255 extern const uint8_t _PyOpcode_Caches[256]; @@ -198,20 +199,20 @@ extern const uint8_t _PyOpcode_Deopt[256]; static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 0U, - 536870912U, + 0U, 135118848U, 4163U, - 122880U, + 253952U, 0U, 0U, }; static const uint32_t _PyOpcode_Jump[8] = { 0U, 0U, - 536870912U, + 0U, 135118848U, 4163U, - 122880U, + 253952U, 0U, 0U, }; @@ -284,7 +285,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [END_ASYNC_FOR] = END_ASYNC_FOR, [EXTENDED_ARG] = EXTENDED_ARG, [FORMAT_VALUE] = FORMAT_VALUE, - [FOR_ITER] = FOR_ITER, + [FOR_END] = FOR_END, + [FOR_END_QUICK] = FOR_END, [GET_AITER] = GET_AITER, [GET_ANEXT] = GET_ANEXT, [GET_AWAITABLE] = GET_AWAITABLE, @@ -486,6 +488,7 @@ static const char *const _PyOpcode_OpName[256] = { [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [FOR_END_QUICK] = "FOR_END_QUICK", [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", @@ -496,40 +499,39 @@ static const char *const _PyOpcode_OpName[256] = { [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [LOAD_METHOD_ADAPTIVE] = "LOAD_METHOD_ADAPTIVE", [LOAD_METHOD_CLASS] = "LOAD_METHOD_CLASS", [LOAD_METHOD_MODULE] = "LOAD_METHOD_MODULE", [LOAD_METHOD_NO_DICT] = "LOAD_METHOD_NO_DICT", - [LOAD_METHOD_WITH_DICT] = "LOAD_METHOD_WITH_DICT", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [LOAD_METHOD_WITH_DICT] = "LOAD_METHOD_WITH_DICT", [LOAD_METHOD_WITH_VALUES] = "LOAD_METHOD_WITH_VALUES", [PRECALL_ADAPTIVE] = "PRECALL_ADAPTIVE", [PRECALL_BOUND_METHOD] = "PRECALL_BOUND_METHOD", [PRECALL_BUILTIN_CLASS] = "PRECALL_BUILTIN_CLASS", [PRECALL_BUILTIN_FAST_WITH_KEYWORDS] = "PRECALL_BUILTIN_FAST_WITH_KEYWORDS", - [PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [PRECALL_NO_KW_BUILTIN_FAST] = "PRECALL_NO_KW_BUILTIN_FAST", - [PRECALL_NO_KW_BUILTIN_O] = "PRECALL_NO_KW_BUILTIN_O", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [PRECALL_NO_KW_BUILTIN_O] = "PRECALL_NO_KW_BUILTIN_O", [PRECALL_NO_KW_ISINSTANCE] = "PRECALL_NO_KW_ISINSTANCE", [PRECALL_NO_KW_LEN] = "PRECALL_NO_KW_LEN", [PRECALL_NO_KW_LIST_APPEND] = "PRECALL_NO_KW_LIST_APPEND", [PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST", [PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - [PRECALL_NO_KW_METHOD_DESCRIPTOR_O] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_O", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", @@ -541,7 +543,7 @@ static const char *const _PyOpcode_OpName[256] = { [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE", - [FOR_ITER] = "FOR_ITER", + [PRECALL_NO_KW_METHOD_DESCRIPTOR_O] = "PRECALL_NO_KW_METHOD_DESCRIPTOR_O", [UNPACK_EX] = "UNPACK_EX", [STORE_ATTR] = "STORE_ATTR", [DELETE_ATTR] = "DELETE_ATTR", @@ -625,10 +627,10 @@ static const char *const _PyOpcode_OpName[256] = { [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", + [FOR_END] = "FOR_END", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [180] = "<180>", [181] = "<181>", [182] = "<182>", [183] = "<183>", @@ -708,7 +710,6 @@ static const char *const _PyOpcode_OpName[256] = { #endif #define EXTRA_CASES \ - case 180: \ case 181: \ case 182: \ case 183: \ diff --git a/Lib/dis.py b/Lib/dis.py index 205e9d8d193f32b..4224754b67c2148 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -30,7 +30,6 @@ LOAD_CONST = opmap['LOAD_CONST'] LOAD_GLOBAL = opmap['LOAD_GLOBAL'] BINARY_OP = opmap['BINARY_OP'] -JUMP_BACKWARD = opmap['JUMP_BACKWARD'] CACHE = opmap["CACHE"] @@ -412,7 +411,8 @@ def parse_exception_table(code): return entries def _is_backward_jump(op): - return 'JUMP_BACKWARD' in opname[op] + name = opname[op] + return 'JUMP_BACKWARD' in name or name == "FOR_END" def _get_instructions_bytes(code, varname_from_oparg=None, names=None, co_consts=None, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 71e1e24b51e22d2..5f67226adfc5223 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -416,7 +416,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3493).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3494).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 9ee06831c376875..a96dd3d6eca16ca 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -111,7 +111,6 @@ def jabs_op(name, op, entries=0): name_op('STORE_NAME', 90) # Index in name list name_op('DELETE_NAME', 91) # "" def_op('UNPACK_SEQUENCE', 92, 1) # Number of tuple items -jrel_op('FOR_ITER', 93) def_op('UNPACK_EX', 94) name_op('STORE_ATTR', 95, 4) # Index in name list name_op('DELETE_ATTR', 96) # "" @@ -201,6 +200,7 @@ def jabs_op(name, op, entries=0): jrel_op('POP_JUMP_BACKWARD_IF_NONE', 174) jrel_op('POP_JUMP_BACKWARD_IF_FALSE', 175) jrel_op('POP_JUMP_BACKWARD_IF_TRUE', 176) +jrel_op('FOR_END', 177) del def_op, name_op, jrel_op, jabs_op @@ -267,6 +267,9 @@ def jabs_op(name, op, entries=0): "JUMP_BACKWARD": [ "JUMP_BACKWARD_QUICK", ], + "FOR_END": [ + "FOR_END_QUICK", + ], "LOAD_ATTR": [ "LOAD_ATTR_ADAPTIVE", "LOAD_ATTR_INSTANCE_VALUE", diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 2a4c0d2eeb656ab..183217a91ef39eb 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -37,10 +37,10 @@ def test_stack_effect_jump(self): self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0), 0) self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=True), 0) self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1) - FOR_ITER = dis.opmap['FOR_ITER'] - self.assertEqual(stack_effect(FOR_ITER, 0), 1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), -1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), 1) + FOR_END = dis.opmap['FOR_END'] + self.assertEqual(stack_effect(FOR_END, 0), 1) + self.assertEqual(stack_effect(FOR_END, 0, jump=True), 1) + self.assertEqual(stack_effect(FOR_END, 0, jump=False), -1) JUMP_FORWARD = dis.opmap['JUMP_FORWARD'] self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0) self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=True), 0) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 0bd589d5cfb6f24..1875049ec656d26 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -146,12 +146,13 @@ def bug708901(): %3d PRECALL 2 CALL 2 GET_ITER - >> FOR_ITER 2 (to 40) - STORE_FAST 0 (res) + JUMP_FORWARD 2 (to 40) + >> STORE_FAST 0 (res) -%3d JUMP_BACKWARD 3 (to 34) +%3d NOP -%3d >> LOAD_CONST 0 (None) +%3d >> FOR_END 3 (to 36) + LOAD_CONST 0 (None) RETURN_VALUE """ % (bug708901.__code__.co_firstlineno, bug708901.__code__.co_firstlineno + 1, @@ -569,14 +570,14 @@ def foo(x): %3d RESUME 0 BUILD_LIST 0 LOAD_FAST 0 (.0) - >> FOR_ITER 7 (to 24) - STORE_FAST 1 (z) + JUMP_FORWARD 6 (to 22) + >> STORE_FAST 1 (z) LOAD_DEREF 2 (x) LOAD_FAST 1 (z) BINARY_OP 0 (+) LIST_APPEND 2 - JUMP_BACKWARD 8 (to 8) - >> RETURN_VALUE + >> FOR_END 7 (to 10) + RETURN_VALUE """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, @@ -616,7 +617,7 @@ def loop_test(): 8 LOAD_CONST 2 (3) 10 BINARY_OP_ADAPTIVE 5 (*) 14 GET_ITER - 16 FOR_ITER 17 (to 52) + 16 JUMP_FORWARD 16 (to 50) 18 STORE_FAST 0 (i) %3d 20 LOAD_GLOBAL_MODULE 1 (NULL + load_test) @@ -624,9 +625,9 @@ def loop_test(): 34 PRECALL_PYFUNC 1 38 CALL_PY_WITH_DEFAULTS 1 48 POP_TOP - 50 JUMP_BACKWARD_QUICK 18 (to 16) -%3d >> 52 LOAD_CONST 0 (None) +%3d >> 50 FOR_END_QUICK 17 (to 18) + 52 LOAD_CONST 0 (None) 54 RETURN_VALUE """ % (loop_test.__code__.co_firstlineno, loop_test.__code__.co_firstlineno + 1, @@ -1352,8 +1353,8 @@ def _prepare_test_cases(): Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=98, argrepr='to 98', offset=32, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=34, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=96, argrepr='to 96', offset=32, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=34, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=36, starts_line=4, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=48, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), @@ -1370,8 +1371,8 @@ def _prepare_test_cases(): Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=2, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None), + Instruction(opname='FOR_END', opcode=177, arg=32, argval=34, argrepr='to 34', offset=96, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 6a2f550d67052a0..f486ba97699d7fe 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -510,16 +510,16 @@ def f(x): def test_assignment_idiom_in_comprehensions(self): def listcomp(): return [y for x in a for y in [f(x)]] - self.assertEqual(count_instr_recursively(listcomp, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(listcomp, 'FOR_END'), 1) def setcomp(): return {y for x in a for y in [f(x)]} - self.assertEqual(count_instr_recursively(setcomp, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(setcomp, 'FOR_END'), 1) def dictcomp(): return {y: y for x in a for y in [f(x)]} - self.assertEqual(count_instr_recursively(dictcomp, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(dictcomp, 'FOR_END'), 1) def genexpr(): return (y for x in a for y in [f(x)]) - self.assertEqual(count_instr_recursively(genexpr, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(genexpr, 'FOR_END'), 1) def test_format_combinations(self): flags = '-+ #0' diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst new file mode 100644 index 000000000000000..c57e4eb22f4342c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst @@ -0,0 +1,5 @@ +Replaced the ``FOR_ITER`` opcode that lived at the top of ``for``-loops with a +``FOR_END`` opcode that lives at the bottom. This form of `Loop Inversion +`_ replaces the (unconditional +jump, conditional jump) pair with just one conditional jump during most +iterations. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 7278ca147490f61..67b385c4701c0fe 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -273,11 +273,14 @@ mark_stacks(PyCodeObject *code_obj, int len) next_stack = push_value(pop_value(next_stack), Iterator); stacks[i+1] = next_stack; break; - case FOR_ITER: + case FOR_END: { - int64_t target_stack = pop_value(next_stack); - stacks[i+1] = push_value(next_stack, Object); - j = get_arg(code, i) + i + 1; + int64_t target_stack = push_value(next_stack, Object); + stacks[i+1] = pop_value(next_stack); + j = i + 1 - get_arg(code, i); + if (stacks[j] == UNINITIALIZED && j < i) { + todo = 1; + } assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; @@ -584,7 +587,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore } else if (err < 0) { if (start_stack == OVERFLOWED) { - msg = "stack to deep to analyze"; + msg = "stack too deep to analyze"; } else if (start_stack == UNINITIALIZED) { msg = "can't jump from within an exception handler"; diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 3034927d7a12b9f..222c3de6d64be0d 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -9,10 +9,10 @@ unsigned char M_test_frozenmain[] = { 0,0,1,0,2,0,101,1,106,4,0,0,0,0,0,0, 0,0,166,0,0,0,171,0,0,0,0,0,0,0,0,0, 100,4,25,0,0,0,0,0,0,0,0,0,90,5,100,5, - 68,0,93,25,90,6,2,0,101,2,100,6,101,6,155,0, + 68,0,110,24,90,6,2,0,101,2,100,6,101,6,155,0, 100,7,101,5,101,6,25,0,0,0,0,0,0,0,0,0, 155,0,157,4,166,1,0,0,171,1,0,0,0,0,0,0, - 0,0,1,0,140,26,100,1,83,0,41,8,233,0,0,0, + 0,0,1,0,177,25,100,1,83,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,41,5,90,12,112,114,111,103, @@ -28,7 +28,7 @@ unsigned char M_test_frozenmain[] = { 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8, 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0, - 0,115,152,0,0,0,248,240,6,0,1,11,128,10,128,10, + 0,115,154,0,0,0,248,240,6,0,1,11,128,10,128,10, 128,10,216,0,24,208,0,24,208,0,24,208,0,24,224,0, 5,128,5,208,6,26,209,0,27,212,0,27,208,0,27,216, 0,5,128,5,128,106,144,35,148,40,209,0,27,212,0,27, @@ -37,6 +37,6 @@ unsigned char M_test_frozenmain[] = { 7,1,42,240,0,7,1,42,128,67,240,14,0,5,10,128, 69,208,10,40,144,67,208,10,40,208,10,40,152,54,160,35, 156,59,208,10,40,208,10,40,209,4,41,212,4,41,208,4, - 41,208,4,41,240,15,7,1,42,240,0,7,1,42,114,9, - 0,0,0, + 41,240,15,6,12,2,240,0,6,12,2,240,0,6,12,2, + 114,9,0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index 90068bc51a7f6a1..79aa1135fad4921 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4044,6 +4044,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(JUMP_FORWARD) { + PREDICTED(JUMP_FORWARD); JUMPBY(oparg); DISPATCH(); } @@ -4348,7 +4349,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int SET_TOP(iter); if (iter == NULL) goto error; - PREDICT(FOR_ITER); + PREDICT(JUMP_FORWARD); DISPATCH(); } @@ -4381,18 +4382,25 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(FOR_ITER) { - PREDICTED(FOR_ITER); + TARGET(FOR_END) { /* before: [iter]; after: [iter, iter()] *or* [] */ + _PyCode_Warmup(frame->f_code); + JUMP_TO_INSTRUCTION(FOR_END_QUICK); + } + + TARGET(FOR_END_QUICK) { + PREDICTED(FOR_END_QUICK); PyObject *iter = TOP(); #ifdef Py_STATS extern int _PySpecialization_ClassifyIterator(PyObject *); - _py_stats.opcode_stats[FOR_ITER].specialization.failure++; - _py_stats.opcode_stats[FOR_ITER].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++; + _py_stats.opcode_stats[FOR_END].specialization.failure++; + _py_stats.opcode_stats[FOR_END].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++; #endif PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next != NULL) { PUSH(next); + JUMPBY(-oparg); + CHECK_EVAL_BREAKER(); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); DISPATCH(); @@ -4409,7 +4417,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* iterator ended normally */ STACK_SHRINK(1); Py_DECREF(iter); - JUMPBY(oparg); DISPATCH(); } @@ -6937,13 +6944,20 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, return -1; } if (line != -1 && f->f_trace_lines) { - /* Trace backward edges (except in 'yield from') or if line number has changed */ - int trace = line != lastline || - (_PyInterpreterFrame_LASTI(frame) < instr_prev && - // SEND has no quickened forms, so no need to use _PyOpcode_Deopt - // here: - _Py_OPCODE(*frame->prev_instr) != SEND); - if (trace) { + int prev_op = _PyOpcode_Deopt[_Py_OPCODE(code[instr_prev])]; + int next_op = _PyOpcode_Deopt[_Py_OPCODE(*frame->prev_instr)]; + // Trace before FOR_END, not after, even though a backwards + // jump happens after. However, don't trace on the first FOR_END + // of the for loop, since we're staying on the same line. + // Also don't trace JUMP_NO_INTERRUPT --> SEND. + bool line_number_changed = (line != lastline); + bool first_iteration = (next_op == FOR_END && + prev_op == JUMP_FORWARD && + !line_number_changed); + bool for_loop_end = (next_op == FOR_END && !first_iteration); + bool back_jump = (_PyInterpreterFrame_LASTI(frame) < instr_prev && + next_op != SEND && prev_op != FOR_END); + if (line_number_changed || for_loop_end || back_jump) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } } diff --git a/Python/compile.c b/Python/compile.c index d66ee17293ac6e9..ed11d056dc73928 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -121,7 +121,8 @@ (opcode) == POP_JUMP_BACKWARD_IF_NONE || \ (opcode) == POP_JUMP_BACKWARD_IF_NOT_NONE || \ (opcode) == POP_JUMP_BACKWARD_IF_TRUE || \ - (opcode) == POP_JUMP_BACKWARD_IF_FALSE) + (opcode) == POP_JUMP_BACKWARD_IF_FALSE || \ + (opcode) == FOR_END) #define IS_TOP_LEVEL_AWAIT(c) ( \ @@ -1005,9 +1006,9 @@ stack_effect(int opcode, int oparg, int jump) return oparg-1; case UNPACK_EX: return (oparg&0xFF) + (oparg>>8); - case FOR_ITER: + case FOR_END: /* -1 at end of iterator, 1 if continue iterating. */ - return jump > 0 ? -1 : 1; + return jump == 0 ? -1 : 1; case SEND: return jump > 0 ? -1 : 0; case STORE_ATTR: @@ -3085,13 +3086,16 @@ compiler_if(struct compiler *c, stmt_ty s) static int compiler_for(struct compiler *c, stmt_ty s) { - basicblock *start, *body, *cleanup, *end; + basicblock *start, *body, *cleanup, *end, *back_jump; start = compiler_new_block(c); body = compiler_new_block(c); cleanup = compiler_new_block(c); + back_jump = compiler_new_block(c); end = compiler_new_block(c); - if (start == NULL || body == NULL || end == NULL || cleanup == NULL) { + if (start == NULL || body == NULL || end == NULL || + cleanup == NULL || back_jump == NULL) + { return 0; } if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) { @@ -3100,15 +3104,14 @@ compiler_for(struct compiler *c, stmt_ty s) VISIT(c, expr, s->v.For.iter); ADDOP(c, GET_ITER); compiler_use_next_block(c, start); - ADDOP_JUMP(c, FOR_ITER, cleanup); + ADDOP_JUMP_NOLINE(c, JUMP, back_jump); compiler_use_next_block(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); - /* Mark jump as artificial */ - UNSET_LOC(c); - ADDOP_JUMP(c, JUMP, start); + compiler_use_next_block(c, back_jump); + SET_LOC(c, s->v.For.iter); + ADDOP_JUMP(c, FOR_END, body); compiler_use_next_block(c, cleanup); - compiler_pop_fblock(c, FOR_LOOP, start); VISIT_SEQ(c, stmt, s->v.For.orelse); @@ -5172,14 +5175,15 @@ compiler_sync_comprehension_generator(struct compiler *c, and then write to the element */ comprehension_ty gen; - basicblock *start, *anchor, *if_cleanup; + basicblock *start, *anchor, *if_cleanup, *body; Py_ssize_t i, n; start = compiler_new_block(c); if_cleanup = compiler_new_block(c); anchor = compiler_new_block(c); + body = compiler_new_block(c); - if (start == NULL || if_cleanup == NULL || anchor == NULL) { + if (start == NULL || if_cleanup == NULL || anchor == NULL || body == NULL) { return 0; } @@ -5221,7 +5225,8 @@ compiler_sync_comprehension_generator(struct compiler *c, if (start) { depth++; compiler_use_next_block(c, start); - ADDOP_JUMP(c, FOR_ITER, anchor); + ADDOP_JUMP_NOLINE(c, JUMP, if_cleanup); + compiler_use_next_block(c, body); } VISIT(c, expr, gen->target); @@ -5269,7 +5274,7 @@ compiler_sync_comprehension_generator(struct compiler *c, } compiler_use_next_block(c, if_cleanup); if (start) { - ADDOP_JUMP(c, JUMP, start); + ADDOP_JUMP(c, FOR_END, body); compiler_use_next_block(c, anchor); } @@ -8920,16 +8925,10 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) i -= jump_thread(inst, target, JUMP); } break; - case FOR_ITER: - if (target->i_opcode == JUMP) { - /* This will not work now because the jump (at target) could - * be forward or backward and FOR_ITER only jumps forward. We - * can re-enable this if ever we implement a backward version - * of FOR_ITER. - */ - /* - i -= jump_thread(inst, target, FOR_ITER); - */ + case FOR_END: + switch (target->i_opcode) { + case JUMP: + i -= jump_thread(inst, target, FOR_END); } break; case SWAP: @@ -9061,7 +9060,7 @@ normalize_basic_block(basicblock *bb) { case POP_JUMP_IF_TRUE: case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: - case FOR_ITER: + case FOR_END: if (i != bb->b_iused-1) { PyErr_SetString(PyExc_SystemError, "malformed control flow graph."); return -1; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 5268c4f2a277502..45ea86bd100c39c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -37,6 +37,7 @@ static void *opcode_targets[256] = { &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_FOR_END_QUICK, &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, @@ -47,40 +48,39 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_LOAD_METHOD_CLASS, &&TARGET_LOAD_METHOD_MODULE, &&TARGET_LOAD_METHOD_NO_DICT, - &&TARGET_LOAD_METHOD_WITH_DICT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_METHOD_WITH_DICT, &&TARGET_LOAD_METHOD_WITH_VALUES, &&TARGET_PRECALL_ADAPTIVE, &&TARGET_PRECALL_BOUND_METHOD, &&TARGET_PRECALL_BUILTIN_CLASS, &&TARGET_PRECALL_BUILTIN_FAST_WITH_KEYWORDS, - &&TARGET_PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_PRECALL_NO_KW_BUILTIN_FAST, - &&TARGET_PRECALL_NO_KW_BUILTIN_O, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_PRECALL_NO_KW_BUILTIN_O, &&TARGET_PRECALL_NO_KW_ISINSTANCE, &&TARGET_PRECALL_NO_KW_LEN, &&TARGET_PRECALL_NO_KW_LIST_APPEND, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, - &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, @@ -92,7 +92,7 @@ static void *opcode_targets[256] = { &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, &&TARGET_UNPACK_SEQUENCE, - &&TARGET_FOR_ITER, + &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_UNPACK_EX, &&TARGET_STORE_ATTR, &&TARGET_DELETE_ATTR, @@ -176,6 +176,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_BACKWARD_IF_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_FALSE, &&TARGET_POP_JUMP_BACKWARD_IF_TRUE, + &&TARGET_FOR_END, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, @@ -253,6 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; diff --git a/Python/specialize.c b/Python/specialize.c index 3a8b768549c63d2..38325602c14a8f7 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -141,7 +141,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats) { /* Mark some opcodes as specializable for stats, * even though we don't specialize them yet. */ - fprintf(out, "opcode[%d].specializable : 1\n", FOR_ITER); + fprintf(out, "opcode[%d].specializable : 1\n", FOR_END); for (int i = 0; i < 256; i++) { if (_PyOpcode_Adaptive[i]) { fprintf(out, "opcode[%d].specializable : 1\n", i); @@ -273,6 +273,9 @@ _PyCode_Quicken(PyCodeObject *code) case JUMP_BACKWARD: _Py_SET_OPCODE(instructions[i], JUMP_BACKWARD_QUICK); break; + case FOR_END: + _Py_SET_OPCODE(instructions[i], FOR_END_QUICK); + break; case RESUME: _Py_SET_OPCODE(instructions[i], RESUME_QUICK); break; @@ -451,21 +454,21 @@ initial_counter_value(void) { #define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 23 #define SPEC_FAIL_COMPARE_OP_EXTENDED_ARG 24 -/* FOR_ITER */ -#define SPEC_FAIL_FOR_ITER_GENERATOR 10 -#define SPEC_FAIL_FOR_ITER_COROUTINE 11 -#define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12 -#define SPEC_FAIL_FOR_ITER_LIST 13 -#define SPEC_FAIL_FOR_ITER_TUPLE 14 -#define SPEC_FAIL_FOR_ITER_SET 15 -#define SPEC_FAIL_FOR_ITER_STRING 16 -#define SPEC_FAIL_FOR_ITER_BYTES 17 -#define SPEC_FAIL_FOR_ITER_RANGE 18 -#define SPEC_FAIL_FOR_ITER_ITERTOOLS 19 -#define SPEC_FAIL_FOR_ITER_DICT_KEYS 20 -#define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21 -#define SPEC_FAIL_FOR_ITER_DICT_VALUES 22 -#define SPEC_FAIL_FOR_ITER_ENUMERATE 23 +/* FOR_END */ +#define SPEC_FAIL_FOR_END_GENERATOR 10 +#define SPEC_FAIL_FOR_END_COROUTINE 11 +#define SPEC_FAIL_FOR_END_ASYNC_GENERATOR 12 +#define SPEC_FAIL_FOR_END_LIST 13 +#define SPEC_FAIL_FOR_END_TUPLE 14 +#define SPEC_FAIL_FOR_END_SET 15 +#define SPEC_FAIL_FOR_END_STRING 16 +#define SPEC_FAIL_FOR_END_BYTES 17 +#define SPEC_FAIL_FOR_END_RANGE 18 +#define SPEC_FAIL_FOR_END_ITERTOOLS 19 +#define SPEC_FAIL_FOR_END_DICT_KEYS 20 +#define SPEC_FAIL_FOR_END_DICT_ITEMS 21 +#define SPEC_FAIL_FOR_END_DICT_VALUES 22 +#define SPEC_FAIL_FOR_END_ENUMERATE 23 // UNPACK_SEQUENCE @@ -2009,48 +2012,48 @@ int _PySpecialization_ClassifyIterator(PyObject *iter) { if (PyGen_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_GENERATOR; + return SPEC_FAIL_FOR_END_GENERATOR; } if (PyCoro_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_COROUTINE; + return SPEC_FAIL_FOR_END_COROUTINE; } if (PyAsyncGen_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR; + return SPEC_FAIL_FOR_END_ASYNC_GENERATOR; } PyTypeObject *t = Py_TYPE(iter); if (t == &PyListIter_Type) { - return SPEC_FAIL_FOR_ITER_LIST; + return SPEC_FAIL_FOR_END_LIST; } if (t == &PyTupleIter_Type) { - return SPEC_FAIL_FOR_ITER_TUPLE; + return SPEC_FAIL_FOR_END_TUPLE; } if (t == &PyDictIterKey_Type) { - return SPEC_FAIL_FOR_ITER_DICT_KEYS; + return SPEC_FAIL_FOR_END_DICT_KEYS; } if (t == &PyDictIterValue_Type) { - return SPEC_FAIL_FOR_ITER_DICT_VALUES; + return SPEC_FAIL_FOR_END_DICT_VALUES; } if (t == &PyDictIterItem_Type) { - return SPEC_FAIL_FOR_ITER_DICT_ITEMS; + return SPEC_FAIL_FOR_END_DICT_ITEMS; } if (t == &PySetIter_Type) { - return SPEC_FAIL_FOR_ITER_SET; + return SPEC_FAIL_FOR_END_SET; } if (t == &PyUnicodeIter_Type) { - return SPEC_FAIL_FOR_ITER_STRING; + return SPEC_FAIL_FOR_END_STRING; } if (t == &PyBytesIter_Type) { - return SPEC_FAIL_FOR_ITER_BYTES; + return SPEC_FAIL_FOR_END_BYTES; } if (t == &PyRangeIter_Type) { - return SPEC_FAIL_FOR_ITER_RANGE; + return SPEC_FAIL_FOR_END_RANGE; } if (t == &PyEnum_Type) { - return SPEC_FAIL_FOR_ITER_ENUMERATE; + return SPEC_FAIL_FOR_END_ENUMERATE; } if (strncmp(t->tp_name, "itertools", 8) == 0) { - return SPEC_FAIL_FOR_ITER_ITERTOOLS; + return SPEC_FAIL_FOR_END_ITERTOOLS; } return SPEC_FAIL_OTHER; }