Skip to content

Commit 5a81e54

Browse files
committed
Return a small struct in tp_iteritem to support MSVC tailcalling
1 parent 4376246 commit 5a81e54

File tree

10 files changed

+54
-63
lines changed

10 files changed

+54
-63
lines changed

Include/object.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,11 @@ typedef Py_hash_t (*hashfunc)(PyObject *);
385385
typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
386386
typedef PyObject *(*getiterfunc) (PyObject *);
387387
typedef PyObject *(*iternextfunc) (PyObject *);
388-
typedef PyObject *(*iteritemfunc) (PyObject *, Py_ssize_t *index);
388+
typedef struct _py_object_index_pair {
389+
PyObject *object;
390+
Py_ssize_t index;
391+
} PyObjectIndexPair;
392+
typedef PyObjectIndexPair (*iteritemfunc) (PyObject *, Py_ssize_t index);
389393
typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
390394
typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
391395
typedef int (*initproc)(PyObject *, PyObject *, PyObject *);

Modules/_testinternalcapi/test_cases.c.h

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

Objects/bytesobject.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,16 +3206,15 @@ Construct an immutable array of bytes from:\n\
32063206
static PyObject *bytes_iter(PyObject *seq);
32073207

32083208

3209-
static PyObject *
3210-
bytes_iteritem(PyObject *obj, Py_ssize_t *index)
3209+
static PyObjectIndexPair
3210+
bytes_iteritem(PyObject *obj, Py_ssize_t index)
32113211
{
3212-
Py_ssize_t i = *index;
32133212
PyBytesObject *a = _PyBytes_CAST(obj);
3214-
if (i >= Py_SIZE(a)) {
3215-
return NULL;
3213+
if (index >= Py_SIZE(a)) {
3214+
return (PyObjectIndexPair) { .object = NULL, .index = index };
32163215
}
3217-
*index = i+1;
3218-
return _PyLong_FromUnsignedChar((unsigned char)a->ob_sval[i]);
3216+
PyObject *l = _PyLong_FromUnsignedChar((unsigned char)a->ob_sval[index]);
3217+
return (PyObjectIndexPair) { .object = l, .index = index + 1 };
32193218
}
32203219

32213220
PyTypeObject PyBytes_Type = {

Objects/listobject.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3913,13 +3913,11 @@ list_ass_subscript(PyObject *self, PyObject *item, PyObject *value)
39133913
return res;
39143914
}
39153915

3916-
static PyObject *
3917-
list_iteritem(PyObject *obj, Py_ssize_t *index)
3916+
static PyObjectIndexPair
3917+
list_iteritem(PyObject *obj, Py_ssize_t index)
39183918
{
3919-
Py_ssize_t i = *index;
3920-
PyObject *result = list_get_item_ref((PyListObject *)obj, i);
3921-
*index = i+1;
3922-
return result;
3919+
PyObject *result = list_get_item_ref((PyListObject *)obj, index);
3920+
return (PyObjectIndexPair) { .object = result, .index = index + 1 };
39233921
}
39243922

39253923
static PyMappingMethods list_as_mapping = {

Objects/tupleobject.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -873,17 +873,16 @@ static PySequenceMethods tuple_as_sequence = {
873873
tuple_contains, /* sq_contains */
874874
};
875875

876-
static PyObject *
877-
tuple_iteritem(PyObject *obj, Py_ssize_t *index)
876+
static PyObjectIndexPair
877+
tuple_iteritem(PyObject *obj, Py_ssize_t index)
878878
{
879-
Py_ssize_t i = *index;
880-
if (i >= PyTuple_GET_SIZE(obj)) {
881-
return NULL;
879+
;
880+
if (index >= PyTuple_GET_SIZE(obj)) {
881+
return (PyObjectIndexPair) { .object = NULL, index = index };
882882
}
883-
PyObject *result = PyTuple_GET_ITEM(obj, i);
883+
PyObject *result = PyTuple_GET_ITEM(obj, index);
884884
Py_INCREF(result);
885-
*index = i+1;
886-
return result;
885+
return (PyObjectIndexPair) { .object = result, .index = index + 1 };
887886
}
888887

889888
static PyObject*

Objects/unicodeobject.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13982,24 +13982,18 @@ unicode_subtype_new(PyTypeObject *type, PyObject *unicode)
1398213982
return NULL;
1398313983
}
1398413984

13985-
static PyObject *
13986-
unicode_iteritem(PyObject *obj, Py_ssize_t *index)
13985+
static PyObjectIndexPair
13986+
unicode_iteritem(PyObject *obj, Py_ssize_t index)
1398713987
{
13988-
Py_ssize_t i = *index;
13989-
if (i >= PyUnicode_GET_LENGTH(obj)) {
13990-
return NULL;
13988+
if (index >= PyUnicode_GET_LENGTH(obj)) {
13989+
return (PyObjectIndexPair) { .object = NULL, .index = index };
1399113990
}
1399213991
const void *data = PyUnicode_DATA(obj);
1399313992
int kind = PyUnicode_KIND(obj);
13994-
Py_UCS4 ch = PyUnicode_READ(kind, data, i);
13993+
Py_UCS4 ch = PyUnicode_READ(kind, data, index);
1399513994
PyObject *result = unicode_char(ch);
13996-
if (result == NULL) {
13997-
*index = -1;
13998-
}
13999-
else {
14000-
*index = i+1;
14001-
}
14002-
return result;
13995+
index = (result == NULL) ? -1 : index + 1;
13996+
return (PyObjectIndexPair) { .object = result, .index = index };
1400313997
}
1400413998

1400513999
void

Python/bytecodes.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,12 +3643,9 @@ dummy_func(
36433643
replaced op(_FOR_ITER_VIRTUAL, (iter, null_or_index -- iter, null_or_index, next)) {
36443644
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
36453645
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
3646-
PyObject *next_o;
3647-
{ // Make it clear that index doesn't escape; for MSVC tailcall
3648-
Py_ssize_t tmp = index;
3649-
next_o = Py_TYPE(iter_o)->tp_iteritem(iter_o, &tmp);
3650-
index = tmp;
3651-
}
3646+
PyObjectIndexPair next_index = Py_TYPE(iter_o)->tp_iteritem(iter_o, index);
3647+
PyObject *next_o = next_index.object;
3648+
index = next_index.index;
36523649
if (next_o == NULL) {
36533650
if (index < 0) {
36543651
ERROR_NO_POP();
@@ -3669,7 +3666,9 @@ dummy_func(
36693666
op(_FOR_ITER_VIRTUAL_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) {
36703667
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
36713668
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
3672-
PyObject *next_o = Py_TYPE(iter_o)->tp_iteritem(iter_o, &index);
3669+
PyObjectIndexPair next_index = Py_TYPE(iter_o)->tp_iteritem(iter_o, index);
3670+
PyObject *next_o = next_index.object;
3671+
index = next_index.index;
36733672
if (next_o == NULL) {
36743673
if (index < 0) {
36753674
ERROR_NO_POP();

Python/ceval.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3759,15 +3759,17 @@ _PyStackRef _PyForIter_VirtualIteratorNext(PyThreadState* tstate, _PyInterpreter
37593759
if (PyStackRef_IsTaggedInt(index)) {
37603760
intptr_t i = PyStackRef_UntagInt(index);
37613761
assert(i >= 0);
3762-
PyObject *next = Py_TYPE(iter_o)->tp_iteritem(iter_o, &i);
3762+
PyObjectIndexPair next_index = Py_TYPE(iter_o)->tp_iteritem(iter_o, i);
3763+
i = next_index.index;
3764+
PyObject *next = next_index.object;
37633765
if (next == NULL) {
37643766
return i < 0 ? PyStackRef_ERROR : PyStackRef_NULL;
37653767
}
37663768
*index_ptr = PyStackRef_TagInt(i);
37673769
return PyStackRef_FromPyObjectSteal(next);
37683770
}
3769-
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3770-
if (next_o == NULL) {
3771+
PyObject *next = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3772+
if (next == NULL) {
37713773
if (_PyErr_Occurred(tstate)) {
37723774
if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
37733775
_PyEval_MonitorRaise(tstate, frame, frame->instr_ptr);
@@ -3779,7 +3781,7 @@ _PyStackRef _PyForIter_VirtualIteratorNext(PyThreadState* tstate, _PyInterpreter
37793781
}
37803782
return PyStackRef_NULL;
37813783
}
3782-
return PyStackRef_FromPyObjectSteal(next_o);
3784+
return PyStackRef_FromPyObjectSteal(next);
37833785
}
37843786

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

Python/executor_cases.c.h

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

Python/generated_cases.c.h

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

0 commit comments

Comments
 (0)