Skip to content

Commit

Permalink
GH-100110: Specialize FOR_ITER for tuples (GH-100109)
Browse files Browse the repository at this point in the history
* Specialize FOR_ITER for tuples
  • Loading branch information
Fidget-Spinner authored Dec 9, 2022
1 parent 0448dea commit 748c6c0
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 67 deletions.
26 changes: 13 additions & 13 deletions Include/internal/pycore_opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Include/internal/pycore_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ struct _Py_tuple_state {
extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
extern PyObject *_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);


typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
PyTupleObject *it_seq; /* Set to NULL when iterator is exhausted */
} _PyTupleIterObject;

#ifdef __cplusplus
}
#endif
Expand Down
57 changes: 29 additions & 28 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ def pseudo_op(name, op, real_ops):
],
"FOR_ITER": [
"FOR_ITER_LIST",
"FOR_ITER_TUPLE",
"FOR_ITER_RANGE",
"FOR_ITER_GEN",
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Specialize ``FOR_ITER`` for tuples.
23 changes: 9 additions & 14 deletions Objects/tupleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -995,29 +995,24 @@ _PyTuple_ClearFreeList(PyInterpreterState *interp)

/*********************** Tuple Iterator **************************/

typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
PyTupleObject *it_seq; /* Set to NULL when iterator is exhausted */
} tupleiterobject;

static void
tupleiter_dealloc(tupleiterobject *it)
tupleiter_dealloc(_PyTupleIterObject *it)
{
_PyObject_GC_UNTRACK(it);
Py_XDECREF(it->it_seq);
PyObject_GC_Del(it);
}

static int
tupleiter_traverse(tupleiterobject *it, visitproc visit, void *arg)
tupleiter_traverse(_PyTupleIterObject *it, visitproc visit, void *arg)
{
Py_VISIT(it->it_seq);
return 0;
}

static PyObject *
tupleiter_next(tupleiterobject *it)
tupleiter_next(_PyTupleIterObject *it)
{
PyTupleObject *seq;
PyObject *item;
Expand All @@ -1040,7 +1035,7 @@ tupleiter_next(tupleiterobject *it)
}

static PyObject *
tupleiter_len(tupleiterobject *it, PyObject *Py_UNUSED(ignored))
tupleiter_len(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored))
{
Py_ssize_t len = 0;
if (it->it_seq)
Expand All @@ -1051,7 +1046,7 @@ tupleiter_len(tupleiterobject *it, PyObject *Py_UNUSED(ignored))
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");

static PyObject *
tupleiter_reduce(tupleiterobject *it, PyObject *Py_UNUSED(ignored))
tupleiter_reduce(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored))
{
if (it->it_seq)
return Py_BuildValue("N(O)n", _PyEval_GetBuiltin(&_Py_ID(iter)),
Expand All @@ -1061,7 +1056,7 @@ tupleiter_reduce(tupleiterobject *it, PyObject *Py_UNUSED(ignored))
}

static PyObject *
tupleiter_setstate(tupleiterobject *it, PyObject *state)
tupleiter_setstate(_PyTupleIterObject *it, PyObject *state)
{
Py_ssize_t index = PyLong_AsSsize_t(state);
if (index == -1 && PyErr_Occurred())
Expand Down Expand Up @@ -1089,7 +1084,7 @@ static PyMethodDef tupleiter_methods[] = {
PyTypeObject PyTupleIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"tuple_iterator", /* tp_name */
sizeof(tupleiterobject), /* tp_basicsize */
sizeof(_PyTupleIterObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)tupleiter_dealloc, /* tp_dealloc */
Expand Down Expand Up @@ -1122,13 +1117,13 @@ PyTypeObject PyTupleIter_Type = {
static PyObject *
tuple_iter(PyObject *seq)
{
tupleiterobject *it;
_PyTupleIterObject *it;

if (!PyTuple_Check(seq)) {
PyErr_BadInternalCall();
return NULL;
}
it = PyObject_GC_New(tupleiterobject, &PyTupleIter_Type);
it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
if (it == NULL)
return NULL;
it->it_index = 0;
Expand Down
23 changes: 23 additions & 0 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,29 @@ dummy_func(
end_for_iter_list:
}

// stack effect: ( -- __0)
inst(FOR_ITER_TUPLE) {
assert(cframe.use_tracing == 0);
_PyTupleIterObject *it = (_PyTupleIterObject *)TOP();
DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit);
PyTupleObject *seq = it->it_seq;
if (seq) {
if (it->it_index < PyTuple_GET_SIZE(seq)) {
PyObject *next = PyTuple_GET_ITEM(seq, it->it_index++);
PUSH(Py_NewRef(next));
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER);
goto end_for_iter_tuple; // End of this instruction
}
it->it_seq = NULL;
Py_DECREF(seq);
}
STACK_SHRINK(1);
Py_DECREF(it);
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1);
end_for_iter_tuple:
}

// stack effect: ( -- __0)
inst(FOR_ITER_RANGE) {
assert(cframe.use_tracing == 0);
Expand Down
23 changes: 23 additions & 0 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 748c6c0

Please sign in to comment.