Skip to content

Commit 58db93d

Browse files
committed
Handle GET_YIELD_FROM_ITER and END_SEND correctly
`GET_YIELD_FROM_ITER` doesn't consume its operand if its a coroutine or generator, so treat it conservatively. `END_SEND` leaves the TOS.
1 parent 220bbf9 commit 58db93d

2 files changed

Lines changed: 29 additions & 10 deletions

File tree

Lib/test/test_peepholer.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,6 +2663,24 @@ def test_set_function_attribute(self):
26632663
]
26642664
self.cfg_optimization_test(insts, expected, consts=[None])
26652665

2666+
def test_get_yield_from_iter(self):
2667+
# GET_YIELD_FROM_ITER may leave its operand on the stack
2668+
insts = [
2669+
("LOAD_FAST", 0, 1),
2670+
("GET_YIELD_FROM_ITER", None, 2),
2671+
("LOAD_CONST", 0, 3),
2672+
send := self.Label(),
2673+
("SEND", end := self.Label(), 5),
2674+
("YIELD_VALUE", 1, 6),
2675+
("RESUME", 2, 7),
2676+
("JUMP", send, 8),
2677+
end,
2678+
("END_SEND", None, 9),
2679+
("LOAD_CONST", 0, 10),
2680+
("RETURN_VALUE", None, 11),
2681+
]
2682+
self.cfg_optimization_test(insts, insts, consts=[None])
2683+
26662684
def test_del_in_finally(self):
26672685
# This loads `obj` onto the stack, executes `del obj`, then returns the
26682686
# `obj` from the stack. See gh-133371 for more details.

Python/flowgraph.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2874,6 +2874,7 @@ optimize_load_fast(cfg_builder *g)
28742874
case GET_ANEXT:
28752875
case GET_ITER:
28762876
case GET_LEN:
2877+
case GET_YIELD_FROM_ITER:
28772878
case IMPORT_FROM:
28782879
case MATCH_KEYS:
28792880
case MATCH_MAPPING:
@@ -2908,6 +2909,16 @@ optimize_load_fast(cfg_builder *g)
29082909
break;
29092910
}
29102911

2912+
case END_SEND:
2913+
case SET_FUNCTION_ATTRIBUTE: {
2914+
assert(_PyOpcode_num_popped(opcode, oparg) == 2);
2915+
assert(_PyOpcode_num_pushed(opcode, oparg) == 1);
2916+
ref tos = ref_stack_pop(&refs);
2917+
ref_stack_pop(&refs);
2918+
PUSH_REF(tos.instr, tos.local);
2919+
break;
2920+
}
2921+
29112922
// Opcodes that consume some inputs and push new values
29122923
case CHECK_EXC_MATCH: {
29132924
ref_stack_pop(&refs);
@@ -2944,16 +2955,6 @@ optimize_load_fast(cfg_builder *g)
29442955
break;
29452956
}
29462957

2947-
case SET_FUNCTION_ATTRIBUTE: {
2948-
assert(_PyOpcode_num_popped(opcode, oparg) == 2);
2949-
assert(_PyOpcode_num_pushed(opcode, oparg) == 1);
2950-
ref func = ref_stack_pop(&refs);
2951-
// Pop attr
2952-
ref_stack_pop(&refs);
2953-
PUSH_REF(func.instr, func.local);
2954-
break;
2955-
}
2956-
29572958
// Opcodes that consume all of their inputs
29582959
default: {
29592960
int num_popped = _PyOpcode_num_popped(opcode, oparg);

0 commit comments

Comments
 (0)