Skip to content

Commit a94d30d

Browse files
committed
Faster marking of reachable objects
1 parent f495c2b commit a94d30d

File tree

1 file changed

+65
-5
lines changed

1 file changed

+65
-5
lines changed

Python/gc.c

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,7 @@ move_to_reachable(PyObject *op, PyGC_Head *reachable, int visited_space)
14351435
return 0;
14361436
}
14371437

1438+
14381439
static Py_ssize_t
14391440
mark_all_reachable(PyGC_Head *reachable, PyGC_Head *visited, int visited_space)
14401441
{
@@ -1444,18 +1445,77 @@ mark_all_reachable(PyGC_Head *reachable, PyGC_Head *visited, int visited_space)
14441445
.visited_space = visited_space,
14451446
.size = 0
14461447
};
1448+
Py_ssize_t objects_marked = 0;
14471449
while (!gc_list_is_empty(reachable)) {
14481450
PyGC_Head *gc = _PyGCHead_NEXT(reachable);
14491451
assert(gc_old_space(gc) == visited_space);
14501452
gc_list_move(gc, visited);
14511453
PyObject *op = FROM_GC(gc);
1452-
traverseproc traverse = Py_TYPE(op)->tp_traverse;
1453-
(void) traverse(op,
1454-
visit_add_to_container,
1455-
&arg);
1454+
assert(PyObject_IS_GC(op));
1455+
switch(Py_TYPE(op)->tp_version_tag) {
1456+
case _Py_TYPE_VERSION_LIST:
1457+
{
1458+
PyListObject *o = (PyListObject *)op;
1459+
Py_ssize_t i;
1460+
for (i = Py_SIZE(o); --i >= 0; ) {
1461+
PyObject *item = o->ob_item[i];
1462+
objects_marked += move_to_reachable(item, reachable, visited_space);
1463+
}
1464+
break;
1465+
}
1466+
case _Py_TYPE_VERSION_TUPLE:
1467+
{
1468+
PyTupleObject *o = (PyTupleObject *)op;
1469+
for (Py_ssize_t i = Py_SIZE(o); --i >= 0; ) {
1470+
PyObject *item = o->ob_item[i];
1471+
objects_marked += move_to_reachable(item, reachable, visited_space);
1472+
}
1473+
break;
1474+
}
1475+
case _Py_TYPE_VERSION_DICT:
1476+
{
1477+
PyDictObject *mp = (PyDictObject *)op;
1478+
PyDictKeysObject *keys = mp->ma_keys;
1479+
Py_ssize_t i, n = keys->dk_nentries;
1480+
if (DK_IS_UNICODE(keys)) {
1481+
if (_PyDict_HasSplitTable(mp)) {
1482+
if (!mp->ma_values->embedded) {
1483+
for (i = 0; i < n; i++) {
1484+
PyObject *value = mp->ma_values->values[i];
1485+
objects_marked += move_to_reachable(value, reachable, visited_space);
1486+
}
1487+
}
1488+
}
1489+
else {
1490+
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
1491+
for (i = 0; i < n; i++) {
1492+
PyObject *value = entries[i].me_value;
1493+
objects_marked += move_to_reachable(value, reachable, visited_space);
1494+
}
1495+
}
1496+
}
1497+
else {
1498+
PyDictKeyEntry *entries = DK_ENTRIES(keys);
1499+
for (i = 0; i < n; i++) {
1500+
if (entries[i].me_value != NULL) {
1501+
PyObject *key = entries[i].me_key;
1502+
objects_marked += move_to_reachable(key, reachable, visited_space);
1503+
PyObject *value = entries[i].me_value;
1504+
objects_marked += move_to_reachable(value, reachable, visited_space);
1505+
}
1506+
}
1507+
}
1508+
break;
1509+
}
1510+
default:
1511+
{
1512+
traverseproc traverse = Py_TYPE(op)->tp_traverse;
1513+
(void) traverse(op, visit_add_to_container, &arg);
1514+
}
1515+
}
14561516
}
14571517
gc_list_validate_space(visited, visited_space);
1458-
return arg.size;
1518+
return objects_marked + arg.size;
14591519
}
14601520

14611521
static Py_ssize_t

0 commit comments

Comments
 (0)