Skip to content

Commit 3038a78

Browse files
committed
Faster marking of reachable objects
1 parent b0fcc2c commit 3038a78

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
@@ -1433,6 +1433,7 @@ move_to_reachable(PyObject *op, PyGC_Head *reachable, int visited_space)
14331433
return 0;
14341434
}
14351435

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

14591519
static Py_ssize_t

0 commit comments

Comments
 (0)