@@ -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
14371471static Py_ssize_t
14381472mark_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