@@ -1404,7 +1404,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
1404
1404
struct get_referrers_args {
1405
1405
struct visitor_args base ;
1406
1406
PyObject * objs ;
1407
- struct worklist results ;
1407
+ _PyObjectStack results ;
1408
1408
};
1409
1409
1410
1410
static int
@@ -1428,11 +1428,17 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
1428
1428
if (op == NULL ) {
1429
1429
return true;
1430
1430
}
1431
+ if (op -> ob_gc_bits & (_PyGC_BITS_UNREACHABLE | _PyGC_BITS_FROZEN )) {
1432
+ // Exclude unreachable objects (in-progress GC) and frozen
1433
+ // objects from gc.get_objects() to match the default build.
1434
+ return true;
1435
+ }
1431
1436
1432
1437
struct get_referrers_args * arg = (struct get_referrers_args * )args ;
1433
1438
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 );
1439
+ if (_PyObjectStack_Push (& arg -> results , op ) < 0 ) {
1440
+ return false;
1441
+ }
1436
1442
}
1437
1443
1438
1444
return true;
@@ -1446,43 +1452,36 @@ _PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs)
1446
1452
return NULL ;
1447
1453
}
1448
1454
1455
+ // NOTE: We can't append to the PyListObject during gc_visit_heaps()
1456
+ // because PyList_Append() may reclaim an abandoned mimalloc segments
1457
+ // while we are traversing them.
1458
+ struct get_referrers_args args = { .objs = objs };
1449
1459
_PyEval_StopTheWorld (interp );
1460
+ int err = gc_visit_heaps (interp , & visit_get_referrers , & args .base );
1461
+ _PyEval_StartTheWorld (interp );
1450
1462
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.
1455
- struct get_referrers_args args = { .objs = objs };
1456
- gc_visit_heaps (interp , & visit_get_referrers , & args .base );
1463
+ if (err < 0 ) {
1464
+ PyErr_NoMemory ();
1465
+ goto error ;
1466
+ }
1457
1467
1458
- bool error = false;
1459
1468
PyObject * op ;
1460
- while ((op = worklist_pop (& args .results )) != NULL ) {
1461
- gc_restore_tid (op );
1469
+ while ((op = _PyObjectStack_Pop (& args .results )) != NULL ) {
1462
1470
if (op != objs && PyList_Append (result , op ) < 0 ) {
1463
- error = true;
1464
- break ;
1471
+ goto error ;
1465
1472
}
1466
1473
}
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
-
1473
- _PyEval_StartTheWorld (interp );
1474
-
1475
- if (error ) {
1476
- Py_DECREF (result );
1477
- return NULL ;
1478
- }
1479
-
1480
1474
return result ;
1475
+
1476
+ error :
1477
+ Py_DECREF (result );
1478
+ _PyObjectStack_Clear (& args .results );
1479
+ return NULL ;
1481
1480
}
1482
1481
1483
1482
struct get_objects_args {
1484
1483
struct visitor_args base ;
1485
- struct worklist objects ;
1484
+ _PyObjectStack objects ;
1486
1485
};
1487
1486
1488
1487
static bool
@@ -1493,11 +1492,16 @@ visit_get_objects(const mi_heap_t *heap, const mi_heap_area_t *area,
1493
1492
if (op == NULL ) {
1494
1493
return true;
1495
1494
}
1495
+ if (op -> ob_gc_bits & (_PyGC_BITS_UNREACHABLE | _PyGC_BITS_FROZEN )) {
1496
+ // Exclude unreachable objects (in-progress GC) and frozen
1497
+ // objects from gc.get_objects() to match the default build.
1498
+ return true;
1499
+ }
1496
1500
1497
1501
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
-
1502
+ if ( _PyObjectStack_Push ( & arg -> objects , op ) < 0 ) {
1503
+ return false ;
1504
+ }
1501
1505
return true;
1502
1506
}
1503
1507
@@ -1509,38 +1513,31 @@ _PyGC_GetObjects(PyInterpreterState *interp, int generation)
1509
1513
return NULL ;
1510
1514
}
1511
1515
1516
+ // NOTE: We can't append to the PyListObject during gc_visit_heaps()
1517
+ // because PyList_Append() may reclaim an abandoned mimalloc segments
1518
+ // while we are traversing them.
1519
+ struct get_objects_args args = { 0 };
1512
1520
_PyEval_StopTheWorld (interp );
1521
+ int err = gc_visit_heaps (interp , & visit_get_objects , & args .base );
1522
+ _PyEval_StartTheWorld (interp );
1513
1523
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.
1518
- struct get_objects_args args = { 0 };
1519
- gc_visit_heaps (interp , & visit_get_objects , & args .base );
1524
+ if (err < 0 ) {
1525
+ PyErr_NoMemory ();
1526
+ goto error ;
1527
+ }
1520
1528
1521
- bool error = false;
1522
1529
PyObject * op ;
1523
- while ((op = worklist_pop (& args .objects )) != NULL ) {
1524
- gc_restore_tid (op );
1530
+ while ((op = _PyObjectStack_Pop (& args .objects )) != NULL ) {
1525
1531
if (op != result && PyList_Append (result , op ) < 0 ) {
1526
- error = true;
1527
- break ;
1532
+ goto error ;
1528
1533
}
1529
1534
}
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
-
1536
- _PyEval_StartTheWorld (interp );
1537
-
1538
- if (error ) {
1539
- Py_DECREF (result );
1540
- return NULL ;
1541
- }
1542
-
1543
1535
return result ;
1536
+
1537
+ error :
1538
+ Py_DECREF (result );
1539
+ _PyObjectStack_Clear (& args .objects );
1540
+ return NULL ;
1544
1541
}
1545
1542
1546
1543
static bool
0 commit comments