mirror of https://github.com/python/cpython
GH-100982: Restrict `FOR_ITER_RANGE` to a single instruction to allow instrumentation. (GH-101985)
This commit is contained in:
parent
8d46c7ed5e
commit
7c106a443f
|
@ -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.
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue