@@ -1401,10 +1401,32 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
1401
1401
return n + m ;
1402
1402
}
1403
1403
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
+
1404
1426
struct get_referrers_args {
1405
1427
struct visitor_args base ;
1406
1428
PyObject * objs ;
1407
- struct worklist results ;
1429
+ _PyObjectStack results ;
1408
1430
};
1409
1431
1410
1432
static int
@@ -1428,11 +1450,21 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
1428
1450
if (op == NULL ) {
1429
1451
return true;
1430
1452
}
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
+ }
1431
1458
1432
1459
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
+ }
1433
1464
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
+ }
1436
1468
}
1437
1469
1438
1470
return true;
@@ -1441,48 +1473,25 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
1441
1473
PyObject *
1442
1474
_PyGC_GetReferrers (PyInterpreterState * interp , PyObject * objs )
1443
1475
{
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.
1455
1479
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 );
1473
1482
_PyEval_StartTheWorld (interp );
1474
1483
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 );
1478
1488
}
1479
-
1480
- return result ;
1489
+ return list ;
1481
1490
}
1482
1491
1483
1492
struct get_objects_args {
1484
1493
struct visitor_args base ;
1485
- struct worklist objects ;
1494
+ _PyObjectStack objects ;
1486
1495
};
1487
1496
1488
1497
static bool
@@ -1493,54 +1502,36 @@ visit_get_objects(const mi_heap_t *heap, const mi_heap_area_t *area,
1493
1502
if (op == NULL ) {
1494
1503
return true;
1495
1504
}
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
+ }
1496
1510
1497
1511
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
+ }
1501
1515
return true;
1502
1516
}
1503
1517
1504
1518
PyObject *
1505
1519
_PyGC_GetObjects (PyInterpreterState * interp , int generation )
1506
1520
{
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.
1518
1524
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 );
1536
1527
_PyEval_StartTheWorld (interp );
1537
1528
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 );
1541
1533
}
1542
-
1543
- return result ;
1534
+ return list ;
1544
1535
}
1545
1536
1546
1537
static bool
0 commit comments