GH-145668: Add FOR_ITER specialization for virtual iterators. Specialize GET_ITER. (GH-147967)

* Add FOR_ITER_VIRTUAL to specialize FOR_ITER for virtual iterators
* Add GET_ITER_SELF to specialize GET_ITER for iterators (including generators)
* Add GET_ITER_VIRTUAL to specialize GET_ITER for iterables as virtual iterators
* Add new (internal) _tp_iteritem function slot to PyTypeObject
* Put limited RESUME at start of genexpr for free-threading. Fix up exception handling in genexpr
This commit is contained in:
Mark Shannon 2026-04-16 15:22:22 +01:00 committed by GitHub
parent 0fcf2b72d3
commit 600f4dbd54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 2987 additions and 1534 deletions

View file

@ -1396,9 +1396,46 @@ dummy_func(void) {
}
op(_GET_ITER, (iterable -- iter, index_or_null)) {
if (sym_matches_type(iterable, &PyTuple_Type) || sym_matches_type(iterable, &PyList_Type)) {
bool is_coro = false;
bool is_trad = false; // has `tp_iter` slot
bool definite = true;
PyTypeObject *tp = sym_get_type(iterable);
if (tp == NULL) {
definite = false;
tp = sym_get_probable_type(iterable);
}
if (oparg == GET_ITER_YIELD_FROM_NO_CHECK) {
if (tp == &PyCoro_Type) {
if (!definite) {
ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
sym_set_type(iterable, tp);
}
ADD_OP(_PUSH_NULL, 0, 0);
is_coro = true;
}
}
if (tp != NULL &&
tp->_tp_iteritem == NULL &&
tp->tp_iter != NULL &&
tp->tp_iter != PyObject_SelfIter &&
tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE
) {
assert(tp != &PyCoro_Type);
is_trad = true;
if (!definite) {
ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
sym_set_type(iterable, tp);
}
ADD_OP(_GET_ITER_TRAD, 0, 0);
}
if (is_coro) {
assert(!is_trad);
iter = iterable;
index_or_null = sym_new_not_null(ctx);
index_or_null = sym_new_null(ctx);
}
else if (is_trad) {
iter = sym_new_not_null(ctx);
index_or_null = sym_new_null(ctx);
}
else {
iter = sym_new_not_null(ctx);
@ -1406,6 +1443,42 @@ dummy_func(void) {
}
}
op(_GUARD_ITERATOR, (iterable -- iterable)) {
bool definite = true;
PyTypeObject *tp = sym_get_type(iterable);
if (tp == NULL) {
definite = false;
tp = sym_get_probable_type(iterable);
}
if (tp != NULL && tp->tp_iter == PyObject_SelfIter) {
if (definite) {
ADD_OP(_NOP, 0, 0);
}
else {
ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
sym_set_type(iterable, tp);
}
}
}
op(_GUARD_ITER_VIRTUAL, (iterable -- iterable)) {
bool definite = true;
PyTypeObject *tp = sym_get_type(iterable);
if (tp == NULL) {
definite = false;
tp = sym_get_probable_type(iterable);
}
if (tp != NULL && tp->_tp_iteritem != NULL) {
if (definite) {
ADD_OP(_NOP, 0, 0);
}
else {
ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
sym_set_type(iterable, tp);
}
}
}
op(_FOR_ITER_GEN_FRAME, (iter, unused -- iter, unused, gen_frame)) {
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, iter, NULL, 0);
if (new_frame == NULL) {