Skip to content

Commit c41d531

Browse files
committed
Streamline non-specialized FOR_ITER
1 parent 4e44e85 commit c41d531

14 files changed

+103
-83
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_ids.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode_ids.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/_opcode_metadata.py

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_dis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ def loop_test():
906906
LIST_EXTEND 1
907907
LOAD_SMALL_INT 3
908908
BINARY_OP 5 (*)
909-
GET_ITER_LIST_OR_TUPLE
909+
GET_ITER_INDEX
910910
L1: FOR_ITER_LIST 14 (to L2)
911911
STORE_FAST 0 (i)
912912

Lib/test/test_opcache.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,7 +1891,7 @@ def for_iter_list():
18911891
self.assertIn(i, L)
18921892

18931893
for_iter_list()
1894-
self.assert_specialized(for_iter_list, "GET_ITER_LIST_OR_TUPLE")
1894+
self.assert_specialized(for_iter_list, "GET_ITER_INDEX")
18951895
self.assert_no_opcode(for_iter_list, "GET_ITER")
18961896

18971897
t = tuple(range(2))
@@ -1903,9 +1903,21 @@ def for_iter_tuple():
19031903
self.assertIn(i, t)
19041904

19051905
for_iter_tuple()
1906-
self.assert_specialized(for_iter_tuple, "GET_ITER_LIST_OR_TUPLE")
1906+
self.assert_specialized(for_iter_tuple, "GET_ITER_INDEX")
19071907
self.assert_no_opcode(for_iter_tuple, "GET_ITER")
19081908

1909+
s = "hello"
1910+
def for_iter_str():
1911+
n = 0
1912+
while n < _testinternalcapi.SPECIALIZATION_THRESHOLD:
1913+
n += 1
1914+
for c in s:
1915+
self.assertIn(c, s)
1916+
1917+
for_iter_str()
1918+
self.assert_specialized(for_iter_str, "GET_ITER_INDEX")
1919+
self.assert_no_opcode(for_iter_str, "GET_ITER")
1920+
19091921
def for_iter_generator():
19101922
n = 0
19111923
while n < _testinternalcapi.SPECIALIZATION_THRESHOLD:

Python/bytecodes.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,7 +3053,7 @@ dummy_func(
30533053

30543054

30553055
family(GET_ITER, 1) = {
3056-
GET_ITER_LIST_OR_TUPLE,
3056+
GET_ITER_INDEX,
30573057
GET_ITER_SELF,
30583058
GET_ITER_RANGE,
30593059
};
@@ -3108,11 +3108,9 @@ dummy_func(
31083108
null = PyStackRef_NULL;
31093109
}
31103110

3111-
inst(GET_ITER_LIST_OR_TUPLE, (unused/1, iter -- iter, index0)) {
3111+
inst(GET_ITER_INDEX, (unused/1, iter -- iter, index0)) {
31123112
PyTypeObject *tp = PyStackRef_TYPE(iter);
3113-
if (tp != &PyList_Type) {
3114-
DEOPT_IF(tp != &PyTuple_Type);
3115-
}
3113+
DEOPT_IF(tp->tp_iterindex == NULL);
31163114
index0 = PyStackRef_TagInt(0);
31173115
}
31183116

@@ -3171,20 +3169,20 @@ dummy_func(
31713169
FOR_ITER_INDEX,
31723170
};
31733171

3174-
specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter, null_or_index -- iter, null_or_index)) {
3172+
specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter, maybe_index -- iter, maybe_index)) {
31753173
#if ENABLE_SPECIALIZATION_FT
31763174
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
31773175
next_instr = this_instr;
3178-
_Py_Specialize_ForIter(iter, null_or_index, next_instr, oparg);
3176+
_Py_Specialize_ForIter(iter, maybe_index, next_instr, oparg);
31793177
DISPATCH_SAME_OPARG();
31803178
}
31813179
OPCODE_DEFERRED_INC(FOR_ITER);
31823180
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
31833181
#endif /* ENABLE_SPECIALIZATION_FT */
31843182
}
31853183

