Skip to content

Commit 7c106a4

Browse files
authored
GH-100982: Restrict FOR_ITER_RANGE to a single instruction to allow instrumentation. (GH-101985)
1 parent 8d46c7e commit 7c106a4

File tree

4 files changed

+22
-30
lines changed

4 files changed

+22
-30
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Restrict the scope of the :opcode:`FOR_ITER_RANGE` instruction to the scope of the
2+
original :opcode:`FOR_ITER` instruction, to allow instrumentation.

Python/bytecodes.c

+8-16
Original file line numberDiff line numberDiff line change
@@ -2178,35 +2178,27 @@ dummy_func(
21782178
// Common case: no jump, leave it to the code generator
21792179
}
21802180

2181-
// This is slightly different, when the loop isn't terminated we
2182-
// jump over the immediately following STORE_FAST instruction.
2183-
inst(FOR_ITER_RANGE, (unused/1, iter -- iter, unused)) {
2181+
inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) {
21842182
assert(cframe.use_tracing == 0);
21852183
_PyRangeIterObject *r = (_PyRangeIterObject *)iter;
21862184
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
21872185
STAT_INC(FOR_ITER, hit);
2188-
_Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER];
2189-
assert(_PyOpcode_Deopt[next.op.code] == STORE_FAST);
21902186
if (r->len <= 0) {
21912187
STACK_SHRINK(1);
21922188
Py_DECREF(r);
21932189
// Jump over END_FOR instruction.
21942190
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1);
2191+
DISPATCH();
21952192
}
2196-
else {
2197-
long value = r->start;
2198-
r->start = value + r->step;
2199-
r->len--;
2200-
if (_PyLong_AssignValue(&GETLOCAL(next.op.arg), value) < 0) {
2201-
goto error;
2202-
}
2203-
// The STORE_FAST is already done.
2204-
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1);
2193+
long value = r->start;
2194+
r->start = value + r->step;
2195+
r->len--;
2196+
next = PyLong_FromLong(value);
2197+
if (next == NULL) {
2198+
goto error;
22052199
}
2206-
DISPATCH();
22072200
}
22082201

2209-
// This is *not* a super-instruction, unique in the family.
22102202
inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) {
22112203
assert(cframe.use_tracing == 0);
22122204
PyGenObject *gen = (PyGenObject *)iter;

Python/generated_cases.c.h

+11-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -2155,8 +2155,6 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
21552155
assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER);
21562156
_PyForIterCache *cache = (_PyForIterCache *)(instr + 1);
21572157
PyTypeObject *tp = Py_TYPE(iter);
2158-
_Py_CODEUNIT next = instr[1+INLINE_CACHE_ENTRIES_FOR_ITER];
2159-
int next_op = _PyOpcode_Deopt[next.op.code];
21602158
if (tp == &PyListIter_Type) {
21612159
instr->op.code = FOR_ITER_LIST;
21622160
goto success;
@@ -2165,7 +2163,7 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
21652163
instr->op.code = FOR_ITER_TUPLE;
21662164
goto success;
21672165
}
2168-
else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) {
2166+
else if (tp == &PyRangeIter_Type) {
21692167
instr->op.code = FOR_ITER_RANGE;
21702168
goto success;
21712169
}

0 commit comments

Comments
 (0)