@@ -1401,10 +1401,32 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
14011401 return n + m ;
14021402}
14031403
1404+ static PyObject *
1405+ list_from_object_stack (_PyObjectStack * stack )
1406+ {
1407+ PyObject * list = PyList_New (_PyObjectStack_Size (stack ));
1408+ if (list == NULL ) {
1409+ PyObject * op ;
1410+ while ((op = _PyObjectStack_Pop (stack )) != NULL ) {
1411+ Py_DECREF (op );
1412+ }
1413+ return NULL ;
1414+ }
1415+
1416+ PyObject * op ;
1417+ Py_ssize_t idx = 0 ;
1418+ while ((op = _PyObjectStack_Pop (stack )) != NULL ) {
1419+ assert (idx < PyList_GET_SIZE (list ));
1420+ PyList_SET_ITEM (list , idx ++ , op );
1421+ }
1422+ assert (idx == PyList_GET_SIZE (list ));
1423+ return list ;
1424+ }
1425+
14041426struct get_referrers_args {
14051427 struct visitor_args base ;
14061428 PyObject * objs ;
1407- struct worklist results ;
1429+ _PyObjectStack results ;
14081430};
14091431
14101432static int
@@ -1428,11 +1450,21 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
14281450 if (op == NULL ) {
14291451 return true;
14301452 }
1453+ if (op -> ob_gc_bits & (_PyGC_BITS_UNREACHABLE | _PyGC_BITS_FROZEN )) {
1454+ // Exclude unreachable objects (in-progress GC) and frozen
1455+ // objects from gc.get_objects() to match the default build.
1456+ return true;
1457+ }
14311458
14321459 struct get_referrers_args * arg = (struct get_referrers_args * )args ;
1460+ if (op == arg -> objs ) {
1461+ // Don't include the tuple itself in the referrers list.
1462+ return true;
1463+ }
14331464 if (Py_TYPE (op )-> tp_traverse (op , referrersvisit , arg -> objs )) {
1434- op -> ob_tid = 0 ; // we will restore the refcount later
1435- worklist_push (& arg -> results , op );
1465+ if (_PyObjectStack_Push (& arg -> results , Py_NewRef (op )) < 0 ) {
1466+ return false;
1467+ }
14361468 }
14371469
14381470 return true;
@@ -1441,48 +1473,25 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
14411473PyObject *
14421474_PyGC_GetReferrers (PyInterpreterState * interp , PyObject * objs )
14431475{
1444- PyObject * result = PyList_New (0 );
1445- if (!result ) {
1446- return NULL ;
1447- }
1448-
1449- _PyEval_StopTheWorld (interp );
1450-
1451- // Append all objects to a worklist. This abuses ob_tid. We will restore
1452- // it later. NOTE: We can't append to the PyListObject during
1453- // gc_visit_heaps() because PyList_Append() may reclaim an abandoned
1454- // mimalloc segments while we are traversing them.
1476+ // NOTE: We can't append to the PyListObject during gc_visit_heaps()
1477+ // because PyList_Append() may reclaim an abandoned mimalloc segments
1478+ // while we are traversing them.
14551479 struct get_referrers_args args = { .objs = objs };
1456- gc_visit_heaps (interp , & visit_get_referrers , & args .base );
1457-
1458- bool error = false;
1459- PyObject * op ;
1460- while ((op = worklist_pop (& args .results )) != NULL ) {
1461- gc_restore_tid (op );
1462- if (op != objs && PyList_Append (result , op ) < 0 ) {
1463- error = true;
1464- break ;
1465- }
1466- }
1467-
1468- // In case of error, clear the remaining worklist
1469- while ((op = worklist_pop (& args .results )) != NULL ) {
1470- gc_restore_tid (op );
1471- }
1472-
1480+ _PyEval_StopTheWorld (interp );
1481+ int err = gc_visit_heaps (interp , & visit_get_referrers , & args .base );
14731482 _PyEval_StartTheWorld (interp );
14741483
1475- if (error ) {
1476- Py_DECREF (result );
1477- return NULL ;
1484+ PyObject * list = list_from_object_stack (& args .results );
1485+ if (err < 0 ) {
1486+ PyErr_NoMemory ();
1487+ Py_CLEAR (list );
14781488 }
1479-
1480- return result ;
1489+ return list ;
14811490}
14821491
14831492struct get_objects_args {
14841493 struct visitor_args base ;
1485- struct worklist objects ;
1494+ _PyObjectStack objects ;
14861495};
14871496
14881497static bool
@@ -1493,54 +1502,36 @@ visit_get_objects(const mi_heap_t *heap, const mi_heap_area_t *area,
14931502 if (op == NULL ) {
14941503 return true;
14951504 }
1505+ if (op -> ob_gc_bits & (_PyGC_BITS_UNREACHABLE | _PyGC_BITS_FROZEN )) {
1506+ // Exclude unreachable objects (in-progress GC) and frozen
1507+ // objects from gc.get_objects() to match the default build.
1508+ return true;
1509+ }
14961510
14971511 struct get_objects_args * arg = (struct get_objects_args * )args ;
1498- op -> ob_tid = 0 ; // we will restore the refcount later
1499- worklist_push ( & arg -> objects , op ) ;
1500-
1512+ if ( _PyObjectStack_Push ( & arg -> objects , Py_NewRef ( op )) < 0 ) {
1513+ return false ;
1514+ }
15011515 return true;
15021516}
15031517
15041518PyObject *
15051519_PyGC_GetObjects (PyInterpreterState * interp , int generation )
15061520{
1507- PyObject * result = PyList_New (0 );
1508- if (!result ) {
1509- return NULL ;
1510- }
1511-
1512- _PyEval_StopTheWorld (interp );
1513-
1514- // Append all objects to a worklist. This abuses ob_tid. We will restore
1515- // it later. NOTE: We can't append to the list during gc_visit_heaps()
1516- // because PyList_Append() may reclaim an abandoned mimalloc segment
1517- // while we are traversing it.
1521+ // NOTE: We can't append to the PyListObject during gc_visit_heaps()
1522+ // because PyList_Append() may reclaim an abandoned mimalloc segments
1523+ // while we are traversing them.
15181524 struct get_objects_args args = { 0 };
1519- gc_visit_heaps (interp , & visit_get_objects , & args .base );
1520-
1521- bool error = false;
1522- PyObject * op ;
1523- while ((op = worklist_pop (& args .objects )) != NULL ) {
1524- gc_restore_tid (op );
1525- if (op != result && PyList_Append (result , op ) < 0 ) {
1526- error = true;
1527- break ;
1528- }
1529- }
1530-
1531- // In case of error, clear the remaining worklist
1532- while ((op = worklist_pop (& args .objects )) != NULL ) {
1533- gc_restore_tid (op );
1534- }
1535-
1525+ _PyEval_StopTheWorld (interp );
1526+ int err = gc_visit_heaps (interp , & visit_get_objects , & args .base );
15361527 _PyEval_StartTheWorld (interp );
15371528
1538- if (error ) {
1539- Py_DECREF (result );
1540- return NULL ;
1529+ PyObject * list = list_from_object_stack (& args .objects );
1530+ if (err < 0 ) {
1531+ PyErr_NoMemory ();
1532+ Py_CLEAR (list );
15411533 }
1542-
1543- return result ;
1534+ return list ;
15441535}
15451536
15461537static bool
0 commit comments