mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
GH-112354: END_FOR
instruction to only pop one value. (GH-114247)
* Compiler emits END_FOR; POP_TOP instead of END_FOR. To support tier 2 side exits in loops.
This commit is contained in:
parent
6fadd68da5
commit
981d172f7f
16 changed files with 238 additions and 184 deletions
|
@ -265,9 +265,9 @@ dummy_func(
|
|||
res = NULL;
|
||||
}
|
||||
|
||||
macro(END_FOR) = POP_TOP + POP_TOP;
|
||||
macro(END_FOR) = POP_TOP;
|
||||
|
||||
inst(INSTRUMENTED_END_FOR, (receiver, value --)) {
|
||||
inst(INSTRUMENTED_END_FOR, (receiver, value -- receiver)) {
|
||||
TIER_ONE_ONLY
|
||||
/* Need to create a fake StopIteration error here,
|
||||
* to conform to PEP 380 */
|
||||
|
@ -2550,8 +2550,8 @@ dummy_func(
|
|||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
|
||||
Py_DECREF(iter);
|
||||
STACK_SHRINK(1);
|
||||
/* Jump forward oparg, then skip following END_FOR instruction */
|
||||
JUMPBY(oparg + 1);
|
||||
/* Jump forward oparg, then skip following END_FOR and POP_TOP instruction */
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
// Common case: no jump, leave it to the code generator
|
||||
|
@ -2599,8 +2599,8 @@ dummy_func(
|
|||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
|
||||
STACK_SHRINK(1);
|
||||
Py_DECREF(iter);
|
||||
/* Skip END_FOR */
|
||||
target = next_instr + oparg + 1;
|
||||
/* Skip END_FOR and POP_TOP */
|
||||
target = next_instr + oparg + 2;
|
||||
}
|
||||
INSTRUMENTED_JUMP(this_instr, target, PY_MONITORING_EVENT_BRANCH);
|
||||
}
|
||||
|
@ -2621,8 +2621,8 @@ dummy_func(
|
|||
}
|
||||
Py_DECREF(iter);
|
||||
STACK_SHRINK(1);
|
||||
/* Jump forward oparg, then skip following END_FOR instruction */
|
||||
JUMPBY(oparg + 1);
|
||||
/* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
}
|
||||
|
@ -2667,8 +2667,8 @@ dummy_func(
|
|||
}
|
||||
Py_DECREF(iter);
|
||||
STACK_SHRINK(1);
|
||||
/* Jump forward oparg, then skip following END_FOR instruction */
|
||||
JUMPBY(oparg + 1);
|
||||
/* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
}
|
||||
|
@ -2709,8 +2709,8 @@ dummy_func(
|
|||
if (r->len <= 0) {
|
||||
STACK_SHRINK(1);
|
||||
Py_DECREF(r);
|
||||
// Jump over END_FOR instruction.
|
||||
JUMPBY(oparg + 1);
|
||||
// Jump over END_FOR and POP_TOP instructions.
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3075,7 +3075,12 @@ compiler_for(struct compiler *c, stmt_ty s)
|
|||
ADDOP_JUMP(c, NO_LOCATION, JUMP, start);
|
||||
|
||||
USE_LABEL(c, cleanup);
|
||||
/* It is important for instrumentation that the `END_FOR` comes first.
|
||||
* Iteration over a generator will jump to the first of these instructions,
|
||||
* but a non-generator will jump to a later instruction.
|
||||
*/
|
||||
ADDOP(c, NO_LOCATION, END_FOR);
|
||||
ADDOP(c, NO_LOCATION, POP_TOP);
|
||||
|
||||
compiler_pop_fblock(c, FOR_LOOP, start);
|
||||
|
||||
|
@ -5390,7 +5395,12 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
|
|||
ADDOP_JUMP(c, elt_loc, JUMP, start);
|
||||
|
||||
USE_LABEL(c, anchor);
|
||||
/* It is important for instrumentation that the `END_FOR` comes first.
|
||||
* Iteration over a generator will jump to the first of these instructions,
|
||||
* but a non-generator will jump to a later instruction.
|
||||
*/
|
||||
ADDOP(c, NO_LOCATION, END_FOR);
|
||||
ADDOP(c, NO_LOCATION, POP_TOP);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
|
35
Python/generated_cases.c.h
generated
35
Python/generated_cases.c.h
generated
|
@ -2342,17 +2342,9 @@
|
|||
next_instr += 1;
|
||||
INSTRUCTION_STATS(END_FOR);
|
||||
PyObject *value;
|
||||
// _POP_TOP
|
||||
value = stack_pointer[-1];
|
||||
{
|
||||
Py_DECREF(value);
|
||||
}
|
||||
// _POP_TOP
|
||||
value = stack_pointer[-2];
|
||||
{
|
||||
Py_DECREF(value);
|
||||
}
|
||||
stack_pointer += -2;
|
||||
Py_DECREF(value);
|
||||
stack_pointer += -1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
@ -2505,8 +2497,8 @@
|
|||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
|
||||
Py_DECREF(iter);
|
||||
STACK_SHRINK(1);
|
||||
/* Jump forward oparg, then skip following END_FOR instruction */
|
||||
JUMPBY(oparg + 1);
|
||||
/* Jump forward oparg, then skip following END_FOR and POP_TOP instruction */
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
// Common case: no jump, leave it to the code generator
|
||||
|
@ -2567,8 +2559,8 @@
|
|||
}
|
||||
Py_DECREF(iter);
|
||||
STACK_SHRINK(1);
|
||||
/* Jump forward oparg, then skip following END_FOR instruction */
|
||||
JUMPBY(oparg + 1);
|
||||
/* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
}
|
||||
|
@ -2608,8 +2600,8 @@
|
|||
if (r->len <= 0) {
|
||||
STACK_SHRINK(1);
|
||||
Py_DECREF(r);
|
||||
// Jump over END_FOR instruction.
|
||||
JUMPBY(oparg + 1);
|
||||
// Jump over END_FOR and POP_TOP instructions.
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
}
|
||||
|
@ -2655,8 +2647,8 @@
|
|||
}
|
||||
Py_DECREF(iter);
|
||||
STACK_SHRINK(1);
|
||||
/* Jump forward oparg, then skip following END_FOR instruction */
|
||||
JUMPBY(oparg + 1);
|
||||
/* Jump forward oparg, then skip following END_FOR and POP_TOP instructions */
|
||||
JUMPBY(oparg + 2);
|
||||
DISPATCH();
|
||||
}
|
||||
}
|
||||
|
@ -2952,9 +2944,8 @@
|
|||
}
|
||||
PyErr_SetRaisedException(NULL);
|
||||
}
|
||||
Py_DECREF(receiver);
|
||||
Py_DECREF(value);
|
||||
stack_pointer += -2;
|
||||
stack_pointer += -1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
@ -3005,8 +2996,8 @@
|
|||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
|
||||
STACK_SHRINK(1);
|
||||
Py_DECREF(iter);
|
||||
/* Skip END_FOR */
|
||||
target = next_instr + oparg + 1;
|
||||
/* Skip END_FOR and POP_TOP */
|
||||
target = next_instr + oparg + 2;
|
||||
}
|
||||
INSTRUMENTED_JUMP(this_instr, target, PY_MONITORING_EVENT_BRANCH);
|
||||
DISPATCH();
|
||||
|
|
|
@ -572,9 +572,10 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
|||
uop = _PyUOp_Replacements[uop];
|
||||
assert(uop != 0);
|
||||
if (uop == _FOR_ITER_TIER_TWO) {
|
||||
target += 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1 + extended;
|
||||
assert(_PyCode_CODE(code)[target-1].op.code == END_FOR ||
|
||||
_PyCode_CODE(code)[target-1].op.code == INSTRUMENTED_END_FOR);
|
||||
target += 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 2 + extended;
|
||||
assert(_PyCode_CODE(code)[target-2].op.code == END_FOR ||
|
||||
_PyCode_CODE(code)[target-2].op.code == INSTRUMENTED_END_FOR);
|
||||
assert(_PyCode_CODE(code)[target-1].op.code == POP_TOP);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue