Skip to content

Commit c024484

Browse files
committed
Handle more classes in fast marking
1 parent 3038a78 commit c024484

File tree

6 files changed

+100
-58
lines changed

6 files changed

+100
-58
lines changed

Include/internal/pycore_typeobject.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ extern "C" {
2525
#define _Py_TYPE_VERSION_BYTEARRAY 9
2626
#define _Py_TYPE_VERSION_BYTES 10
2727
#define _Py_TYPE_VERSION_COMPLEX 11
28+
#define _Py_TYPE_VERSION_GENERATOR 12
29+
#define _Py_TYPE_VERSION_COROUTINE 13
30+
#define _Py_TYPE_VERSION_MODULE 14
31+
#define _Py_TYPE_VERSION_TYPE 15
2832

2933
#define _Py_TYPE_VERSION_NEXT 16
3034

Objects/genobject.c

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -876,25 +876,8 @@ PyTypeObject PyGen_Type = {
876876
gen_methods, /* tp_methods */
877877
gen_memberlist, /* tp_members */
878878
gen_getsetlist, /* tp_getset */
879-
0, /* tp_base */
880-
0, /* tp_dict */
881-
882-
0, /* tp_descr_get */
883-
0, /* tp_descr_set */
884-
0, /* tp_dictoffset */
885-
0, /* tp_init */
886-
0, /* tp_alloc */
887-
0, /* tp_new */
888-
0, /* tp_free */
889-
0, /* tp_is_gc */
890-
0, /* tp_bases */
891-
0, /* tp_mro */
892-
0, /* tp_cache */
893-
0, /* tp_subclasses */
894-
0, /* tp_weaklist */
895-
0, /* tp_del */
896-
0, /* tp_version_tag */
897-
_PyGen_Finalize, /* tp_finalize */
879+
.tp_finalize = _PyGen_Finalize,
880+
.tp_version_tag = _Py_TYPE_VERSION_GENERATOR,
898881
};
899882

900883
static PyObject *
@@ -1236,24 +1219,8 @@ PyTypeObject PyCoro_Type = {
12361219
coro_methods, /* tp_methods */
12371220
coro_memberlist, /* tp_members */
12381221
coro_getsetlist, /* tp_getset */
1239-
0, /* tp_base */
1240-
0, /* tp_dict */
1241-
0, /* tp_descr_get */
1242-
0, /* tp_descr_set */
1243-
0, /* tp_dictoffset */
1244-
0, /* tp_init */
1245-
0, /* tp_alloc */
1246-
0, /* tp_new */
1247-
0, /* tp_free */
1248-
0, /* tp_is_gc */
1249-
0, /* tp_bases */
1250-
0, /* tp_mro */
1251-
0, /* tp_cache */
1252-
0, /* tp_subclasses */
1253-
0, /* tp_weaklist */
1254-
0, /* tp_del */
1255-
0, /* tp_version_tag */
1256-
_PyGen_Finalize, /* tp_finalize */
1222+
.tp_finalize = _PyGen_Finalize,
1223+
.tp_version_tag = _Py_TYPE_VERSION_COROUTINE,
12571224
};
12581225

12591226
static void

Objects/moduleobject.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,4 +1356,5 @@ PyTypeObject PyModule_Type = {
13561356
0, /* tp_alloc */
13571357
new_module, /* tp_new */
13581358
PyObject_GC_Del, /* tp_free */
1359+
.tp_version_tag = _Py_TYPE_VERSION_MODULE,
13591360
};

Objects/setobject.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,11 @@ 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+
495500
static void
496501
set_dealloc(PyObject *self)
497502
{

Objects/typeobject.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6351,6 +6351,7 @@ PyTypeObject PyType_Type = {
63516351
PyObject_GC_Del, /* tp_free */
63526352
type_is_gc, /* tp_is_gc */
63536353
.tp_vectorcall = type_vectorcall,
6354+
.tp_version_tag = _Py_TYPE_VERSION_TYPE,
63546355
};
63556356

63566357

Python/gc.c

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,40 @@ move_to_reachable(PyObject *op, PyGC_Head *reachable, int visited_space)
14331433
return 0;
14341434
}
14351435

1436+
static Py_ssize_t
1437+
move_frame_to_reachable(_PyInterpreterFrame *frame, PyGC_Head *reachable, int visited_space)
1438+
{
1439+
_PyStackRef *locals = frame->localsplus;
1440+
_PyStackRef *sp = frame->stackpointer;
1441+
Py_ssize_t objects_marked = move_to_reachable(frame->f_locals, reachable, visited_space);
1442+
PyObject *func = PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
1443+
objects_marked += move_to_reachable(func, reachable, visited_space);
1444+
while (sp > locals) {
1445+
sp--;
1446+
if (PyStackRef_IsNull(*sp)) {
1447+
continue;
1448+
}
1449+
PyObject *op = PyStackRef_AsPyObjectBorrow(*sp);
1450+
if (!_Py_IsImmortal(op) && _PyObject_IS_GC(op)) {
1451+
PyGC_Head *gc = AS_GC(op);
1452+
if (_PyObject_GC_IS_TRACKED(op) &&
1453+
gc_old_space(gc) != visited_space) {
1454+
gc_flip_old_space(gc);
1455+
objects_marked++;
1456+
gc_list_move(gc, reachable);
1457+
}
1458+
}
1459+
}
1460+
return objects_marked;
1461+
}
1462+
1463+
/* This should be refactored:
1464+
* 1. Make `move_to_reachable` an inline "private API" function
1465+
* 2. Move bodies of each case below into a _PyXXX_MarkReachable function in file for type XXX.
1466+
* 3. Trust lto to inline those functions.
1467+
*/
1468+
1469+
extern int _PyTemporary_SetNext(PySetObject *so, Py_ssize_t *pos_ptr, setentry **entry_ptr);
14361470

14371471
static Py_ssize_t
14381472
mark_all_reachable(PyGC_Head *reachable, PyGC_Head *visited, int visited_space)
@@ -1470,6 +1504,19 @@ mark_all_reachable(PyGC_Head *reachable, PyGC_Head *visited, int visited_space)
14701504
}
14711505
break;
14721506
}
1507+
case _Py_TYPE_VERSION_MODULE:
1508+
{
1509+
PyModuleObject *m = (PyModuleObject *)op;
1510+
/* bpo-39824: Don't call m_traverse() if m_size > 0 and md_state=NULL */
1511+
if (m->md_def && m->md_def->m_traverse
1512+
&& (m->md_def->m_size <= 0 || m->md_state != NULL))
1513+
{
1514+
m->md_def->m_traverse(op, visit_add_to_container, &arg);
1515+
}
1516+
op = m->md_dict;
1517+
assert (op != NULL);
1518+
}
1519+
/* fall through */
14731520
case _Py_TYPE_VERSION_DICT:
14741521
{
14751522
PyDictObject *mp = (PyDictObject *)op;
@@ -1505,6 +1552,43 @@ mark_all_reachable(PyGC_Head *reachable, PyGC_Head *visited, int visited_space)
15051552
}
15061553
break;
15071554
}
1555+
case _Py_TYPE_VERSION_SET:
1556+
case _Py_TYPE_VERSION_FROZEN_SET:
1557+
{
1558+
PySetObject *so = (PySetObject *)op;
1559+
Py_ssize_t pos = 0;
1560+
setentry *entry;
1561+
while (_PyTemporary_SetNext(so, &pos, &entry)) {
1562+
objects_marked += move_to_reachable(entry->key, reachable, visited_space);
1563+
}
1564+
break;
1565+
}
1566+
case _Py_TYPE_VERSION_COROUTINE:
1567+
case _Py_TYPE_VERSION_GENERATOR:
1568+
{
1569+
PyGenObject *gen = (PyGenObject *)op;
1570+
if (gen->gi_frame_state == FRAME_CLEARED) {
1571+
break;
1572+
}
1573+
objects_marked += move_to_reachable(gen->gi_exc_state.exc_value, reachable, visited_space);
1574+
if (gen->gi_frame_state != FRAME_EXECUTING) {
1575+
/* if executing we already traversed it on the stack */
1576+
_PyInterpreterFrame *frame = &gen->gi_iframe;
1577+
objects_marked += move_frame_to_reachable(frame, reachable, visited_space);
1578+
}
1579+
break;
1580+
}
1581+
case _Py_TYPE_VERSION_TYPE:
1582+
{
1583+
PyTypeObject *type = (PyTypeObject *)op;
1584+
objects_marked += move_to_reachable(type->tp_dict, reachable, visited_space);
1585+
objects_marked += move_to_reachable(type->tp_cache, reachable, visited_space);
1586+
objects_marked += move_to_reachable(type->tp_mro, reachable, visited_space);
1587+
objects_marked += move_to_reachable(type->tp_bases, reachable, visited_space);
1588+
objects_marked += move_to_reachable((PyObject *)type->tp_base, reachable, visited_space);
1589+
objects_marked += move_to_reachable(((PyHeapTypeObject *)type)->ht_module, reachable, visited_space);
1590+
break;
1591+
}
15081592
default:
15091593
{
15101594
traverseproc traverse = Py_TYPE(op)->tp_traverse;
@@ -1557,27 +1641,7 @@ mark_stacks(PyInterpreterState *interp, PyGC_Head *visited, int visited_space, b
15571641
frame = frame->previous;
15581642
continue;
15591643
}
1560-
_PyStackRef *locals = frame->localsplus;
1561-
_PyStackRef *sp = frame->stackpointer;
1562-
objects_marked += move_to_reachable(frame->f_locals, &reachable, visited_space);
1563-
PyObject *func = PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
1564-
objects_marked += move_to_reachable(func, &reachable, visited_space);
1565-
while (sp > locals) {
1566-
sp--;
1567-
if (PyStackRef_IsNull(*sp)) {
1568-
continue;
1569-
}
1570-
PyObject *op = PyStackRef_AsPyObjectBorrow(*sp);
1571-
if (!_Py_IsImmortal(op) && _PyObject_IS_GC(op)) {
1572-
PyGC_Head *gc = AS_GC(op);
1573-
if (_PyObject_GC_IS_TRACKED(op) &&
1574-
gc_old_space(gc) != visited_space) {
1575-
gc_flip_old_space(gc);
1576-
objects_marked++;
1577-
gc_list_move(gc, &reachable);
1578-
}
1579-
}
1580-
}
1644+
objects_marked += move_frame_to_reachable(frame, &reachable, visited_space);
15811645
if (!start && frame->visited) {
15821646
// If this frame has already been visited, then the lower frames
15831647
// will have already been visited and will not have changed

0 commit comments

Comments
 (0)