GH-100982: Restrict `FOR_ITER_RANGE` to a single instruction to allow instrumentation. (GH-101985)

This commit is contained in:
Mark Shannon 2023-02-22 11:11:57 +00:00 committed by GitHub
parent 8d46c7ed5e
commit 7c106a443f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 22 additions and 30 deletions

View File

@ -0,0 +1,2 @@
Restrict the scope of the :opcode:`FOR_ITER_RANGE` instruction to the scope of the
original :opcode:`FOR_ITER` instruction, to allow instrumentation.

View File

@ -2178,35 +2178,27 @@ dummy_func(
// Common case: no jump, leave it to the code generator // Common case: no jump, leave it to the code generator
} }
// This is slightly different, when the loop isn't terminated we inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) {
// jump over the immediately following STORE_FAST instruction.
inst(FOR_ITER_RANGE, (unused/1, iter -- iter, unused)) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
_PyRangeIterObject *r = (_PyRangeIterObject *)iter; _PyRangeIterObject *r = (_PyRangeIterObject *)iter;
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit); STAT_INC(FOR_ITER, hit);
_Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER];
assert(_PyOpcode_Deopt[next.op.code] == STORE_FAST);
if (r->len <= 0) { if (r->len <= 0) {
STACK_SHRINK(1); STACK_SHRINK(1);
Py_DECREF(r); Py_DECREF(r);
// Jump over END_FOR instruction. // Jump over END_FOR instruction.
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1);
DISPATCH();
} }
else { long value = r->start;
long value = r->start; r->start = value + r->step;
r->start = value + r->step; r->len--;
r->len--; next = PyLong_FromLong(value);
if (_PyLong_AssignValue(&GETLOCAL(next.op.arg), value) < 0) { if (next == NULL) {
goto error; goto error;
}
// The STORE_FAST is already done.
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1);
} }
DISPATCH();
} }
// This is *not* a super-instruction, unique in the family.
inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
PyGenObject *gen = (PyGenObject *)iter; PyGenObject *gen = (PyGenObject *)iter;

View File

@ -2756,28 +2756,28 @@
TARGET(FOR_ITER_RANGE) { TARGET(FOR_ITER_RANGE) {
PyObject *iter = PEEK(1); PyObject *iter = PEEK(1);
PyObject *next;
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
_PyRangeIterObject *r = (_PyRangeIterObject *)iter; _PyRangeIterObject *r = (_PyRangeIterObject *)iter;
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit); STAT_INC(FOR_ITER, hit);
_Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER];
assert(_PyOpcode_Deopt[next.op.code] == STORE_FAST);
if (r->len <= 0) { if (r->len <= 0) {
STACK_SHRINK(1); STACK_SHRINK(1);
Py_DECREF(r); Py_DECREF(r);
// Jump over END_FOR instruction. // Jump over END_FOR instruction.
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1);
DISPATCH();
} }
else { long value = r->start;
long value = r->start; r->start = value + r->step;
r->start = value + r->step; r->len--;
r->len--; next = PyLong_FromLong(value);
if (_PyLong_AssignValue(&GETLOCAL(next.op.arg), value) < 0) { if (next == NULL) {
goto error; goto error;
}
// The STORE_FAST is already done.
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1);
} }
STACK_GROW(1);
POKE(1, next);
JUMPBY(1);
DISPATCH(); DISPATCH();
} }

View File

@ -2155,8 +2155,6 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER);
_PyForIterCache *cache = (_PyForIterCache *)(instr + 1); _PyForIterCache *cache = (_PyForIterCache *)(instr + 1);
PyTypeObject *tp = Py_TYPE(iter); PyTypeObject *tp = Py_TYPE(iter);
_Py_CODEUNIT next = instr[1+INLINE_CACHE_ENTRIES_FOR_ITER];
int next_op = _PyOpcode_Deopt[next.op.code];
if (tp == &PyListIter_Type) { if (tp == &PyListIter_Type) {
instr->op.code = FOR_ITER_LIST; instr->op.code = FOR_ITER_LIST;
goto success; goto success;
@ -2165,7 +2163,7 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
instr->op.code = FOR_ITER_TUPLE; instr->op.code = FOR_ITER_TUPLE;
goto success; goto success;
} }
else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) { else if (tp == &PyRangeIter_Type) {
instr->op.code = FOR_ITER_RANGE; instr->op.code = FOR_ITER_RANGE;
goto success; goto success;
} }