3186-
replaced op(_FOR_ITER, (iter, null_or_index -- iter, null_or_index, next)) {
3187-
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index);
3184+
replaced op(_FOR_ITER, (iter, null_or_index[1] -- iter, null_or_index[1], next)) {
3185+
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, null_or_index);
31883186
if (!PyStackRef_IsValid(item)) {
31893187
if (PyStackRef_IsError(item)) {
31903188
ERROR_NO_POP();
@@ -3230,8 +3228,8 @@ dummy_func(
32303228
_ITER_CHECK_INDEX +
32313229
_FOR_ITER_INDEX;
32323230

3233-
op(_FOR_ITER_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) {
3234-
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index);
3231+
op(_FOR_ITER_TIER_TWO, (iter, null_or_index[1] -- iter, null_or_index[1], next)) {
3232+
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, null_or_index);
32353233
if (!PyStackRef_IsValid(item)) {
32363234
if (PyStackRef_IsError(item)) {
32373235
ERROR_NO_POP();
@@ -3246,8 +3244,8 @@ dummy_func(
32463244
macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER;
32473245

32483246

3249-
inst(INSTRUMENTED_FOR_ITER, (unused/1, iter, null_or_index -- iter, null_or_index, next)) {
3250-
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index);
3247+
inst(INSTRUMENTED_FOR_ITER, (unused/1, iter, null_or_index[1] -- iter, null_or_index[1], next)) {
3248+
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, null_or_index);
32513249
if (!PyStackRef_IsValid(item)) {
32523250
if (PyStackRef_IsError(item)) {
32533251
ERROR_NO_POP();

Python/ceval.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3439,13 +3439,44 @@ _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *na
34393439
return value;
34403440
}
34413441

3442+
static _PyStackRef
3443+
not_iterator(PyObject *obj)
3444+
{
3445+
PyErr_Format(PyExc_TypeError,
3446+
"'%.200s' object is not an async iterator",
3447+
Py_TYPE(obj)->tp_name);
3448+
return PyStackRef_ERROR;
3449+
}
3450+
34423451
_PyStackRef
34433452
_PyForIter_VirtualIteratorNext(
34443453
PyThreadState* tstate, _PyInterpreterFrame* frame,
34453454
_PyStackRef iter, _PyStackRef* index_ptr
34463455
) {
34473456
_PyStackRef index = *index_ptr;
3448-
if (PyStackRef_IsTaggedInt(index)) {
3457+
if (PyStackRef_IsNull(index)) {
3458+
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
3459+
iternextfunc func = Py_TYPE(iter_o)->tp_iternext;
3460+
if (func == NULL) {
3461+
return not_iterator(iter_o);
3462+
}
3463+
PyObject *next_o = func(iter_o);
3464+
if (next_o == NULL) {
3465+
if (_PyErr_Occurred(tstate)) {
3466+
if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
3467+
_PyEval_MonitorRaise(tstate, frame, frame->instr_ptr);
3468+
_PyErr_Clear(tstate);
3469+
}
3470+
else {
3471+
return PyStackRef_ERROR;
3472+
}
3473+
}
3474+
return PyStackRef_NULL;
3475+
}
3476+
return PyStackRef_FromPyObjectSteal(next_o);
3477+
}
3478+
else {
3479+
assert(PyStackRef_IsTaggedInt(index));
34493480
if (PyStackRef_IsTaggedInt(iter)) {
34503481
if (!PyStackRef_TaggedIntLessThan(index, iter)) {
34513482
return PyStackRef_NULL;
@@ -3465,21 +3496,6 @@ _PyForIter_VirtualIteratorNext(
34653496
return PyStackRef_FromPyObjectSteal(item);
34663497
}
34673498
}
3468-
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
3469-
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3470-
if (next_o == NULL) {
3471-
if (_PyErr_Occurred(tstate)) {
3472-
if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
3473-
_PyEval_MonitorRaise(tstate, frame, frame->instr_ptr);
3474-
_PyErr_Clear(tstate);
3475-
}
3476-
else {
3477-
return PyStackRef_ERROR;
3478-
}
3479-
}
3480-
return PyStackRef_NULL;
3481-
}
3482-
return PyStackRef_FromPyObjectSteal(next_o);
34833499
}
34843500

34853501
/* Check if a 'cls' provides the given special method. */

Python/executor_cases.c.h

Lines changed: 7 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)