@@ -1281,10 +1281,32 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
12811281    return  n  +  m ;
12821282}
12831283
1284+ static  PyObject  * 
1285+ list_from_object_stack (_PyObjectStack  * stack )
1286+ {
1287+     PyObject  * list  =  PyList_New (_PyObjectStack_Size (stack ));
1288+     if  (list  ==  NULL ) {
1289+         PyObject  * op ;
1290+         while  ((op  =  _PyObjectStack_Pop (stack )) !=  NULL ) {
1291+             Py_DECREF (op );
1292+         }
1293+         return  NULL ;
1294+     }
1295+ 
1296+     PyObject  * op ;
1297+     Py_ssize_t  idx  =  0 ;
1298+     while  ((op  =  _PyObjectStack_Pop (stack )) !=  NULL ) {
1299+         assert (idx  <  PyList_GET_SIZE (list ));
1300+         PyList_SET_ITEM (list , idx ++ , op );
1301+     }
1302+     assert (idx  ==  PyList_GET_SIZE (list ));
1303+     return  list ;
1304+ }
1305+ 
12841306struct  get_referrers_args  {
12851307    struct  visitor_args  base ;
12861308    PyObject  * objs ;
1287-     struct   worklist  results ;
1309+     _PyObjectStack  results ;
12881310};
12891311
12901312static  int 
@@ -1308,11 +1330,21 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
13081330    if  (op  ==  NULL ) {
13091331        return  true;
13101332    }
1333+     if  (op -> ob_gc_bits  &  (_PyGC_BITS_UNREACHABLE  | _PyGC_BITS_FROZEN )) {
1334+         // Exclude unreachable objects (in-progress GC) and frozen 
1335+         // objects from gc.get_objects() to match the default build. 
1336+         return  true;
1337+     }
13111338
13121339    struct  get_referrers_args  * arg  =  (struct  get_referrers_args  * )args ;
1340+     if  (op  ==  arg -> objs ) {
1341+         // Don't include the tuple itself in the referrers list. 
1342+         return  true;
1343+     }
13131344    if  (Py_TYPE (op )-> tp_traverse (op , referrersvisit , arg -> objs )) {
1314-         op -> ob_tid  =  0 ;  // we will restore the refcount later 
1315-         worklist_push (& arg -> results , op );
1345+         if  (_PyObjectStack_Push (& arg -> results , Py_NewRef (op )) <  0 ) {
1346+             return  false;
1347+         }
13161348    }
13171349
13181350    return  true;
@@ -1321,48 +1353,25 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
13211353PyObject  * 
13221354_PyGC_GetReferrers (PyInterpreterState  * interp , PyObject  * objs )
13231355{
1324-     PyObject  * result  =  PyList_New (0 );
1325-     if  (!result ) {
1326-         return  NULL ;
1327-     }
1328- 
1329-     _PyEval_StopTheWorld (interp );
1330- 
1331-     // Append all objects to a worklist. This abuses ob_tid. We will restore 
1332-     // it later. NOTE: We can't append to the PyListObject during 
1333-     // gc_visit_heaps() because PyList_Append() may reclaim an abandoned 
1334-     // mimalloc segments while we are traversing them. 
1356+     // NOTE: We can't append to the PyListObject during gc_visit_heaps() 
1357+     // because PyList_Append() may reclaim an abandoned mimalloc segments 
1358+     // while we are traversing them. 
13351359    struct  get_referrers_args  args  =  { .objs  =  objs  };
1336-     gc_visit_heaps (interp , & visit_get_referrers , & args .base );
1337- 
1338-     bool  error  =  false;
1339-     PyObject  * op ;
1340-     while  ((op  =  worklist_pop (& args .results )) !=  NULL ) {
1341-         gc_restore_tid (op );
1342-         if  (op  !=  objs  &&  PyList_Append (result , op ) <  0 ) {
1343-             error  =  true;
1344-             break ;
1345-         }
1346-     }
1347- 
1348-     // In case of error, clear the remaining worklist 
1349-     while  ((op  =  worklist_pop (& args .results )) !=  NULL ) {
1350-         gc_restore_tid (op );
1351-     }
1352- 
1360+     _PyEval_StopTheWorld (interp );
1361+     int  err  =  gc_visit_heaps (interp , & visit_get_referrers , & args .base );
13531362    _PyEval_StartTheWorld (interp );
13541363
1355-     if  (error ) {
1356-         Py_DECREF (result );
1357-         return  NULL ;
1364+     PyObject  * list  =  list_from_object_stack (& args .results );
1365+     if  (err  <  0 ) {
1366+         PyErr_NoMemory ();
1367+         Py_CLEAR (list );
13581368    }
1359- 
1360-     return  result ;
1369+     return  list ;
13611370}
13621371
13631372struct  get_objects_args  {
13641373    struct  visitor_args  base ;
1365-     struct   worklist  objects ;
1374+     _PyObjectStack  objects ;
13661375};
13671376
13681377static  bool 
@@ -1373,54 +1382,36 @@ visit_get_objects(const mi_heap_t *heap, const mi_heap_area_t *area,
13731382    if  (op  ==  NULL ) {
13741383        return  true;
13751384    }
1385+     if  (op -> ob_gc_bits  &  (_PyGC_BITS_UNREACHABLE  | _PyGC_BITS_FROZEN )) {
1386+         // Exclude unreachable objects (in-progress GC) and frozen 
1387+         // objects from gc.get_objects() to match the default build. 
1388+         return  true;
1389+     }
13761390
13771391    struct  get_objects_args  * arg  =  (struct  get_objects_args  * )args ;
1378-     op -> ob_tid   =   0 ;   // we will restore the refcount later 
1379-     worklist_push ( & arg -> objects ,  op ) ;
1380- 
1392+     if  ( _PyObjectStack_Push ( & arg -> objects ,  Py_NewRef ( op ))  <   0 ) { 
1393+          return  false ;
1394+     } 
13811395    return  true;
13821396}
13831397
13841398PyObject  * 
13851399_PyGC_GetObjects (PyInterpreterState  * interp , int  generation )
13861400{
1387-     PyObject  * result  =  PyList_New (0 );
1388-     if  (!result ) {
1389-         return  NULL ;
1390-     }
1391- 
1392-     _PyEval_StopTheWorld (interp );
1393- 
1394-     // Append all objects to a worklist. This abuses ob_tid. We will restore 
1395-     // it later. NOTE: We can't append to the list during gc_visit_heaps() 
1396-     // because PyList_Append() may reclaim an abandoned mimalloc segment 
1397-     // while we are traversing it. 
1401+     // NOTE: We can't append to the PyListObject during gc_visit_heaps() 
1402+     // because PyList_Append() may reclaim an abandoned mimalloc segments 
1403+     // while we are traversing them. 
13981404    struct  get_objects_args  args  =  { 0  };
1399-     gc_visit_heaps (interp , & visit_get_objects , & args .base );
1400- 
1401-     bool  error  =  false;
1402-     PyObject  * op ;
1403-     while  ((op  =  worklist_pop (& args .objects )) !=  NULL ) {
1404-         gc_restore_tid (op );
1405-         if  (op  !=  result  &&  PyList_Append (result , op ) <  0 ) {
1406-             error  =  true;
1407-             break ;
1408-         }
1409-     }
1410- 
1411-     // In case of error, clear the remaining worklist 
1412-     while  ((op  =  worklist_pop (& args .objects )) !=  NULL ) {
1413-         gc_restore_tid (op );
1414-     }
1415- 
1405+     _PyEval_StopTheWorld (interp );
1406+     int  err  =  gc_visit_heaps (interp , & visit_get_objects , & args .base );
14161407    _PyEval_StartTheWorld (interp );
14171408
1418-     if  (error ) {
1419-         Py_DECREF (result );
1420-         return  NULL ;
1409+     PyObject  * list  =  list_from_object_stack (& args .objects );
1410+     if  (err  <  0 ) {
1411+         PyErr_NoMemory ();
1412+         Py_CLEAR (list );
14211413    }
1422- 
1423-     return  result ;
1414+     return  list ;
14241415}
14251416
14261417static  bool 
0 commit comments