@@ -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