summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2024-01-24 15:10:17 (GMT)
committerGitHub <noreply@github.com>2024-01-24 15:10:17 (GMT)
commit981d172f7f0613d30bef4a8934b361db7fcf0672 (patch)
treebda610af879108b30ba43e39579900e35689543c /Python
parent6fadd68da5dd928847264b17f62a5b8b369c1c1e (diff)
downloadcpython-981d172f7f0613d30bef4a8934b361db7fcf0672.zip
cpython-981d172f7f0613d30bef4a8934b361db7fcf0672.tar.gz
cpython-981d172f7f0613d30bef4a8934b361db7fcf0672.tar.bz2
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.
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c24
-rw-r--r--Python/compile.c10
-rw-r--r--Python/generated_cases.c.h35
-rw-r--r--Python/optimizer.c7
4 files changed, 39 insertions, 37 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 18749ce..fef3cd4 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -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();
}
}
diff --git a/Python/compile.c b/Python/compile.c
index 2a6291c..7cf05dd 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -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;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index c4bb3ae..16f1db3 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -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();
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 4b6ed17..db61506 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -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: