Skip to content

Commit e8497ae

Browse files
committed
Add support for asyn generators on fast path. Simplify counting
1 parent c024484 commit e8497ae

File tree

10 files changed

+165
-135
lines changed

10 files changed

+165
-135
lines changed

Include/internal/pycore_frame.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,9 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func,
409409
size_t argcount, PyObject *kwnames,
410410
_PyInterpreterFrame *previous);
411411

412+
void
413+
_PyFrame_MoveToReachable(_PyInterpreterFrame *frame, PyGC_Head *reachable, int visited_space);
414+
412415
#ifdef __cplusplus
413416
}
414417
#endif

Include/internal/pycore_gc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ extern void _PyGC_VisitObjectsWorldStopped(PyInterpreterState *interp,
401401
gcvisitobjects_t callback, void *arg);
402402
#endif
403403

404+
void _PyGC_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space);
405+
404406
#ifdef __cplusplus
405407
}
406408
#endif

Include/internal/pycore_typeobject.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ extern "C" {
2929
#define _Py_TYPE_VERSION_COROUTINE 13
3030
#define _Py_TYPE_VERSION_MODULE 14
3131
#define _Py_TYPE_VERSION_TYPE 15
32+
#define _Py_TYPE_VERSION_ASYNC_GENERATOR 16
33+
#define _Py_TYPE_VERSION_ASYNC_ASEND 17
3234

33-
#define _Py_TYPE_VERSION_NEXT 16
35+
#define _Py_TYPE_VERSION_NEXT 20
3436

3537

3638
#define _Py_TYPE_BASE_VERSION_TAG (2<<16)

Objects/dictobject.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4475,6 +4475,42 @@ dict_popitem_impl(PyDictObject *self)
44754475
return res;
44764476
}
44774477

4478+
void
4479+
_PyDict_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
4480+
{
4481+
PyDictObject *mp = (PyDictObject *)op;
4482+
PyDictKeysObject *keys = mp->ma_keys;
4483+
Py_ssize_t i, n = keys->dk_nentries;
4484+
if (DK_IS_UNICODE(keys)) {
4485+
if (_PyDict_HasSplitTable(mp)) {
4486+
if (!mp->ma_values->embedded) {
4487+
for (i = 0; i < n; i++) {
4488+
PyObject *value = mp->ma_values->values[i];
4489+
_PyGC_MoveToReachable(value, reachable, visited_space);
4490+
}
4491+
}
4492+
}
4493+
else {
4494+
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
4495+
for (i = 0; i < n; i++) {
4496+
PyObject *value = entries[i].me_value;
4497+
_PyGC_MoveToReachable(value, reachable, visited_space);
4498+
}
4499+
}
4500+
}
4501+
else {
4502+
PyDictKeyEntry *entries = DK_ENTRIES(keys);
4503+
for (i = 0; i < n; i++) {
4504+
if (entries[i].me_value != NULL) {
4505+
PyObject *key = entries[i].me_key;
4506+
_PyGC_MoveToReachable(key, reachable, visited_space);
4507+
PyObject *value = entries[i].me_value;
4508+
_PyGC_MoveToReachable(value, reachable, visited_space);
4509+
}
4510+
}
4511+
}
4512+
}
4513+
44784514
static int
44794515
dict_traverse(PyObject *op, visitproc visit, void *arg)
44804516
{

Objects/genobject.c

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ gen_traverse(PyObject *self, visitproc visit, void *arg)
7878
return 0;
7979
}
8080

81+
void
82+
_PyGen_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
83+
{
84+
PyGenObject *gen = (PyGenObject *)op;
85+
if (gen->gi_frame_state == FRAME_CLEARED) {
86+
return;
87+
}
88+
_PyGC_MoveToReachable(gen->gi_exc_state.exc_value, reachable, visited_space);
89+
if (gen->gi_frame_state == FRAME_EXECUTING) {
90+
/* if executing we already traversed it on the stack */
91+
return;
92+
}
93+
_PyInterpreterFrame *frame = &gen->gi_iframe;
94+
_PyFrame_MoveToReachable(frame, reachable, visited_space);
95+
}
96+
8197
void
8298
_PyGen_Finalize(PyObject *self)
8399
{
@@ -1426,6 +1442,14 @@ typedef struct _PyAsyncGenWrappedValue {
14261442
_Py_CAST(_PyAsyncGenWrappedValue*, (op)))
14271443

14281444

1445+
void
1446+
_PyAsyncGen_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
1447+
{
1448+
PyAsyncGenObject *ag = _PyAsyncGenObject_CAST(op);
1449+
_PyGC_MoveToReachable(ag->ag_origin_or_finalizer, reachable, visited_space);
1450+
_PyGen_MoveToReachable(op, reachable, visited_space);
1451+
}
1452+
14291453
static int
14301454
async_gen_traverse(PyObject *self, visitproc visit, void *arg)
14311455
{
@@ -1634,24 +1658,8 @@ PyTypeObject PyAsyncGen_Type = {
16341658
async_gen_methods, /* tp_methods */
16351659
async_gen_memberlist, /* tp_members */
16361660
async_gen_getsetlist, /* tp_getset */
1637-
0, /* tp_base */
1638-
0, /* tp_dict */
1639-
0, /* tp_descr_get */
1640-
0, /* tp_descr_set */
1641-
0, /* tp_dictoffset */
1642-
0, /* tp_init */
1643-
0, /* tp_alloc */
1644-
0, /* tp_new */
1645-
0, /* tp_free */
1646-
0, /* tp_is_gc */
1647-
0, /* tp_bases */
1648-
0, /* tp_mro */
1649-
0, /* tp_cache */
1650-
0, /* tp_subclasses */
1651-
0, /* tp_weaklist */
1652-
0, /* tp_del */
1653-
0, /* tp_version_tag */
1654-
_PyGen_Finalize, /* tp_finalize */
1661+
.tp_finalize = _PyGen_Finalize,
1662+
.tp_version_tag = _Py_TYPE_VERSION_ASYNC_GENERATOR,
16551663
};
16561664

16571665

@@ -1724,6 +1732,14 @@ async_gen_asend_dealloc(PyObject *self)
17241732
_Py_FREELIST_FREE(async_gen_asends, self, PyObject_GC_Del);
17251733
}
17261734

1735+
void
1736+
_PyAsyncAsend_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
1737+
{
1738+
PyAsyncGenASend *ags = _PyAsyncGenASend_CAST(op);
1739+
_PyGC_MoveToReachable((PyObject *)ags->ags_sendval, reachable, visited_space);
1740+
_PyAsyncGen_MoveToReachable((PyObject *)ags->ags_gen, reachable, visited_space);
1741+
}
1742+
17271743
static int
17281744
async_gen_asend_traverse(PyObject *self, visitproc visit, void *arg)
17291745
{
@@ -1896,17 +1912,8 @@ PyTypeObject _PyAsyncGenASend_Type = {
18961912
PyObject_SelfIter, /* tp_iter */
18971913
async_gen_asend_iternext, /* tp_iternext */
18981914
async_gen_asend_methods, /* tp_methods */
1899-
0, /* tp_members */
1900-
0, /* tp_getset */
1901-
0, /* tp_base */
1902-
0, /* tp_dict */
1903-
0, /* tp_descr_get */
1904-
0, /* tp_descr_set */
1905-
0, /* tp_dictoffset */
1906-
0, /* tp_init */
1907-
0, /* tp_alloc */
1908-
0, /* tp_new */
19091915
.tp_finalize = async_gen_asend_finalize,
1916+
.tp_version_tag = _Py_TYPE_VERSION_ASYNC_ASEND,
19101917
};
19111918

19121919

Objects/listobject.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3276,6 +3276,17 @@ list_remove_impl(PyListObject *self, PyObject *value)
32763276
return NULL;
32773277
}
32783278

3279+
void
3280+
_PyList_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
3281+
{
3282+
PyListObject *o = (PyListObject *)op;
3283+
Py_ssize_t i;
3284+
for (i = Py_SIZE(o); --i >= 0; ) {
3285+
PyObject *item = o->ob_item[i];
3286+
_PyGC_MoveToReachable(item, reachable, visited_space);
3287+
}
3288+
}
3289+
32793290
static int
32803291
list_traverse(PyObject *self, visitproc visit, void *arg)
32813292
{

Objects/setobject.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -492,11 +492,6 @@ set_next(PySetObject *so, Py_ssize_t *pos_ptr, setentry **entry_ptr)
492492
return 1;
493493
}
494494

495-
int _PyTemporary_SetNext(PySetObject *so, Py_ssize_t *pos_ptr, setentry **entry_ptr)
496-
{
497-
return set_next(so, pos_ptr, entry_ptr);
498-
}
499-
500495
static void
501496
set_dealloc(PyObject *self)
502497
{
@@ -705,6 +700,17 @@ set_traverse(PyObject *self, visitproc visit, void *arg)
705700
return 0;
706701
}
707702

703+
void
704+
_PySet_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
705+
{
706+
PySetObject *so = (PySetObject *)op;
707+
Py_ssize_t pos = 0;
708+
setentry *entry;
709+
while (set_next(so, &pos, &entry)) {
710+
_PyGC_MoveToReachable(entry->key, reachable, visited_space);
711+
}
712+
}
713+
708714
/* Work to increase the bit dispersion for closely spaced hash values.
709715
This is important because some use cases have many combinations of a
710716
small number of elements with nearby hashes so that many distinct

Objects/tupleobject.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,16 @@ tuple_count(PyTupleObject *self, PyObject *value)
623623
return PyLong_FromSsize_t(count);
624624
}
625625

626+
void
627+
_PyTuple_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
628+
{
629+
PyTupleObject *o = (PyTupleObject *)op;
630+
for (Py_ssize_t i = Py_SIZE(o); --i >= 0; ) {
631+
PyObject *item = o->ob_item[i];
632+
_PyGC_MoveToReachable(item, reachable, visited_space);
633+
}
634+
}
635+
626636
static int
627637
tuple_traverse(PyObject *self, visitproc visit, void *arg)
628638
{

Objects/typeobject.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6214,6 +6214,19 @@ PyDoc_STRVAR(type_doc,
62146214
"type(object) -> the object's type\n"
62156215
"type(name, bases, dict, **kwds) -> a new type");
62166216

6217+
6218+
void
6219+
_PyType_MoveToReachable(PyObject *op, PyGC_Head *reachable, int visited_space)
6220+
{
6221+
PyTypeObject *type = (PyTypeObject *)op;
6222+
_PyGC_MoveToReachable(type->tp_dict, reachable, visited_space);
6223+
_PyGC_MoveToReachable(type->tp_cache, reachable, visited_space);
6224+
_PyGC_MoveToReachable(type->tp_mro, reachable, visited_space);
6225+
_PyGC_MoveToReachable(type->tp_bases, reachable, visited_space);
6226+
_PyGC_MoveToReachable((PyObject *)type->tp_base, reachable, visited_space);
6227+
_PyGC_MoveToReachable(((PyHeapTypeObject *)type)->ht_module, reachable, visited_space);
6228+
}
6229+
62176230
static int
62186231
type_traverse(PyObject *self, visitproc visit, void *arg)
62196232
{

0 commit comments

Comments
 (0)