@@ -1281,10 +1281,32 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
1281
1281
return n + m ;
1282
1282
}
1283
1283
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
+
1284
1306
struct get_referrers_args {
1285
1307
struct visitor_args base ;
1286
1308
PyObject * objs ;
1287
- struct worklist results ;
1309
+ _PyObjectStack results ;
1288
1310
};
1289
1311
1290
1312
static int
@@ -1308,11 +1330,21 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
1308
1330
if (op == NULL ) {
1309
1331
return true;
1310
1332
}
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
+ }
1311
1338
1312
1339
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
+ }
1313
1344
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
+ }
1316
1348
}
1317
1349
1318
1350
return true;
@@ -1321,48 +1353,25 @@ visit_get_referrers(const mi_heap_t *heap, const mi_heap_area_t *area,
1321
1353
PyObject *
1322
1354
_PyGC_GetReferrers (PyInterpreterState * interp , PyObject * objs )
1323
1355
{
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.
1335
1359
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 );
1353
1362
_PyEval_StartTheWorld (interp );
1354
1363
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 );
1358
1368
}
1359
-
1360
- return result ;
1369
+ return list ;
1361
1370
}
1362
1371
1363
1372
struct get_objects_args {
1364
1373
struct visitor_args base ;
1365
- struct worklist objects ;
1374
+ _PyObjectStack objects ;
1366
1375
};
1367
1376
1368
1377
static bool
@@ -1373,54 +1382,36 @@ visit_get_objects(const mi_heap_t *heap, const mi_heap_area_t *area,
1373
1382
if (op == NULL ) {
1374
1383
return true;
1375
1384
}
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
+ }
1376
1390
1377
1391
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
+ }
1381
1395
return true;
1382
1396
}
1383
1397
1384
1398
PyObject *
1385
1399
_PyGC_GetObjects (PyInterpreterState * interp , int generation )
1386
1400
{
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.
1398
1404
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 );
1416
1407
_PyEval_StartTheWorld (interp );
1417
1408
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 );
1421
1413
}
1422
-
1423
- return result ;
1414
+ return list ;
1424
1415
}
1425
1416
1426
1417
static bool
0 commit comments