17db96d56Sopenharmony_ci/*
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci  Reference Cycle Garbage Collection
47db96d56Sopenharmony_ci  ==================================
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ci  Neil Schemenauer <nas@arctrix.com>
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci  Based on a post on the python-dev list.  Ideas from Guido van Rossum,
97db96d56Sopenharmony_ci  Eric Tiedemann, and various others.
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ci  http://www.arctrix.com/nas/python/gc/
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci  The following mailing list threads provide a historical perspective on
147db96d56Sopenharmony_ci  the design of this module.  Note that a fair amount of refinement has
157db96d56Sopenharmony_ci  occurred since those discussions.
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ci  http://mail.python.org/pipermail/python-dev/2000-March/002385.html
187db96d56Sopenharmony_ci  http://mail.python.org/pipermail/python-dev/2000-March/002434.html
197db96d56Sopenharmony_ci  http://mail.python.org/pipermail/python-dev/2000-March/002497.html
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci  For a highlevel view of the collection process, read the collect
227db96d56Sopenharmony_ci  function.
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci*/
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci#include "Python.h"
277db96d56Sopenharmony_ci#include "pycore_context.h"
287db96d56Sopenharmony_ci#include "pycore_initconfig.h"
297db96d56Sopenharmony_ci#include "pycore_interp.h"      // PyInterpreterState.gc
307db96d56Sopenharmony_ci#include "pycore_object.h"
317db96d56Sopenharmony_ci#include "pycore_pyerrors.h"
327db96d56Sopenharmony_ci#include "pycore_pystate.h"     // _PyThreadState_GET()
337db96d56Sopenharmony_ci#include "pydtrace.h"
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_citypedef struct _gc_runtime_state GCState;
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci/*[clinic input]
387db96d56Sopenharmony_cimodule gc
397db96d56Sopenharmony_ci[clinic start generated code]*/
407db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b5c9690ecc842d79]*/
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci#ifdef Py_DEBUG
447db96d56Sopenharmony_ci#  define GC_DEBUG
457db96d56Sopenharmony_ci#endif
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci#define GC_NEXT _PyGCHead_NEXT
487db96d56Sopenharmony_ci#define GC_PREV _PyGCHead_PREV
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_ci// update_refs() set this bit for all objects in current generation.
517db96d56Sopenharmony_ci// subtract_refs() and move_unreachable() uses this to distinguish
527db96d56Sopenharmony_ci// visited object is in GCing or not.
537db96d56Sopenharmony_ci//
547db96d56Sopenharmony_ci// move_unreachable() removes this flag from reachable objects.
557db96d56Sopenharmony_ci// Only unreachable objects have this flag.
567db96d56Sopenharmony_ci//
577db96d56Sopenharmony_ci// No objects in interpreter have this flag after GC ends.
587db96d56Sopenharmony_ci#define PREV_MASK_COLLECTING   _PyGC_PREV_MASK_COLLECTING
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci// Lowest bit of _gc_next is used for UNREACHABLE flag.
617db96d56Sopenharmony_ci//
627db96d56Sopenharmony_ci// This flag represents the object is in unreachable list in move_unreachable()
637db96d56Sopenharmony_ci//
647db96d56Sopenharmony_ci// Although this flag is used only in move_unreachable(), move_unreachable()
657db96d56Sopenharmony_ci// doesn't clear this flag to skip unnecessary iteration.
667db96d56Sopenharmony_ci// move_legacy_finalizers() removes this flag instead.
677db96d56Sopenharmony_ci// Between them, unreachable list is not normal list and we can not use
687db96d56Sopenharmony_ci// most gc_list_* functions for it.
697db96d56Sopenharmony_ci#define NEXT_MASK_UNREACHABLE  (1)
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci/* Get an object's GC head */
727db96d56Sopenharmony_ci#define AS_GC(o) ((PyGC_Head *)(((char *)(o))-sizeof(PyGC_Head)))
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci/* Get the object given the GC head */
757db96d56Sopenharmony_ci#define FROM_GC(g) ((PyObject *)(((char *)(g))+sizeof(PyGC_Head)))
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_cistatic inline int
787db96d56Sopenharmony_cigc_is_collecting(PyGC_Head *g)
797db96d56Sopenharmony_ci{
807db96d56Sopenharmony_ci    return (g->_gc_prev & PREV_MASK_COLLECTING) != 0;
817db96d56Sopenharmony_ci}
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_cistatic inline void
847db96d56Sopenharmony_cigc_clear_collecting(PyGC_Head *g)
857db96d56Sopenharmony_ci{
867db96d56Sopenharmony_ci    g->_gc_prev &= ~PREV_MASK_COLLECTING;
877db96d56Sopenharmony_ci}
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_cistatic inline Py_ssize_t
907db96d56Sopenharmony_cigc_get_refs(PyGC_Head *g)
917db96d56Sopenharmony_ci{
927db96d56Sopenharmony_ci    return (Py_ssize_t)(g->_gc_prev >> _PyGC_PREV_SHIFT);
937db96d56Sopenharmony_ci}
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_cistatic inline void
967db96d56Sopenharmony_cigc_set_refs(PyGC_Head *g, Py_ssize_t refs)
977db96d56Sopenharmony_ci{
987db96d56Sopenharmony_ci    g->_gc_prev = (g->_gc_prev & ~_PyGC_PREV_MASK)
997db96d56Sopenharmony_ci        | ((uintptr_t)(refs) << _PyGC_PREV_SHIFT);
1007db96d56Sopenharmony_ci}
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_cistatic inline void
1037db96d56Sopenharmony_cigc_reset_refs(PyGC_Head *g, Py_ssize_t refs)
1047db96d56Sopenharmony_ci{
1057db96d56Sopenharmony_ci    g->_gc_prev = (g->_gc_prev & _PyGC_PREV_MASK_FINALIZED)
1067db96d56Sopenharmony_ci        | PREV_MASK_COLLECTING
1077db96d56Sopenharmony_ci        | ((uintptr_t)(refs) << _PyGC_PREV_SHIFT);
1087db96d56Sopenharmony_ci}
1097db96d56Sopenharmony_ci
1107db96d56Sopenharmony_cistatic inline void
1117db96d56Sopenharmony_cigc_decref(PyGC_Head *g)
1127db96d56Sopenharmony_ci{
1137db96d56Sopenharmony_ci    _PyObject_ASSERT_WITH_MSG(FROM_GC(g),
1147db96d56Sopenharmony_ci                              gc_get_refs(g) > 0,
1157db96d56Sopenharmony_ci                              "refcount is too small");
1167db96d56Sopenharmony_ci    g->_gc_prev -= 1 << _PyGC_PREV_SHIFT;
1177db96d56Sopenharmony_ci}
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_ci/* set for debugging information */
1207db96d56Sopenharmony_ci#define DEBUG_STATS             (1<<0) /* print collection statistics */
1217db96d56Sopenharmony_ci#define DEBUG_COLLECTABLE       (1<<1) /* print collectable objects */
1227db96d56Sopenharmony_ci#define DEBUG_UNCOLLECTABLE     (1<<2) /* print uncollectable objects */
1237db96d56Sopenharmony_ci#define DEBUG_SAVEALL           (1<<5) /* save all garbage in gc.garbage */
1247db96d56Sopenharmony_ci#define DEBUG_LEAK              DEBUG_COLLECTABLE | \
1257db96d56Sopenharmony_ci                DEBUG_UNCOLLECTABLE | \
1267db96d56Sopenharmony_ci                DEBUG_SAVEALL
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci#define GEN_HEAD(gcstate, n) (&(gcstate)->generations[n].head)
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_cistatic GCState *
1327db96d56Sopenharmony_ciget_gc_state(void)
1337db96d56Sopenharmony_ci{
1347db96d56Sopenharmony_ci    PyInterpreterState *interp = _PyInterpreterState_GET();
1357db96d56Sopenharmony_ci    return &interp->gc;
1367db96d56Sopenharmony_ci}
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_civoid
1407db96d56Sopenharmony_ci_PyGC_InitState(GCState *gcstate)
1417db96d56Sopenharmony_ci{
1427db96d56Sopenharmony_ci#define INIT_HEAD(GEN) \
1437db96d56Sopenharmony_ci    do { \
1447db96d56Sopenharmony_ci        GEN.head._gc_next = (uintptr_t)&GEN.head; \
1457db96d56Sopenharmony_ci        GEN.head._gc_prev = (uintptr_t)&GEN.head; \
1467db96d56Sopenharmony_ci    } while (0)
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci    for (int i = 0; i < NUM_GENERATIONS; i++) {
1497db96d56Sopenharmony_ci        assert(gcstate->generations[i].count == 0);
1507db96d56Sopenharmony_ci        INIT_HEAD(gcstate->generations[i]);
1517db96d56Sopenharmony_ci    };
1527db96d56Sopenharmony_ci    gcstate->generation0 = GEN_HEAD(gcstate, 0);
1537db96d56Sopenharmony_ci    INIT_HEAD(gcstate->permanent_generation);
1547db96d56Sopenharmony_ci
1557db96d56Sopenharmony_ci#undef INIT_HEAD
1567db96d56Sopenharmony_ci}
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_ciPyStatus
1607db96d56Sopenharmony_ci_PyGC_Init(PyInterpreterState *interp)
1617db96d56Sopenharmony_ci{
1627db96d56Sopenharmony_ci    GCState *gcstate = &interp->gc;
1637db96d56Sopenharmony_ci
1647db96d56Sopenharmony_ci    gcstate->garbage = PyList_New(0);
1657db96d56Sopenharmony_ci    if (gcstate->garbage == NULL) {
1667db96d56Sopenharmony_ci        return _PyStatus_NO_MEMORY();
1677db96d56Sopenharmony_ci    }
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci    gcstate->callbacks = PyList_New(0);
1707db96d56Sopenharmony_ci    if (gcstate->callbacks == NULL) {
1717db96d56Sopenharmony_ci        return _PyStatus_NO_MEMORY();
1727db96d56Sopenharmony_ci    }
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    return _PyStatus_OK();
1757db96d56Sopenharmony_ci}
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci/*
1797db96d56Sopenharmony_ci_gc_prev values
1807db96d56Sopenharmony_ci---------------
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ciBetween collections, _gc_prev is used for doubly linked list.
1837db96d56Sopenharmony_ci
1847db96d56Sopenharmony_ciLowest two bits of _gc_prev are used for flags.
1857db96d56Sopenharmony_ciPREV_MASK_COLLECTING is used only while collecting and cleared before GC ends
1867db96d56Sopenharmony_cior _PyObject_GC_UNTRACK() is called.
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ciDuring a collection, _gc_prev is temporary used for gc_refs, and the gc list
1897db96d56Sopenharmony_ciis singly linked until _gc_prev is restored.
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_cigc_refs
1927db96d56Sopenharmony_ci    At the start of a collection, update_refs() copies the true refcount
1937db96d56Sopenharmony_ci    to gc_refs, for each object in the generation being collected.
1947db96d56Sopenharmony_ci    subtract_refs() then adjusts gc_refs so that it equals the number of
1957db96d56Sopenharmony_ci    times an object is referenced directly from outside the generation
1967db96d56Sopenharmony_ci    being collected.
1977db96d56Sopenharmony_ci
1987db96d56Sopenharmony_ciPREV_MASK_COLLECTING
1997db96d56Sopenharmony_ci    Objects in generation being collected are marked PREV_MASK_COLLECTING in
2007db96d56Sopenharmony_ci    update_refs().
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci_gc_next values
2047db96d56Sopenharmony_ci---------------
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci_gc_next takes these values:
2077db96d56Sopenharmony_ci
2087db96d56Sopenharmony_ci0
2097db96d56Sopenharmony_ci    The object is not tracked
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci!= 0
2127db96d56Sopenharmony_ci    Pointer to the next object in the GC list.
2137db96d56Sopenharmony_ci    Additionally, lowest bit is used temporary for
2147db96d56Sopenharmony_ci    NEXT_MASK_UNREACHABLE flag described below.
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ciNEXT_MASK_UNREACHABLE
2177db96d56Sopenharmony_ci    move_unreachable() then moves objects not reachable (whether directly or
2187db96d56Sopenharmony_ci    indirectly) from outside the generation into an "unreachable" set and
2197db96d56Sopenharmony_ci    set this flag.
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci    Objects that are found to be reachable have gc_refs set to 1.
2227db96d56Sopenharmony_ci    When this flag is set for the reachable object, the object must be in
2237db96d56Sopenharmony_ci    "unreachable" set.
2247db96d56Sopenharmony_ci    The flag is unset and the object is moved back to "reachable" set.
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci    move_legacy_finalizers() will remove this flag from "unreachable" set.
2277db96d56Sopenharmony_ci*/
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci/*** list functions ***/
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_cistatic inline void
2327db96d56Sopenharmony_cigc_list_init(PyGC_Head *list)
2337db96d56Sopenharmony_ci{
2347db96d56Sopenharmony_ci    // List header must not have flags.
2357db96d56Sopenharmony_ci    // We can assign pointer by simple cast.
2367db96d56Sopenharmony_ci    list->_gc_prev = (uintptr_t)list;
2377db96d56Sopenharmony_ci    list->_gc_next = (uintptr_t)list;
2387db96d56Sopenharmony_ci}
2397db96d56Sopenharmony_ci
2407db96d56Sopenharmony_cistatic inline int
2417db96d56Sopenharmony_cigc_list_is_empty(PyGC_Head *list)
2427db96d56Sopenharmony_ci{
2437db96d56Sopenharmony_ci    return (list->_gc_next == (uintptr_t)list);
2447db96d56Sopenharmony_ci}
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci/* Append `node` to `list`. */
2477db96d56Sopenharmony_cistatic inline void
2487db96d56Sopenharmony_cigc_list_append(PyGC_Head *node, PyGC_Head *list)
2497db96d56Sopenharmony_ci{
2507db96d56Sopenharmony_ci    PyGC_Head *last = (PyGC_Head *)list->_gc_prev;
2517db96d56Sopenharmony_ci
2527db96d56Sopenharmony_ci    // last <-> node
2537db96d56Sopenharmony_ci    _PyGCHead_SET_PREV(node, last);
2547db96d56Sopenharmony_ci    _PyGCHead_SET_NEXT(last, node);
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci    // node <-> list
2577db96d56Sopenharmony_ci    _PyGCHead_SET_NEXT(node, list);
2587db96d56Sopenharmony_ci    list->_gc_prev = (uintptr_t)node;
2597db96d56Sopenharmony_ci}
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci/* Remove `node` from the gc list it's currently in. */
2627db96d56Sopenharmony_cistatic inline void
2637db96d56Sopenharmony_cigc_list_remove(PyGC_Head *node)
2647db96d56Sopenharmony_ci{
2657db96d56Sopenharmony_ci    PyGC_Head *prev = GC_PREV(node);
2667db96d56Sopenharmony_ci    PyGC_Head *next = GC_NEXT(node);
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci    _PyGCHead_SET_NEXT(prev, next);
2697db96d56Sopenharmony_ci    _PyGCHead_SET_PREV(next, prev);
2707db96d56Sopenharmony_ci
2717db96d56Sopenharmony_ci    node->_gc_next = 0; /* object is not currently tracked */
2727db96d56Sopenharmony_ci}
2737db96d56Sopenharmony_ci
2747db96d56Sopenharmony_ci/* Move `node` from the gc list it's currently in (which is not explicitly
2757db96d56Sopenharmony_ci * named here) to the end of `list`.  This is semantically the same as
2767db96d56Sopenharmony_ci * gc_list_remove(node) followed by gc_list_append(node, list).
2777db96d56Sopenharmony_ci */
2787db96d56Sopenharmony_cistatic void
2797db96d56Sopenharmony_cigc_list_move(PyGC_Head *node, PyGC_Head *list)
2807db96d56Sopenharmony_ci{
2817db96d56Sopenharmony_ci    /* Unlink from current list. */
2827db96d56Sopenharmony_ci    PyGC_Head *from_prev = GC_PREV(node);
2837db96d56Sopenharmony_ci    PyGC_Head *from_next = GC_NEXT(node);
2847db96d56Sopenharmony_ci    _PyGCHead_SET_NEXT(from_prev, from_next);
2857db96d56Sopenharmony_ci    _PyGCHead_SET_PREV(from_next, from_prev);
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci    /* Relink at end of new list. */
2887db96d56Sopenharmony_ci    // list must not have flags.  So we can skip macros.
2897db96d56Sopenharmony_ci    PyGC_Head *to_prev = (PyGC_Head*)list->_gc_prev;
2907db96d56Sopenharmony_ci    _PyGCHead_SET_PREV(node, to_prev);
2917db96d56Sopenharmony_ci    _PyGCHead_SET_NEXT(to_prev, node);
2927db96d56Sopenharmony_ci    list->_gc_prev = (uintptr_t)node;
2937db96d56Sopenharmony_ci    _PyGCHead_SET_NEXT(node, list);
2947db96d56Sopenharmony_ci}
2957db96d56Sopenharmony_ci
2967db96d56Sopenharmony_ci/* append list `from` onto list `to`; `from` becomes an empty list */
2977db96d56Sopenharmony_cistatic void
2987db96d56Sopenharmony_cigc_list_merge(PyGC_Head *from, PyGC_Head *to)
2997db96d56Sopenharmony_ci{
3007db96d56Sopenharmony_ci    assert(from != to);
3017db96d56Sopenharmony_ci    if (!gc_list_is_empty(from)) {
3027db96d56Sopenharmony_ci        PyGC_Head *to_tail = GC_PREV(to);
3037db96d56Sopenharmony_ci        PyGC_Head *from_head = GC_NEXT(from);
3047db96d56Sopenharmony_ci        PyGC_Head *from_tail = GC_PREV(from);
3057db96d56Sopenharmony_ci        assert(from_head != from);
3067db96d56Sopenharmony_ci        assert(from_tail != from);
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ci        _PyGCHead_SET_NEXT(to_tail, from_head);
3097db96d56Sopenharmony_ci        _PyGCHead_SET_PREV(from_head, to_tail);
3107db96d56Sopenharmony_ci
3117db96d56Sopenharmony_ci        _PyGCHead_SET_NEXT(from_tail, to);
3127db96d56Sopenharmony_ci        _PyGCHead_SET_PREV(to, from_tail);
3137db96d56Sopenharmony_ci    }
3147db96d56Sopenharmony_ci    gc_list_init(from);
3157db96d56Sopenharmony_ci}
3167db96d56Sopenharmony_ci
3177db96d56Sopenharmony_cistatic Py_ssize_t
3187db96d56Sopenharmony_cigc_list_size(PyGC_Head *list)
3197db96d56Sopenharmony_ci{
3207db96d56Sopenharmony_ci    PyGC_Head *gc;
3217db96d56Sopenharmony_ci    Py_ssize_t n = 0;
3227db96d56Sopenharmony_ci    for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(gc)) {
3237db96d56Sopenharmony_ci        n++;
3247db96d56Sopenharmony_ci    }
3257db96d56Sopenharmony_ci    return n;
3267db96d56Sopenharmony_ci}
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci/* Walk the list and mark all objects as non-collecting */
3297db96d56Sopenharmony_cistatic inline void
3307db96d56Sopenharmony_cigc_list_clear_collecting(PyGC_Head *collectable)
3317db96d56Sopenharmony_ci{
3327db96d56Sopenharmony_ci    PyGC_Head *gc;
3337db96d56Sopenharmony_ci    for (gc = GC_NEXT(collectable); gc != collectable; gc = GC_NEXT(gc)) {
3347db96d56Sopenharmony_ci        gc_clear_collecting(gc);
3357db96d56Sopenharmony_ci    }
3367db96d56Sopenharmony_ci}
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_ci/* Append objects in a GC list to a Python list.
3397db96d56Sopenharmony_ci * Return 0 if all OK, < 0 if error (out of memory for list)
3407db96d56Sopenharmony_ci */
3417db96d56Sopenharmony_cistatic int
3427db96d56Sopenharmony_ciappend_objects(PyObject *py_list, PyGC_Head *gc_list)
3437db96d56Sopenharmony_ci{
3447db96d56Sopenharmony_ci    PyGC_Head *gc;
3457db96d56Sopenharmony_ci    for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) {
3467db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
3477db96d56Sopenharmony_ci        if (op != py_list) {
3487db96d56Sopenharmony_ci            if (PyList_Append(py_list, op)) {
3497db96d56Sopenharmony_ci                return -1; /* exception */
3507db96d56Sopenharmony_ci            }
3517db96d56Sopenharmony_ci        }
3527db96d56Sopenharmony_ci    }
3537db96d56Sopenharmony_ci    return 0;
3547db96d56Sopenharmony_ci}
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_ci// Constants for validate_list's flags argument.
3577db96d56Sopenharmony_cienum flagstates {collecting_clear_unreachable_clear,
3587db96d56Sopenharmony_ci                 collecting_clear_unreachable_set,
3597db96d56Sopenharmony_ci                 collecting_set_unreachable_clear,
3607db96d56Sopenharmony_ci                 collecting_set_unreachable_set};
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci#ifdef GC_DEBUG
3637db96d56Sopenharmony_ci// validate_list checks list consistency.  And it works as document
3647db96d56Sopenharmony_ci// describing when flags are expected to be set / unset.
3657db96d56Sopenharmony_ci// `head` must be a doubly-linked gc list, although it's fine (expected!) if
3667db96d56Sopenharmony_ci// the prev and next pointers are "polluted" with flags.
3677db96d56Sopenharmony_ci// What's checked:
3687db96d56Sopenharmony_ci// - The `head` pointers are not polluted.
3697db96d56Sopenharmony_ci// - The objects' PREV_MASK_COLLECTING and NEXT_MASK_UNREACHABLE flags are all
3707db96d56Sopenharmony_ci//   `set or clear, as specified by the 'flags' argument.
3717db96d56Sopenharmony_ci// - The prev and next pointers are mutually consistent.
3727db96d56Sopenharmony_cistatic void
3737db96d56Sopenharmony_civalidate_list(PyGC_Head *head, enum flagstates flags)
3747db96d56Sopenharmony_ci{
3757db96d56Sopenharmony_ci    assert((head->_gc_prev & PREV_MASK_COLLECTING) == 0);
3767db96d56Sopenharmony_ci    assert((head->_gc_next & NEXT_MASK_UNREACHABLE) == 0);
3777db96d56Sopenharmony_ci    uintptr_t prev_value = 0, next_value = 0;
3787db96d56Sopenharmony_ci    switch (flags) {
3797db96d56Sopenharmony_ci        case collecting_clear_unreachable_clear:
3807db96d56Sopenharmony_ci            break;
3817db96d56Sopenharmony_ci        case collecting_set_unreachable_clear:
3827db96d56Sopenharmony_ci            prev_value = PREV_MASK_COLLECTING;
3837db96d56Sopenharmony_ci            break;
3847db96d56Sopenharmony_ci        case collecting_clear_unreachable_set:
3857db96d56Sopenharmony_ci            next_value = NEXT_MASK_UNREACHABLE;
3867db96d56Sopenharmony_ci            break;
3877db96d56Sopenharmony_ci        case collecting_set_unreachable_set:
3887db96d56Sopenharmony_ci            prev_value = PREV_MASK_COLLECTING;
3897db96d56Sopenharmony_ci            next_value = NEXT_MASK_UNREACHABLE;
3907db96d56Sopenharmony_ci            break;
3917db96d56Sopenharmony_ci        default:
3927db96d56Sopenharmony_ci            assert(! "bad internal flags argument");
3937db96d56Sopenharmony_ci    }
3947db96d56Sopenharmony_ci    PyGC_Head *prev = head;
3957db96d56Sopenharmony_ci    PyGC_Head *gc = GC_NEXT(head);
3967db96d56Sopenharmony_ci    while (gc != head) {
3977db96d56Sopenharmony_ci        PyGC_Head *trueprev = GC_PREV(gc);
3987db96d56Sopenharmony_ci        PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next  & ~NEXT_MASK_UNREACHABLE);
3997db96d56Sopenharmony_ci        assert(truenext != NULL);
4007db96d56Sopenharmony_ci        assert(trueprev == prev);
4017db96d56Sopenharmony_ci        assert((gc->_gc_prev & PREV_MASK_COLLECTING) == prev_value);
4027db96d56Sopenharmony_ci        assert((gc->_gc_next & NEXT_MASK_UNREACHABLE) == next_value);
4037db96d56Sopenharmony_ci        prev = gc;
4047db96d56Sopenharmony_ci        gc = truenext;
4057db96d56Sopenharmony_ci    }
4067db96d56Sopenharmony_ci    assert(prev == GC_PREV(head));
4077db96d56Sopenharmony_ci}
4087db96d56Sopenharmony_ci#else
4097db96d56Sopenharmony_ci#define validate_list(x, y) do{}while(0)
4107db96d56Sopenharmony_ci#endif
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci/*** end of list stuff ***/
4137db96d56Sopenharmony_ci
4147db96d56Sopenharmony_ci
4157db96d56Sopenharmony_ci/* Set all gc_refs = ob_refcnt.  After this, gc_refs is > 0 and
4167db96d56Sopenharmony_ci * PREV_MASK_COLLECTING bit is set for all objects in containers.
4177db96d56Sopenharmony_ci */
4187db96d56Sopenharmony_cistatic void
4197db96d56Sopenharmony_ciupdate_refs(PyGC_Head *containers)
4207db96d56Sopenharmony_ci{
4217db96d56Sopenharmony_ci    PyGC_Head *gc = GC_NEXT(containers);
4227db96d56Sopenharmony_ci    for (; gc != containers; gc = GC_NEXT(gc)) {
4237db96d56Sopenharmony_ci        gc_reset_refs(gc, Py_REFCNT(FROM_GC(gc)));
4247db96d56Sopenharmony_ci        /* Python's cyclic gc should never see an incoming refcount
4257db96d56Sopenharmony_ci         * of 0:  if something decref'ed to 0, it should have been
4267db96d56Sopenharmony_ci         * deallocated immediately at that time.
4277db96d56Sopenharmony_ci         * Possible cause (if the assert triggers):  a tp_dealloc
4287db96d56Sopenharmony_ci         * routine left a gc-aware object tracked during its teardown
4297db96d56Sopenharmony_ci         * phase, and did something-- or allowed something to happen --
4307db96d56Sopenharmony_ci         * that called back into Python.  gc can trigger then, and may
4317db96d56Sopenharmony_ci         * see the still-tracked dying object.  Before this assert
4327db96d56Sopenharmony_ci         * was added, such mistakes went on to allow gc to try to
4337db96d56Sopenharmony_ci         * delete the object again.  In a debug build, that caused
4347db96d56Sopenharmony_ci         * a mysterious segfault, when _Py_ForgetReference tried
4357db96d56Sopenharmony_ci         * to remove the object from the doubly-linked list of all
4367db96d56Sopenharmony_ci         * objects a second time.  In a release build, an actual
4377db96d56Sopenharmony_ci         * double deallocation occurred, which leads to corruption
4387db96d56Sopenharmony_ci         * of the allocator's internal bookkeeping pointers.  That's
4397db96d56Sopenharmony_ci         * so serious that maybe this should be a release-build
4407db96d56Sopenharmony_ci         * check instead of an assert?
4417db96d56Sopenharmony_ci         */
4427db96d56Sopenharmony_ci        _PyObject_ASSERT(FROM_GC(gc), gc_get_refs(gc) != 0);
4437db96d56Sopenharmony_ci    }
4447db96d56Sopenharmony_ci}
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci/* A traversal callback for subtract_refs. */
4477db96d56Sopenharmony_cistatic int
4487db96d56Sopenharmony_civisit_decref(PyObject *op, void *parent)
4497db96d56Sopenharmony_ci{
4507db96d56Sopenharmony_ci    _PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op));
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ci    if (_PyObject_IS_GC(op)) {
4537db96d56Sopenharmony_ci        PyGC_Head *gc = AS_GC(op);
4547db96d56Sopenharmony_ci        /* We're only interested in gc_refs for objects in the
4557db96d56Sopenharmony_ci         * generation being collected, which can be recognized
4567db96d56Sopenharmony_ci         * because only they have positive gc_refs.
4577db96d56Sopenharmony_ci         */
4587db96d56Sopenharmony_ci        if (gc_is_collecting(gc)) {
4597db96d56Sopenharmony_ci            gc_decref(gc);
4607db96d56Sopenharmony_ci        }
4617db96d56Sopenharmony_ci    }
4627db96d56Sopenharmony_ci    return 0;
4637db96d56Sopenharmony_ci}
4647db96d56Sopenharmony_ci
4657db96d56Sopenharmony_ci/* Subtract internal references from gc_refs.  After this, gc_refs is >= 0
4667db96d56Sopenharmony_ci * for all objects in containers, and is GC_REACHABLE for all tracked gc
4677db96d56Sopenharmony_ci * objects not in containers.  The ones with gc_refs > 0 are directly
4687db96d56Sopenharmony_ci * reachable from outside containers, and so can't be collected.
4697db96d56Sopenharmony_ci */
4707db96d56Sopenharmony_cistatic void
4717db96d56Sopenharmony_cisubtract_refs(PyGC_Head *containers)
4727db96d56Sopenharmony_ci{
4737db96d56Sopenharmony_ci    traverseproc traverse;
4747db96d56Sopenharmony_ci    PyGC_Head *gc = GC_NEXT(containers);
4757db96d56Sopenharmony_ci    for (; gc != containers; gc = GC_NEXT(gc)) {
4767db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
4777db96d56Sopenharmony_ci        traverse = Py_TYPE(op)->tp_traverse;
4787db96d56Sopenharmony_ci        (void) traverse(op,
4797db96d56Sopenharmony_ci                        (visitproc)visit_decref,
4807db96d56Sopenharmony_ci                        op);
4817db96d56Sopenharmony_ci    }
4827db96d56Sopenharmony_ci}
4837db96d56Sopenharmony_ci
4847db96d56Sopenharmony_ci/* A traversal callback for move_unreachable. */
4857db96d56Sopenharmony_cistatic int
4867db96d56Sopenharmony_civisit_reachable(PyObject *op, PyGC_Head *reachable)
4877db96d56Sopenharmony_ci{
4887db96d56Sopenharmony_ci    if (!_PyObject_IS_GC(op)) {
4897db96d56Sopenharmony_ci        return 0;
4907db96d56Sopenharmony_ci    }
4917db96d56Sopenharmony_ci
4927db96d56Sopenharmony_ci    PyGC_Head *gc = AS_GC(op);
4937db96d56Sopenharmony_ci    const Py_ssize_t gc_refs = gc_get_refs(gc);
4947db96d56Sopenharmony_ci
4957db96d56Sopenharmony_ci    // Ignore objects in other generation.
4967db96d56Sopenharmony_ci    // This also skips objects "to the left" of the current position in
4977db96d56Sopenharmony_ci    // move_unreachable's scan of the 'young' list - they've already been
4987db96d56Sopenharmony_ci    // traversed, and no longer have the PREV_MASK_COLLECTING flag.
4997db96d56Sopenharmony_ci    if (! gc_is_collecting(gc)) {
5007db96d56Sopenharmony_ci        return 0;
5017db96d56Sopenharmony_ci    }
5027db96d56Sopenharmony_ci    // It would be a logic error elsewhere if the collecting flag were set on
5037db96d56Sopenharmony_ci    // an untracked object.
5047db96d56Sopenharmony_ci    assert(gc->_gc_next != 0);
5057db96d56Sopenharmony_ci
5067db96d56Sopenharmony_ci    if (gc->_gc_next & NEXT_MASK_UNREACHABLE) {
5077db96d56Sopenharmony_ci        /* This had gc_refs = 0 when move_unreachable got
5087db96d56Sopenharmony_ci         * to it, but turns out it's reachable after all.
5097db96d56Sopenharmony_ci         * Move it back to move_unreachable's 'young' list,
5107db96d56Sopenharmony_ci         * and move_unreachable will eventually get to it
5117db96d56Sopenharmony_ci         * again.
5127db96d56Sopenharmony_ci         */
5137db96d56Sopenharmony_ci        // Manually unlink gc from unreachable list because the list functions
5147db96d56Sopenharmony_ci        // don't work right in the presence of NEXT_MASK_UNREACHABLE flags.
5157db96d56Sopenharmony_ci        PyGC_Head *prev = GC_PREV(gc);
5167db96d56Sopenharmony_ci        PyGC_Head *next = (PyGC_Head*)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
5177db96d56Sopenharmony_ci        _PyObject_ASSERT(FROM_GC(prev),
5187db96d56Sopenharmony_ci                         prev->_gc_next & NEXT_MASK_UNREACHABLE);
5197db96d56Sopenharmony_ci        _PyObject_ASSERT(FROM_GC(next),
5207db96d56Sopenharmony_ci                         next->_gc_next & NEXT_MASK_UNREACHABLE);
5217db96d56Sopenharmony_ci        prev->_gc_next = gc->_gc_next;  // copy NEXT_MASK_UNREACHABLE
5227db96d56Sopenharmony_ci        _PyGCHead_SET_PREV(next, prev);
5237db96d56Sopenharmony_ci
5247db96d56Sopenharmony_ci        gc_list_append(gc, reachable);
5257db96d56Sopenharmony_ci        gc_set_refs(gc, 1);
5267db96d56Sopenharmony_ci    }
5277db96d56Sopenharmony_ci    else if (gc_refs == 0) {
5287db96d56Sopenharmony_ci        /* This is in move_unreachable's 'young' list, but
5297db96d56Sopenharmony_ci         * the traversal hasn't yet gotten to it.  All
5307db96d56Sopenharmony_ci         * we need to do is tell move_unreachable that it's
5317db96d56Sopenharmony_ci         * reachable.
5327db96d56Sopenharmony_ci         */
5337db96d56Sopenharmony_ci        gc_set_refs(gc, 1);
5347db96d56Sopenharmony_ci    }
5357db96d56Sopenharmony_ci    /* Else there's nothing to do.
5367db96d56Sopenharmony_ci     * If gc_refs > 0, it must be in move_unreachable's 'young'
5377db96d56Sopenharmony_ci     * list, and move_unreachable will eventually get to it.
5387db96d56Sopenharmony_ci     */
5397db96d56Sopenharmony_ci    else {
5407db96d56Sopenharmony_ci        _PyObject_ASSERT_WITH_MSG(op, gc_refs > 0, "refcount is too small");
5417db96d56Sopenharmony_ci    }
5427db96d56Sopenharmony_ci    return 0;
5437db96d56Sopenharmony_ci}
5447db96d56Sopenharmony_ci
5457db96d56Sopenharmony_ci/* Move the unreachable objects from young to unreachable.  After this,
5467db96d56Sopenharmony_ci * all objects in young don't have PREV_MASK_COLLECTING flag and
5477db96d56Sopenharmony_ci * unreachable have the flag.
5487db96d56Sopenharmony_ci * All objects in young after this are directly or indirectly reachable
5497db96d56Sopenharmony_ci * from outside the original young; and all objects in unreachable are
5507db96d56Sopenharmony_ci * not.
5517db96d56Sopenharmony_ci *
5527db96d56Sopenharmony_ci * This function restores _gc_prev pointer.  young and unreachable are
5537db96d56Sopenharmony_ci * doubly linked list after this function.
5547db96d56Sopenharmony_ci * But _gc_next in unreachable list has NEXT_MASK_UNREACHABLE flag.
5557db96d56Sopenharmony_ci * So we can not gc_list_* functions for unreachable until we remove the flag.
5567db96d56Sopenharmony_ci */
5577db96d56Sopenharmony_cistatic void
5587db96d56Sopenharmony_cimove_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
5597db96d56Sopenharmony_ci{
5607db96d56Sopenharmony_ci    // previous elem in the young list, used for restore gc_prev.
5617db96d56Sopenharmony_ci    PyGC_Head *prev = young;
5627db96d56Sopenharmony_ci    PyGC_Head *gc = GC_NEXT(young);
5637db96d56Sopenharmony_ci
5647db96d56Sopenharmony_ci    /* Invariants:  all objects "to the left" of us in young are reachable
5657db96d56Sopenharmony_ci     * (directly or indirectly) from outside the young list as it was at entry.
5667db96d56Sopenharmony_ci     *
5677db96d56Sopenharmony_ci     * All other objects from the original young "to the left" of us are in
5687db96d56Sopenharmony_ci     * unreachable now, and have NEXT_MASK_UNREACHABLE.  All objects to the
5697db96d56Sopenharmony_ci     * left of us in 'young' now have been scanned, and no objects here
5707db96d56Sopenharmony_ci     * or to the right have been scanned yet.
5717db96d56Sopenharmony_ci     */
5727db96d56Sopenharmony_ci
5737db96d56Sopenharmony_ci    while (gc != young) {
5747db96d56Sopenharmony_ci        if (gc_get_refs(gc)) {
5757db96d56Sopenharmony_ci            /* gc is definitely reachable from outside the
5767db96d56Sopenharmony_ci             * original 'young'.  Mark it as such, and traverse
5777db96d56Sopenharmony_ci             * its pointers to find any other objects that may
5787db96d56Sopenharmony_ci             * be directly reachable from it.  Note that the
5797db96d56Sopenharmony_ci             * call to tp_traverse may append objects to young,
5807db96d56Sopenharmony_ci             * so we have to wait until it returns to determine
5817db96d56Sopenharmony_ci             * the next object to visit.
5827db96d56Sopenharmony_ci             */
5837db96d56Sopenharmony_ci            PyObject *op = FROM_GC(gc);
5847db96d56Sopenharmony_ci            traverseproc traverse = Py_TYPE(op)->tp_traverse;
5857db96d56Sopenharmony_ci            _PyObject_ASSERT_WITH_MSG(op, gc_get_refs(gc) > 0,
5867db96d56Sopenharmony_ci                                      "refcount is too small");
5877db96d56Sopenharmony_ci            // NOTE: visit_reachable may change gc->_gc_next when
5887db96d56Sopenharmony_ci            // young->_gc_prev == gc.  Don't do gc = GC_NEXT(gc) before!
5897db96d56Sopenharmony_ci            (void) traverse(op,
5907db96d56Sopenharmony_ci                    (visitproc)visit_reachable,
5917db96d56Sopenharmony_ci                    (void *)young);
5927db96d56Sopenharmony_ci            // relink gc_prev to prev element.
5937db96d56Sopenharmony_ci            _PyGCHead_SET_PREV(gc, prev);
5947db96d56Sopenharmony_ci            // gc is not COLLECTING state after here.
5957db96d56Sopenharmony_ci            gc_clear_collecting(gc);
5967db96d56Sopenharmony_ci            prev = gc;
5977db96d56Sopenharmony_ci        }
5987db96d56Sopenharmony_ci        else {
5997db96d56Sopenharmony_ci            /* This *may* be unreachable.  To make progress,
6007db96d56Sopenharmony_ci             * assume it is.  gc isn't directly reachable from
6017db96d56Sopenharmony_ci             * any object we've already traversed, but may be
6027db96d56Sopenharmony_ci             * reachable from an object we haven't gotten to yet.
6037db96d56Sopenharmony_ci             * visit_reachable will eventually move gc back into
6047db96d56Sopenharmony_ci             * young if that's so, and we'll see it again.
6057db96d56Sopenharmony_ci             */
6067db96d56Sopenharmony_ci            // Move gc to unreachable.
6077db96d56Sopenharmony_ci            // No need to gc->next->prev = prev because it is single linked.
6087db96d56Sopenharmony_ci            prev->_gc_next = gc->_gc_next;
6097db96d56Sopenharmony_ci
6107db96d56Sopenharmony_ci            // We can't use gc_list_append() here because we use
6117db96d56Sopenharmony_ci            // NEXT_MASK_UNREACHABLE here.
6127db96d56Sopenharmony_ci            PyGC_Head *last = GC_PREV(unreachable);
6137db96d56Sopenharmony_ci            // NOTE: Since all objects in unreachable set has
6147db96d56Sopenharmony_ci            // NEXT_MASK_UNREACHABLE flag, we set it unconditionally.
6157db96d56Sopenharmony_ci            // But this may pollute the unreachable list head's 'next' pointer
6167db96d56Sopenharmony_ci            // too. That's semantically senseless but expedient here - the
6177db96d56Sopenharmony_ci            // damage is repaired when this function ends.
6187db96d56Sopenharmony_ci            last->_gc_next = (NEXT_MASK_UNREACHABLE | (uintptr_t)gc);
6197db96d56Sopenharmony_ci            _PyGCHead_SET_PREV(gc, last);
6207db96d56Sopenharmony_ci            gc->_gc_next = (NEXT_MASK_UNREACHABLE | (uintptr_t)unreachable);
6217db96d56Sopenharmony_ci            unreachable->_gc_prev = (uintptr_t)gc;
6227db96d56Sopenharmony_ci        }
6237db96d56Sopenharmony_ci        gc = (PyGC_Head*)prev->_gc_next;
6247db96d56Sopenharmony_ci    }
6257db96d56Sopenharmony_ci    // young->_gc_prev must be last element remained in the list.
6267db96d56Sopenharmony_ci    young->_gc_prev = (uintptr_t)prev;
6277db96d56Sopenharmony_ci    // don't let the pollution of the list head's next pointer leak
6287db96d56Sopenharmony_ci    unreachable->_gc_next &= ~NEXT_MASK_UNREACHABLE;
6297db96d56Sopenharmony_ci}
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_cistatic void
6327db96d56Sopenharmony_ciuntrack_tuples(PyGC_Head *head)
6337db96d56Sopenharmony_ci{
6347db96d56Sopenharmony_ci    PyGC_Head *next, *gc = GC_NEXT(head);
6357db96d56Sopenharmony_ci    while (gc != head) {
6367db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
6377db96d56Sopenharmony_ci        next = GC_NEXT(gc);
6387db96d56Sopenharmony_ci        if (PyTuple_CheckExact(op)) {
6397db96d56Sopenharmony_ci            _PyTuple_MaybeUntrack(op);
6407db96d56Sopenharmony_ci        }
6417db96d56Sopenharmony_ci        gc = next;
6427db96d56Sopenharmony_ci    }
6437db96d56Sopenharmony_ci}
6447db96d56Sopenharmony_ci
6457db96d56Sopenharmony_ci/* Try to untrack all currently tracked dictionaries */
6467db96d56Sopenharmony_cistatic void
6477db96d56Sopenharmony_ciuntrack_dicts(PyGC_Head *head)
6487db96d56Sopenharmony_ci{
6497db96d56Sopenharmony_ci    PyGC_Head *next, *gc = GC_NEXT(head);
6507db96d56Sopenharmony_ci    while (gc != head) {
6517db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
6527db96d56Sopenharmony_ci        next = GC_NEXT(gc);
6537db96d56Sopenharmony_ci        if (PyDict_CheckExact(op)) {
6547db96d56Sopenharmony_ci            _PyDict_MaybeUntrack(op);
6557db96d56Sopenharmony_ci        }
6567db96d56Sopenharmony_ci        gc = next;
6577db96d56Sopenharmony_ci    }
6587db96d56Sopenharmony_ci}
6597db96d56Sopenharmony_ci
6607db96d56Sopenharmony_ci/* Return true if object has a pre-PEP 442 finalization method. */
6617db96d56Sopenharmony_cistatic int
6627db96d56Sopenharmony_cihas_legacy_finalizer(PyObject *op)
6637db96d56Sopenharmony_ci{
6647db96d56Sopenharmony_ci    return Py_TYPE(op)->tp_del != NULL;
6657db96d56Sopenharmony_ci}
6667db96d56Sopenharmony_ci
6677db96d56Sopenharmony_ci/* Move the objects in unreachable with tp_del slots into `finalizers`.
6687db96d56Sopenharmony_ci *
6697db96d56Sopenharmony_ci * This function also removes NEXT_MASK_UNREACHABLE flag
6707db96d56Sopenharmony_ci * from _gc_next in unreachable.
6717db96d56Sopenharmony_ci */
6727db96d56Sopenharmony_cistatic void
6737db96d56Sopenharmony_cimove_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
6747db96d56Sopenharmony_ci{
6757db96d56Sopenharmony_ci    PyGC_Head *gc, *next;
6767db96d56Sopenharmony_ci    assert((unreachable->_gc_next & NEXT_MASK_UNREACHABLE) == 0);
6777db96d56Sopenharmony_ci
6787db96d56Sopenharmony_ci    /* March over unreachable.  Move objects with finalizers into
6797db96d56Sopenharmony_ci     * `finalizers`.
6807db96d56Sopenharmony_ci     */
6817db96d56Sopenharmony_ci    for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) {
6827db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
6837db96d56Sopenharmony_ci
6847db96d56Sopenharmony_ci        _PyObject_ASSERT(op, gc->_gc_next & NEXT_MASK_UNREACHABLE);
6857db96d56Sopenharmony_ci        gc->_gc_next &= ~NEXT_MASK_UNREACHABLE;
6867db96d56Sopenharmony_ci        next = (PyGC_Head*)gc->_gc_next;
6877db96d56Sopenharmony_ci
6887db96d56Sopenharmony_ci        if (has_legacy_finalizer(op)) {
6897db96d56Sopenharmony_ci            gc_clear_collecting(gc);
6907db96d56Sopenharmony_ci            gc_list_move(gc, finalizers);
6917db96d56Sopenharmony_ci        }
6927db96d56Sopenharmony_ci    }
6937db96d56Sopenharmony_ci}
6947db96d56Sopenharmony_ci
6957db96d56Sopenharmony_cistatic inline void
6967db96d56Sopenharmony_ciclear_unreachable_mask(PyGC_Head *unreachable)
6977db96d56Sopenharmony_ci{
6987db96d56Sopenharmony_ci    /* Check that the list head does not have the unreachable bit set */
6997db96d56Sopenharmony_ci    assert(((uintptr_t)unreachable & NEXT_MASK_UNREACHABLE) == 0);
7007db96d56Sopenharmony_ci
7017db96d56Sopenharmony_ci    PyGC_Head *gc, *next;
7027db96d56Sopenharmony_ci    assert((unreachable->_gc_next & NEXT_MASK_UNREACHABLE) == 0);
7037db96d56Sopenharmony_ci    for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) {
7047db96d56Sopenharmony_ci        _PyObject_ASSERT((PyObject*)FROM_GC(gc), gc->_gc_next & NEXT_MASK_UNREACHABLE);
7057db96d56Sopenharmony_ci        gc->_gc_next &= ~NEXT_MASK_UNREACHABLE;
7067db96d56Sopenharmony_ci        next = (PyGC_Head*)gc->_gc_next;
7077db96d56Sopenharmony_ci    }
7087db96d56Sopenharmony_ci    validate_list(unreachable, collecting_set_unreachable_clear);
7097db96d56Sopenharmony_ci}
7107db96d56Sopenharmony_ci
7117db96d56Sopenharmony_ci/* A traversal callback for move_legacy_finalizer_reachable. */
7127db96d56Sopenharmony_cistatic int
7137db96d56Sopenharmony_civisit_move(PyObject *op, PyGC_Head *tolist)
7147db96d56Sopenharmony_ci{
7157db96d56Sopenharmony_ci    if (_PyObject_IS_GC(op)) {
7167db96d56Sopenharmony_ci        PyGC_Head *gc = AS_GC(op);
7177db96d56Sopenharmony_ci        if (gc_is_collecting(gc)) {
7187db96d56Sopenharmony_ci            gc_list_move(gc, tolist);
7197db96d56Sopenharmony_ci            gc_clear_collecting(gc);
7207db96d56Sopenharmony_ci        }
7217db96d56Sopenharmony_ci    }
7227db96d56Sopenharmony_ci    return 0;
7237db96d56Sopenharmony_ci}
7247db96d56Sopenharmony_ci
7257db96d56Sopenharmony_ci/* Move objects that are reachable from finalizers, from the unreachable set
7267db96d56Sopenharmony_ci * into finalizers set.
7277db96d56Sopenharmony_ci */
7287db96d56Sopenharmony_cistatic void
7297db96d56Sopenharmony_cimove_legacy_finalizer_reachable(PyGC_Head *finalizers)
7307db96d56Sopenharmony_ci{
7317db96d56Sopenharmony_ci    traverseproc traverse;
7327db96d56Sopenharmony_ci    PyGC_Head *gc = GC_NEXT(finalizers);
7337db96d56Sopenharmony_ci    for (; gc != finalizers; gc = GC_NEXT(gc)) {
7347db96d56Sopenharmony_ci        /* Note that the finalizers list may grow during this. */
7357db96d56Sopenharmony_ci        traverse = Py_TYPE(FROM_GC(gc))->tp_traverse;
7367db96d56Sopenharmony_ci        (void) traverse(FROM_GC(gc),
7377db96d56Sopenharmony_ci                        (visitproc)visit_move,
7387db96d56Sopenharmony_ci                        (void *)finalizers);
7397db96d56Sopenharmony_ci    }
7407db96d56Sopenharmony_ci}
7417db96d56Sopenharmony_ci
7427db96d56Sopenharmony_ci/* Clear all weakrefs to unreachable objects, and if such a weakref has a
7437db96d56Sopenharmony_ci * callback, invoke it if necessary.  Note that it's possible for such
7447db96d56Sopenharmony_ci * weakrefs to be outside the unreachable set -- indeed, those are precisely
7457db96d56Sopenharmony_ci * the weakrefs whose callbacks must be invoked.  See gc_weakref.txt for
7467db96d56Sopenharmony_ci * overview & some details.  Some weakrefs with callbacks may be reclaimed
7477db96d56Sopenharmony_ci * directly by this routine; the number reclaimed is the return value.  Other
7487db96d56Sopenharmony_ci * weakrefs with callbacks may be moved into the `old` generation.  Objects
7497db96d56Sopenharmony_ci * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in
7507db96d56Sopenharmony_ci * unreachable are left at GC_TENTATIVELY_UNREACHABLE.  When this returns,
7517db96d56Sopenharmony_ci * no object in `unreachable` is weakly referenced anymore.
7527db96d56Sopenharmony_ci */
7537db96d56Sopenharmony_cistatic int
7547db96d56Sopenharmony_cihandle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
7557db96d56Sopenharmony_ci{
7567db96d56Sopenharmony_ci    PyGC_Head *gc;
7577db96d56Sopenharmony_ci    PyObject *op;               /* generally FROM_GC(gc) */
7587db96d56Sopenharmony_ci    PyWeakReference *wr;        /* generally a cast of op */
7597db96d56Sopenharmony_ci    PyGC_Head wrcb_to_call;     /* weakrefs with callbacks to call */
7607db96d56Sopenharmony_ci    PyGC_Head *next;
7617db96d56Sopenharmony_ci    int num_freed = 0;
7627db96d56Sopenharmony_ci
7637db96d56Sopenharmony_ci    gc_list_init(&wrcb_to_call);
7647db96d56Sopenharmony_ci
7657db96d56Sopenharmony_ci    /* Clear all weakrefs to the objects in unreachable.  If such a weakref
7667db96d56Sopenharmony_ci     * also has a callback, move it into `wrcb_to_call` if the callback
7677db96d56Sopenharmony_ci     * needs to be invoked.  Note that we cannot invoke any callbacks until
7687db96d56Sopenharmony_ci     * all weakrefs to unreachable objects are cleared, lest the callback
7697db96d56Sopenharmony_ci     * resurrect an unreachable object via a still-active weakref.  We
7707db96d56Sopenharmony_ci     * make another pass over wrcb_to_call, invoking callbacks, after this
7717db96d56Sopenharmony_ci     * pass completes.
7727db96d56Sopenharmony_ci     */
7737db96d56Sopenharmony_ci    for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) {
7747db96d56Sopenharmony_ci        PyWeakReference **wrlist;
7757db96d56Sopenharmony_ci
7767db96d56Sopenharmony_ci        op = FROM_GC(gc);
7777db96d56Sopenharmony_ci        next = GC_NEXT(gc);
7787db96d56Sopenharmony_ci
7797db96d56Sopenharmony_ci        if (PyWeakref_Check(op)) {
7807db96d56Sopenharmony_ci            /* A weakref inside the unreachable set must be cleared.  If we
7817db96d56Sopenharmony_ci             * allow its callback to execute inside delete_garbage(), it
7827db96d56Sopenharmony_ci             * could expose objects that have tp_clear already called on
7837db96d56Sopenharmony_ci             * them.  Or, it could resurrect unreachable objects.  One way
7847db96d56Sopenharmony_ci             * this can happen is if some container objects do not implement
7857db96d56Sopenharmony_ci             * tp_traverse.  Then, wr_object can be outside the unreachable
7867db96d56Sopenharmony_ci             * set but can be deallocated as a result of breaking the
7877db96d56Sopenharmony_ci             * reference cycle.  If we don't clear the weakref, the callback
7887db96d56Sopenharmony_ci             * will run and potentially cause a crash.  See bpo-38006 for
7897db96d56Sopenharmony_ci             * one example.
7907db96d56Sopenharmony_ci             */
7917db96d56Sopenharmony_ci            _PyWeakref_ClearRef((PyWeakReference *)op);
7927db96d56Sopenharmony_ci        }
7937db96d56Sopenharmony_ci
7947db96d56Sopenharmony_ci        if (! _PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
7957db96d56Sopenharmony_ci            continue;
7967db96d56Sopenharmony_ci
7977db96d56Sopenharmony_ci        /* It supports weakrefs.  Does it have any? */
7987db96d56Sopenharmony_ci        wrlist = (PyWeakReference **)
7997db96d56Sopenharmony_ci                                _PyObject_GET_WEAKREFS_LISTPTR(op);
8007db96d56Sopenharmony_ci
8017db96d56Sopenharmony_ci        /* `op` may have some weakrefs.  March over the list, clear
8027db96d56Sopenharmony_ci         * all the weakrefs, and move the weakrefs with callbacks
8037db96d56Sopenharmony_ci         * that must be called into wrcb_to_call.
8047db96d56Sopenharmony_ci         */
8057db96d56Sopenharmony_ci        for (wr = *wrlist; wr != NULL; wr = *wrlist) {
8067db96d56Sopenharmony_ci            PyGC_Head *wrasgc;                  /* AS_GC(wr) */
8077db96d56Sopenharmony_ci
8087db96d56Sopenharmony_ci            /* _PyWeakref_ClearRef clears the weakref but leaves
8097db96d56Sopenharmony_ci             * the callback pointer intact.  Obscure:  it also
8107db96d56Sopenharmony_ci             * changes *wrlist.
8117db96d56Sopenharmony_ci             */
8127db96d56Sopenharmony_ci            _PyObject_ASSERT((PyObject *)wr, wr->wr_object == op);
8137db96d56Sopenharmony_ci            _PyWeakref_ClearRef(wr);
8147db96d56Sopenharmony_ci            _PyObject_ASSERT((PyObject *)wr, wr->wr_object == Py_None);
8157db96d56Sopenharmony_ci            if (wr->wr_callback == NULL) {
8167db96d56Sopenharmony_ci                /* no callback */
8177db96d56Sopenharmony_ci                continue;
8187db96d56Sopenharmony_ci            }
8197db96d56Sopenharmony_ci
8207db96d56Sopenharmony_ci            /* Headache time.  `op` is going away, and is weakly referenced by
8217db96d56Sopenharmony_ci             * `wr`, which has a callback.  Should the callback be invoked?  If wr
8227db96d56Sopenharmony_ci             * is also trash, no:
8237db96d56Sopenharmony_ci             *
8247db96d56Sopenharmony_ci             * 1. There's no need to call it.  The object and the weakref are
8257db96d56Sopenharmony_ci             *    both going away, so it's legitimate to pretend the weakref is
8267db96d56Sopenharmony_ci             *    going away first.  The user has to ensure a weakref outlives its
8277db96d56Sopenharmony_ci             *    referent if they want a guarantee that the wr callback will get
8287db96d56Sopenharmony_ci             *    invoked.
8297db96d56Sopenharmony_ci             *
8307db96d56Sopenharmony_ci             * 2. It may be catastrophic to call it.  If the callback is also in
8317db96d56Sopenharmony_ci             *    cyclic trash (CT), then although the CT is unreachable from
8327db96d56Sopenharmony_ci             *    outside the current generation, CT may be reachable from the
8337db96d56Sopenharmony_ci             *    callback.  Then the callback could resurrect insane objects.
8347db96d56Sopenharmony_ci             *
8357db96d56Sopenharmony_ci             * Since the callback is never needed and may be unsafe in this case,
8367db96d56Sopenharmony_ci             * wr is simply left in the unreachable set.  Note that because we
8377db96d56Sopenharmony_ci             * already called _PyWeakref_ClearRef(wr), its callback will never
8387db96d56Sopenharmony_ci             * trigger.
8397db96d56Sopenharmony_ci             *
8407db96d56Sopenharmony_ci             * OTOH, if wr isn't part of CT, we should invoke the callback:  the
8417db96d56Sopenharmony_ci             * weakref outlived the trash.  Note that since wr isn't CT in this
8427db96d56Sopenharmony_ci             * case, its callback can't be CT either -- wr acted as an external
8437db96d56Sopenharmony_ci             * root to this generation, and therefore its callback did too.  So
8447db96d56Sopenharmony_ci             * nothing in CT is reachable from the callback either, so it's hard
8457db96d56Sopenharmony_ci             * to imagine how calling it later could create a problem for us.  wr
8467db96d56Sopenharmony_ci             * is moved to wrcb_to_call in this case.
8477db96d56Sopenharmony_ci             */
8487db96d56Sopenharmony_ci            if (gc_is_collecting(AS_GC(wr))) {
8497db96d56Sopenharmony_ci                /* it should already have been cleared above */
8507db96d56Sopenharmony_ci                assert(wr->wr_object == Py_None);
8517db96d56Sopenharmony_ci                continue;
8527db96d56Sopenharmony_ci            }
8537db96d56Sopenharmony_ci
8547db96d56Sopenharmony_ci            /* Create a new reference so that wr can't go away
8557db96d56Sopenharmony_ci             * before we can process it again.
8567db96d56Sopenharmony_ci             */
8577db96d56Sopenharmony_ci            Py_INCREF(wr);
8587db96d56Sopenharmony_ci
8597db96d56Sopenharmony_ci            /* Move wr to wrcb_to_call, for the next pass. */
8607db96d56Sopenharmony_ci            wrasgc = AS_GC(wr);
8617db96d56Sopenharmony_ci            assert(wrasgc != next); /* wrasgc is reachable, but
8627db96d56Sopenharmony_ci                                       next isn't, so they can't
8637db96d56Sopenharmony_ci                                       be the same */
8647db96d56Sopenharmony_ci            gc_list_move(wrasgc, &wrcb_to_call);
8657db96d56Sopenharmony_ci        }
8667db96d56Sopenharmony_ci    }
8677db96d56Sopenharmony_ci
8687db96d56Sopenharmony_ci    /* Invoke the callbacks we decided to honor.  It's safe to invoke them
8697db96d56Sopenharmony_ci     * because they can't reference unreachable objects.
8707db96d56Sopenharmony_ci     */
8717db96d56Sopenharmony_ci    while (! gc_list_is_empty(&wrcb_to_call)) {
8727db96d56Sopenharmony_ci        PyObject *temp;
8737db96d56Sopenharmony_ci        PyObject *callback;
8747db96d56Sopenharmony_ci
8757db96d56Sopenharmony_ci        gc = (PyGC_Head*)wrcb_to_call._gc_next;
8767db96d56Sopenharmony_ci        op = FROM_GC(gc);
8777db96d56Sopenharmony_ci        _PyObject_ASSERT(op, PyWeakref_Check(op));
8787db96d56Sopenharmony_ci        wr = (PyWeakReference *)op;
8797db96d56Sopenharmony_ci        callback = wr->wr_callback;
8807db96d56Sopenharmony_ci        _PyObject_ASSERT(op, callback != NULL);
8817db96d56Sopenharmony_ci
8827db96d56Sopenharmony_ci        /* copy-paste of weakrefobject.c's handle_callback() */
8837db96d56Sopenharmony_ci        temp = PyObject_CallOneArg(callback, (PyObject *)wr);
8847db96d56Sopenharmony_ci        if (temp == NULL)
8857db96d56Sopenharmony_ci            PyErr_WriteUnraisable(callback);
8867db96d56Sopenharmony_ci        else
8877db96d56Sopenharmony_ci            Py_DECREF(temp);
8887db96d56Sopenharmony_ci
8897db96d56Sopenharmony_ci        /* Give up the reference we created in the first pass.  When
8907db96d56Sopenharmony_ci         * op's refcount hits 0 (which it may or may not do right now),
8917db96d56Sopenharmony_ci         * op's tp_dealloc will decref op->wr_callback too.  Note
8927db96d56Sopenharmony_ci         * that the refcount probably will hit 0 now, and because this
8937db96d56Sopenharmony_ci         * weakref was reachable to begin with, gc didn't already
8947db96d56Sopenharmony_ci         * add it to its count of freed objects.  Example:  a reachable
8957db96d56Sopenharmony_ci         * weak value dict maps some key to this reachable weakref.
8967db96d56Sopenharmony_ci         * The callback removes this key->weakref mapping from the
8977db96d56Sopenharmony_ci         * dict, leaving no other references to the weakref (excepting
8987db96d56Sopenharmony_ci         * ours).
8997db96d56Sopenharmony_ci         */
9007db96d56Sopenharmony_ci        Py_DECREF(op);
9017db96d56Sopenharmony_ci        if (wrcb_to_call._gc_next == (uintptr_t)gc) {
9027db96d56Sopenharmony_ci            /* object is still alive -- move it */
9037db96d56Sopenharmony_ci            gc_list_move(gc, old);
9047db96d56Sopenharmony_ci        }
9057db96d56Sopenharmony_ci        else {
9067db96d56Sopenharmony_ci            ++num_freed;
9077db96d56Sopenharmony_ci        }
9087db96d56Sopenharmony_ci    }
9097db96d56Sopenharmony_ci
9107db96d56Sopenharmony_ci    return num_freed;
9117db96d56Sopenharmony_ci}
9127db96d56Sopenharmony_ci
9137db96d56Sopenharmony_cistatic void
9147db96d56Sopenharmony_cidebug_cycle(const char *msg, PyObject *op)
9157db96d56Sopenharmony_ci{
9167db96d56Sopenharmony_ci    PySys_FormatStderr("gc: %s <%s %p>\n",
9177db96d56Sopenharmony_ci                       msg, Py_TYPE(op)->tp_name, op);
9187db96d56Sopenharmony_ci}
9197db96d56Sopenharmony_ci
9207db96d56Sopenharmony_ci/* Handle uncollectable garbage (cycles with tp_del slots, and stuff reachable
9217db96d56Sopenharmony_ci * only from such cycles).
9227db96d56Sopenharmony_ci * If DEBUG_SAVEALL, all objects in finalizers are appended to the module
9237db96d56Sopenharmony_ci * garbage list (a Python list), else only the objects in finalizers with
9247db96d56Sopenharmony_ci * __del__ methods are appended to garbage.  All objects in finalizers are
9257db96d56Sopenharmony_ci * merged into the old list regardless.
9267db96d56Sopenharmony_ci */
9277db96d56Sopenharmony_cistatic void
9287db96d56Sopenharmony_cihandle_legacy_finalizers(PyThreadState *tstate,
9297db96d56Sopenharmony_ci                         GCState *gcstate,
9307db96d56Sopenharmony_ci                         PyGC_Head *finalizers, PyGC_Head *old)
9317db96d56Sopenharmony_ci{
9327db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
9337db96d56Sopenharmony_ci    assert(gcstate->garbage != NULL);
9347db96d56Sopenharmony_ci
9357db96d56Sopenharmony_ci    PyGC_Head *gc = GC_NEXT(finalizers);
9367db96d56Sopenharmony_ci    for (; gc != finalizers; gc = GC_NEXT(gc)) {
9377db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
9387db96d56Sopenharmony_ci
9397db96d56Sopenharmony_ci        if ((gcstate->debug & DEBUG_SAVEALL) || has_legacy_finalizer(op)) {
9407db96d56Sopenharmony_ci            if (PyList_Append(gcstate->garbage, op) < 0) {
9417db96d56Sopenharmony_ci                _PyErr_Clear(tstate);
9427db96d56Sopenharmony_ci                break;
9437db96d56Sopenharmony_ci            }
9447db96d56Sopenharmony_ci        }
9457db96d56Sopenharmony_ci    }
9467db96d56Sopenharmony_ci
9477db96d56Sopenharmony_ci    gc_list_merge(finalizers, old);
9487db96d56Sopenharmony_ci}
9497db96d56Sopenharmony_ci
9507db96d56Sopenharmony_ci/* Run first-time finalizers (if any) on all the objects in collectable.
9517db96d56Sopenharmony_ci * Note that this may remove some (or even all) of the objects from the
9527db96d56Sopenharmony_ci * list, due to refcounts falling to 0.
9537db96d56Sopenharmony_ci */
9547db96d56Sopenharmony_cistatic void
9557db96d56Sopenharmony_cifinalize_garbage(PyThreadState *tstate, PyGC_Head *collectable)
9567db96d56Sopenharmony_ci{
9577db96d56Sopenharmony_ci    destructor finalize;
9587db96d56Sopenharmony_ci    PyGC_Head seen;
9597db96d56Sopenharmony_ci
9607db96d56Sopenharmony_ci    /* While we're going through the loop, `finalize(op)` may cause op, or
9617db96d56Sopenharmony_ci     * other objects, to be reclaimed via refcounts falling to zero.  So
9627db96d56Sopenharmony_ci     * there's little we can rely on about the structure of the input
9637db96d56Sopenharmony_ci     * `collectable` list across iterations.  For safety, we always take the
9647db96d56Sopenharmony_ci     * first object in that list and move it to a temporary `seen` list.
9657db96d56Sopenharmony_ci     * If objects vanish from the `collectable` and `seen` lists we don't
9667db96d56Sopenharmony_ci     * care.
9677db96d56Sopenharmony_ci     */
9687db96d56Sopenharmony_ci    gc_list_init(&seen);
9697db96d56Sopenharmony_ci
9707db96d56Sopenharmony_ci    while (!gc_list_is_empty(collectable)) {
9717db96d56Sopenharmony_ci        PyGC_Head *gc = GC_NEXT(collectable);
9727db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
9737db96d56Sopenharmony_ci        gc_list_move(gc, &seen);
9747db96d56Sopenharmony_ci        if (!_PyGCHead_FINALIZED(gc) &&
9757db96d56Sopenharmony_ci                (finalize = Py_TYPE(op)->tp_finalize) != NULL) {
9767db96d56Sopenharmony_ci            _PyGCHead_SET_FINALIZED(gc);
9777db96d56Sopenharmony_ci            Py_INCREF(op);
9787db96d56Sopenharmony_ci            finalize(op);
9797db96d56Sopenharmony_ci            assert(!_PyErr_Occurred(tstate));
9807db96d56Sopenharmony_ci            Py_DECREF(op);
9817db96d56Sopenharmony_ci        }
9827db96d56Sopenharmony_ci    }
9837db96d56Sopenharmony_ci    gc_list_merge(&seen, collectable);
9847db96d56Sopenharmony_ci}
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci/* Break reference cycles by clearing the containers involved.  This is
9877db96d56Sopenharmony_ci * tricky business as the lists can be changing and we don't know which
9887db96d56Sopenharmony_ci * objects may be freed.  It is possible I screwed something up here.
9897db96d56Sopenharmony_ci */
9907db96d56Sopenharmony_cistatic void
9917db96d56Sopenharmony_cidelete_garbage(PyThreadState *tstate, GCState *gcstate,
9927db96d56Sopenharmony_ci               PyGC_Head *collectable, PyGC_Head *old)
9937db96d56Sopenharmony_ci{
9947db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
9957db96d56Sopenharmony_ci
9967db96d56Sopenharmony_ci    while (!gc_list_is_empty(collectable)) {
9977db96d56Sopenharmony_ci        PyGC_Head *gc = GC_NEXT(collectable);
9987db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
9997db96d56Sopenharmony_ci
10007db96d56Sopenharmony_ci        _PyObject_ASSERT_WITH_MSG(op, Py_REFCNT(op) > 0,
10017db96d56Sopenharmony_ci                                  "refcount is too small");
10027db96d56Sopenharmony_ci
10037db96d56Sopenharmony_ci        if (gcstate->debug & DEBUG_SAVEALL) {
10047db96d56Sopenharmony_ci            assert(gcstate->garbage != NULL);
10057db96d56Sopenharmony_ci            if (PyList_Append(gcstate->garbage, op) < 0) {
10067db96d56Sopenharmony_ci                _PyErr_Clear(tstate);
10077db96d56Sopenharmony_ci            }
10087db96d56Sopenharmony_ci        }
10097db96d56Sopenharmony_ci        else {
10107db96d56Sopenharmony_ci            inquiry clear;
10117db96d56Sopenharmony_ci            if ((clear = Py_TYPE(op)->tp_clear) != NULL) {
10127db96d56Sopenharmony_ci                Py_INCREF(op);
10137db96d56Sopenharmony_ci                (void) clear(op);
10147db96d56Sopenharmony_ci                if (_PyErr_Occurred(tstate)) {
10157db96d56Sopenharmony_ci                    _PyErr_WriteUnraisableMsg("in tp_clear of",
10167db96d56Sopenharmony_ci                                              (PyObject*)Py_TYPE(op));
10177db96d56Sopenharmony_ci                }
10187db96d56Sopenharmony_ci                Py_DECREF(op);
10197db96d56Sopenharmony_ci            }
10207db96d56Sopenharmony_ci        }
10217db96d56Sopenharmony_ci        if (GC_NEXT(collectable) == gc) {
10227db96d56Sopenharmony_ci            /* object is still alive, move it, it may die later */
10237db96d56Sopenharmony_ci            gc_clear_collecting(gc);
10247db96d56Sopenharmony_ci            gc_list_move(gc, old);
10257db96d56Sopenharmony_ci        }
10267db96d56Sopenharmony_ci    }
10277db96d56Sopenharmony_ci}
10287db96d56Sopenharmony_ci
10297db96d56Sopenharmony_ci/* Clear all free lists
10307db96d56Sopenharmony_ci * All free lists are cleared during the collection of the highest generation.
10317db96d56Sopenharmony_ci * Allocated items in the free list may keep a pymalloc arena occupied.
10327db96d56Sopenharmony_ci * Clearing the free lists may give back memory to the OS earlier.
10337db96d56Sopenharmony_ci */
10347db96d56Sopenharmony_cistatic void
10357db96d56Sopenharmony_ciclear_freelists(PyInterpreterState *interp)
10367db96d56Sopenharmony_ci{
10377db96d56Sopenharmony_ci    _PyTuple_ClearFreeList(interp);
10387db96d56Sopenharmony_ci    _PyFloat_ClearFreeList(interp);
10397db96d56Sopenharmony_ci    _PyList_ClearFreeList(interp);
10407db96d56Sopenharmony_ci    _PyDict_ClearFreeList(interp);
10417db96d56Sopenharmony_ci    _PyAsyncGen_ClearFreeLists(interp);
10427db96d56Sopenharmony_ci    _PyContext_ClearFreeList(interp);
10437db96d56Sopenharmony_ci}
10447db96d56Sopenharmony_ci
10457db96d56Sopenharmony_ci// Show stats for objects in each generations
10467db96d56Sopenharmony_cistatic void
10477db96d56Sopenharmony_cishow_stats_each_generations(GCState *gcstate)
10487db96d56Sopenharmony_ci{
10497db96d56Sopenharmony_ci    char buf[100];
10507db96d56Sopenharmony_ci    size_t pos = 0;
10517db96d56Sopenharmony_ci
10527db96d56Sopenharmony_ci    for (int i = 0; i < NUM_GENERATIONS && pos < sizeof(buf); i++) {
10537db96d56Sopenharmony_ci        pos += PyOS_snprintf(buf+pos, sizeof(buf)-pos,
10547db96d56Sopenharmony_ci                             " %zd",
10557db96d56Sopenharmony_ci                             gc_list_size(GEN_HEAD(gcstate, i)));
10567db96d56Sopenharmony_ci    }
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci    PySys_FormatStderr(
10597db96d56Sopenharmony_ci        "gc: objects in each generation:%s\n"
10607db96d56Sopenharmony_ci        "gc: objects in permanent generation: %zd\n",
10617db96d56Sopenharmony_ci        buf, gc_list_size(&gcstate->permanent_generation.head));
10627db96d56Sopenharmony_ci}
10637db96d56Sopenharmony_ci
10647db96d56Sopenharmony_ci/* Deduce which objects among "base" are unreachable from outside the list
10657db96d56Sopenharmony_ci   and move them to 'unreachable'. The process consist in the following steps:
10667db96d56Sopenharmony_ci
10677db96d56Sopenharmony_ci1. Copy all reference counts to a different field (gc_prev is used to hold
10687db96d56Sopenharmony_ci   this copy to save memory).
10697db96d56Sopenharmony_ci2. Traverse all objects in "base" and visit all referred objects using
10707db96d56Sopenharmony_ci   "tp_traverse" and for every visited object, subtract 1 to the reference
10717db96d56Sopenharmony_ci   count (the one that we copied in the previous step). After this step, all
10727db96d56Sopenharmony_ci   objects that can be reached directly from outside must have strictly positive
10737db96d56Sopenharmony_ci   reference count, while all unreachable objects must have a count of exactly 0.
10747db96d56Sopenharmony_ci3. Identify all unreachable objects (the ones with 0 reference count) and move
10757db96d56Sopenharmony_ci   them to the "unreachable" list. This step also needs to move back to "base" all
10767db96d56Sopenharmony_ci   objects that were initially marked as unreachable but are referred transitively
10777db96d56Sopenharmony_ci   by the reachable objects (the ones with strictly positive reference count).
10787db96d56Sopenharmony_ci
10797db96d56Sopenharmony_ciContracts:
10807db96d56Sopenharmony_ci
10817db96d56Sopenharmony_ci    * The "base" has to be a valid list with no mask set.
10827db96d56Sopenharmony_ci
10837db96d56Sopenharmony_ci    * The "unreachable" list must be uninitialized (this function calls
10847db96d56Sopenharmony_ci      gc_list_init over 'unreachable').
10857db96d56Sopenharmony_ci
10867db96d56Sopenharmony_ciIMPORTANT: This function leaves 'unreachable' with the NEXT_MASK_UNREACHABLE
10877db96d56Sopenharmony_ciflag set but it does not clear it to skip unnecessary iteration. Before the
10887db96d56Sopenharmony_ciflag is cleared (for example, by using 'clear_unreachable_mask' function or
10897db96d56Sopenharmony_ciby a call to 'move_legacy_finalizers'), the 'unreachable' list is not a normal
10907db96d56Sopenharmony_cilist and we can not use most gc_list_* functions for it. */
10917db96d56Sopenharmony_cistatic inline void
10927db96d56Sopenharmony_cideduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) {
10937db96d56Sopenharmony_ci    validate_list(base, collecting_clear_unreachable_clear);
10947db96d56Sopenharmony_ci    /* Using ob_refcnt and gc_refs, calculate which objects in the
10957db96d56Sopenharmony_ci     * container set are reachable from outside the set (i.e., have a
10967db96d56Sopenharmony_ci     * refcount greater than 0 when all the references within the
10977db96d56Sopenharmony_ci     * set are taken into account).
10987db96d56Sopenharmony_ci     */
10997db96d56Sopenharmony_ci    update_refs(base);  // gc_prev is used for gc_refs
11007db96d56Sopenharmony_ci    subtract_refs(base);
11017db96d56Sopenharmony_ci
11027db96d56Sopenharmony_ci    /* Leave everything reachable from outside base in base, and move
11037db96d56Sopenharmony_ci     * everything else (in base) to unreachable.
11047db96d56Sopenharmony_ci     *
11057db96d56Sopenharmony_ci     * NOTE:  This used to move the reachable objects into a reachable
11067db96d56Sopenharmony_ci     * set instead.  But most things usually turn out to be reachable,
11077db96d56Sopenharmony_ci     * so it's more efficient to move the unreachable things.  It "sounds slick"
11087db96d56Sopenharmony_ci     * to move the unreachable objects, until you think about it - the reason it
11097db96d56Sopenharmony_ci     * pays isn't actually obvious.
11107db96d56Sopenharmony_ci     *
11117db96d56Sopenharmony_ci     * Suppose we create objects A, B, C in that order.  They appear in the young
11127db96d56Sopenharmony_ci     * generation in the same order.  If B points to A, and C to B, and C is
11137db96d56Sopenharmony_ci     * reachable from outside, then the adjusted refcounts will be 0, 0, and 1
11147db96d56Sopenharmony_ci     * respectively.
11157db96d56Sopenharmony_ci     *
11167db96d56Sopenharmony_ci     * When move_unreachable finds A, A is moved to the unreachable list.  The
11177db96d56Sopenharmony_ci     * same for B when it's first encountered.  Then C is traversed, B is moved
11187db96d56Sopenharmony_ci     * _back_ to the reachable list.  B is eventually traversed, and then A is
11197db96d56Sopenharmony_ci     * moved back to the reachable list.
11207db96d56Sopenharmony_ci     *
11217db96d56Sopenharmony_ci     * So instead of not moving at all, the reachable objects B and A are moved
11227db96d56Sopenharmony_ci     * twice each.  Why is this a win?  A straightforward algorithm to move the
11237db96d56Sopenharmony_ci     * reachable objects instead would move A, B, and C once each.
11247db96d56Sopenharmony_ci     *
11257db96d56Sopenharmony_ci     * The key is that this dance leaves the objects in order C, B, A - it's
11267db96d56Sopenharmony_ci     * reversed from the original order.  On all _subsequent_ scans, none of
11277db96d56Sopenharmony_ci     * them will move.  Since most objects aren't in cycles, this can save an
11287db96d56Sopenharmony_ci     * unbounded number of moves across an unbounded number of later collections.
11297db96d56Sopenharmony_ci     * It can cost more only the first time the chain is scanned.
11307db96d56Sopenharmony_ci     *
11317db96d56Sopenharmony_ci     * Drawback:  move_unreachable is also used to find out what's still trash
11327db96d56Sopenharmony_ci     * after finalizers may resurrect objects.  In _that_ case most unreachable
11337db96d56Sopenharmony_ci     * objects will remain unreachable, so it would be more efficient to move
11347db96d56Sopenharmony_ci     * the reachable objects instead.  But this is a one-time cost, probably not
11357db96d56Sopenharmony_ci     * worth complicating the code to speed just a little.
11367db96d56Sopenharmony_ci     */
11377db96d56Sopenharmony_ci    gc_list_init(unreachable);
11387db96d56Sopenharmony_ci    move_unreachable(base, unreachable);  // gc_prev is pointer again
11397db96d56Sopenharmony_ci    validate_list(base, collecting_clear_unreachable_clear);
11407db96d56Sopenharmony_ci    validate_list(unreachable, collecting_set_unreachable_set);
11417db96d56Sopenharmony_ci}
11427db96d56Sopenharmony_ci
11437db96d56Sopenharmony_ci/* Handle objects that may have resurrected after a call to 'finalize_garbage', moving
11447db96d56Sopenharmony_ci   them to 'old_generation' and placing the rest on 'still_unreachable'.
11457db96d56Sopenharmony_ci
11467db96d56Sopenharmony_ci   Contracts:
11477db96d56Sopenharmony_ci       * After this function 'unreachable' must not be used anymore and 'still_unreachable'
11487db96d56Sopenharmony_ci         will contain the objects that did not resurrect.
11497db96d56Sopenharmony_ci
11507db96d56Sopenharmony_ci       * The "still_unreachable" list must be uninitialized (this function calls
11517db96d56Sopenharmony_ci         gc_list_init over 'still_unreachable').
11527db96d56Sopenharmony_ci
11537db96d56Sopenharmony_ciIMPORTANT: After a call to this function, the 'still_unreachable' set will have the
11547db96d56Sopenharmony_ciPREV_MARK_COLLECTING set, but the objects in this set are going to be removed so
11557db96d56Sopenharmony_ciwe can skip the expense of clearing the flag to avoid extra iteration. */
11567db96d56Sopenharmony_cistatic inline void
11577db96d56Sopenharmony_cihandle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable,
11587db96d56Sopenharmony_ci                           PyGC_Head *old_generation)
11597db96d56Sopenharmony_ci{
11607db96d56Sopenharmony_ci    // Remove the PREV_MASK_COLLECTING from unreachable
11617db96d56Sopenharmony_ci    // to prepare it for a new call to 'deduce_unreachable'
11627db96d56Sopenharmony_ci    gc_list_clear_collecting(unreachable);
11637db96d56Sopenharmony_ci
11647db96d56Sopenharmony_ci    // After the call to deduce_unreachable, the 'still_unreachable' set will
11657db96d56Sopenharmony_ci    // have the PREV_MARK_COLLECTING set, but the objects are going to be
11667db96d56Sopenharmony_ci    // removed so we can skip the expense of clearing the flag.
11677db96d56Sopenharmony_ci    PyGC_Head* resurrected = unreachable;
11687db96d56Sopenharmony_ci    deduce_unreachable(resurrected, still_unreachable);
11697db96d56Sopenharmony_ci    clear_unreachable_mask(still_unreachable);
11707db96d56Sopenharmony_ci
11717db96d56Sopenharmony_ci    // Move the resurrected objects to the old generation for future collection.
11727db96d56Sopenharmony_ci    gc_list_merge(resurrected, old_generation);
11737db96d56Sopenharmony_ci}
11747db96d56Sopenharmony_ci
11757db96d56Sopenharmony_ci/* This is the main function.  Read this to understand how the
11767db96d56Sopenharmony_ci * collection process works. */
11777db96d56Sopenharmony_cistatic Py_ssize_t
11787db96d56Sopenharmony_cigc_collect_main(PyThreadState *tstate, int generation,
11797db96d56Sopenharmony_ci                Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
11807db96d56Sopenharmony_ci                int nofail)
11817db96d56Sopenharmony_ci{
11827db96d56Sopenharmony_ci    int i;
11837db96d56Sopenharmony_ci    Py_ssize_t m = 0; /* # objects collected */
11847db96d56Sopenharmony_ci    Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */
11857db96d56Sopenharmony_ci    PyGC_Head *young; /* the generation we are examining */
11867db96d56Sopenharmony_ci    PyGC_Head *old; /* next older generation */
11877db96d56Sopenharmony_ci    PyGC_Head unreachable; /* non-problematic unreachable trash */
11887db96d56Sopenharmony_ci    PyGC_Head finalizers;  /* objects with, & reachable from, __del__ */
11897db96d56Sopenharmony_ci    PyGC_Head *gc;
11907db96d56Sopenharmony_ci    _PyTime_t t1 = 0;   /* initialize to prevent a compiler warning */
11917db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
11927db96d56Sopenharmony_ci
11937db96d56Sopenharmony_ci    // gc_collect_main() must not be called before _PyGC_Init
11947db96d56Sopenharmony_ci    // or after _PyGC_Fini()
11957db96d56Sopenharmony_ci    assert(gcstate->garbage != NULL);
11967db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
11977db96d56Sopenharmony_ci
11987db96d56Sopenharmony_ci    if (gcstate->debug & DEBUG_STATS) {
11997db96d56Sopenharmony_ci        PySys_WriteStderr("gc: collecting generation %d...\n", generation);
12007db96d56Sopenharmony_ci        show_stats_each_generations(gcstate);
12017db96d56Sopenharmony_ci        t1 = _PyTime_GetPerfCounter();
12027db96d56Sopenharmony_ci    }
12037db96d56Sopenharmony_ci
12047db96d56Sopenharmony_ci    if (PyDTrace_GC_START_ENABLED())
12057db96d56Sopenharmony_ci        PyDTrace_GC_START(generation);
12067db96d56Sopenharmony_ci
12077db96d56Sopenharmony_ci    /* update collection and allocation counters */
12087db96d56Sopenharmony_ci    if (generation+1 < NUM_GENERATIONS)
12097db96d56Sopenharmony_ci        gcstate->generations[generation+1].count += 1;
12107db96d56Sopenharmony_ci    for (i = 0; i <= generation; i++)
12117db96d56Sopenharmony_ci        gcstate->generations[i].count = 0;
12127db96d56Sopenharmony_ci
12137db96d56Sopenharmony_ci    /* merge younger generations with one we are currently collecting */
12147db96d56Sopenharmony_ci    for (i = 0; i < generation; i++) {
12157db96d56Sopenharmony_ci        gc_list_merge(GEN_HEAD(gcstate, i), GEN_HEAD(gcstate, generation));
12167db96d56Sopenharmony_ci    }
12177db96d56Sopenharmony_ci
12187db96d56Sopenharmony_ci    /* handy references */
12197db96d56Sopenharmony_ci    young = GEN_HEAD(gcstate, generation);
12207db96d56Sopenharmony_ci    if (generation < NUM_GENERATIONS-1)
12217db96d56Sopenharmony_ci        old = GEN_HEAD(gcstate, generation+1);
12227db96d56Sopenharmony_ci    else
12237db96d56Sopenharmony_ci        old = young;
12247db96d56Sopenharmony_ci    validate_list(old, collecting_clear_unreachable_clear);
12257db96d56Sopenharmony_ci
12267db96d56Sopenharmony_ci    deduce_unreachable(young, &unreachable);
12277db96d56Sopenharmony_ci
12287db96d56Sopenharmony_ci    untrack_tuples(young);
12297db96d56Sopenharmony_ci    /* Move reachable objects to next generation. */
12307db96d56Sopenharmony_ci    if (young != old) {
12317db96d56Sopenharmony_ci        if (generation == NUM_GENERATIONS - 2) {
12327db96d56Sopenharmony_ci            gcstate->long_lived_pending += gc_list_size(young);
12337db96d56Sopenharmony_ci        }
12347db96d56Sopenharmony_ci        gc_list_merge(young, old);
12357db96d56Sopenharmony_ci    }
12367db96d56Sopenharmony_ci    else {
12377db96d56Sopenharmony_ci        /* We only un-track dicts in full collections, to avoid quadratic
12387db96d56Sopenharmony_ci           dict build-up. See issue #14775. */
12397db96d56Sopenharmony_ci        untrack_dicts(young);
12407db96d56Sopenharmony_ci        gcstate->long_lived_pending = 0;
12417db96d56Sopenharmony_ci        gcstate->long_lived_total = gc_list_size(young);
12427db96d56Sopenharmony_ci    }
12437db96d56Sopenharmony_ci
12447db96d56Sopenharmony_ci    /* All objects in unreachable are trash, but objects reachable from
12457db96d56Sopenharmony_ci     * legacy finalizers (e.g. tp_del) can't safely be deleted.
12467db96d56Sopenharmony_ci     */
12477db96d56Sopenharmony_ci    gc_list_init(&finalizers);
12487db96d56Sopenharmony_ci    // NEXT_MASK_UNREACHABLE is cleared here.
12497db96d56Sopenharmony_ci    // After move_legacy_finalizers(), unreachable is normal list.
12507db96d56Sopenharmony_ci    move_legacy_finalizers(&unreachable, &finalizers);
12517db96d56Sopenharmony_ci    /* finalizers contains the unreachable objects with a legacy finalizer;
12527db96d56Sopenharmony_ci     * unreachable objects reachable *from* those are also uncollectable,
12537db96d56Sopenharmony_ci     * and we move those into the finalizers list too.
12547db96d56Sopenharmony_ci     */
12557db96d56Sopenharmony_ci    move_legacy_finalizer_reachable(&finalizers);
12567db96d56Sopenharmony_ci
12577db96d56Sopenharmony_ci    validate_list(&finalizers, collecting_clear_unreachable_clear);
12587db96d56Sopenharmony_ci    validate_list(&unreachable, collecting_set_unreachable_clear);
12597db96d56Sopenharmony_ci
12607db96d56Sopenharmony_ci    /* Print debugging information. */
12617db96d56Sopenharmony_ci    if (gcstate->debug & DEBUG_COLLECTABLE) {
12627db96d56Sopenharmony_ci        for (gc = GC_NEXT(&unreachable); gc != &unreachable; gc = GC_NEXT(gc)) {
12637db96d56Sopenharmony_ci            debug_cycle("collectable", FROM_GC(gc));
12647db96d56Sopenharmony_ci        }
12657db96d56Sopenharmony_ci    }
12667db96d56Sopenharmony_ci
12677db96d56Sopenharmony_ci    /* Clear weakrefs and invoke callbacks as necessary. */
12687db96d56Sopenharmony_ci    m += handle_weakrefs(&unreachable, old);
12697db96d56Sopenharmony_ci
12707db96d56Sopenharmony_ci    validate_list(old, collecting_clear_unreachable_clear);
12717db96d56Sopenharmony_ci    validate_list(&unreachable, collecting_set_unreachable_clear);
12727db96d56Sopenharmony_ci
12737db96d56Sopenharmony_ci    /* Call tp_finalize on objects which have one. */
12747db96d56Sopenharmony_ci    finalize_garbage(tstate, &unreachable);
12757db96d56Sopenharmony_ci
12767db96d56Sopenharmony_ci    /* Handle any objects that may have resurrected after the call
12777db96d56Sopenharmony_ci     * to 'finalize_garbage' and continue the collection with the
12787db96d56Sopenharmony_ci     * objects that are still unreachable */
12797db96d56Sopenharmony_ci    PyGC_Head final_unreachable;
12807db96d56Sopenharmony_ci    handle_resurrected_objects(&unreachable, &final_unreachable, old);
12817db96d56Sopenharmony_ci
12827db96d56Sopenharmony_ci    /* Call tp_clear on objects in the final_unreachable set.  This will cause
12837db96d56Sopenharmony_ci    * the reference cycles to be broken.  It may also cause some objects
12847db96d56Sopenharmony_ci    * in finalizers to be freed.
12857db96d56Sopenharmony_ci    */
12867db96d56Sopenharmony_ci    m += gc_list_size(&final_unreachable);
12877db96d56Sopenharmony_ci    delete_garbage(tstate, gcstate, &final_unreachable, old);
12887db96d56Sopenharmony_ci
12897db96d56Sopenharmony_ci    /* Collect statistics on uncollectable objects found and print
12907db96d56Sopenharmony_ci     * debugging information. */
12917db96d56Sopenharmony_ci    for (gc = GC_NEXT(&finalizers); gc != &finalizers; gc = GC_NEXT(gc)) {
12927db96d56Sopenharmony_ci        n++;
12937db96d56Sopenharmony_ci        if (gcstate->debug & DEBUG_UNCOLLECTABLE)
12947db96d56Sopenharmony_ci            debug_cycle("uncollectable", FROM_GC(gc));
12957db96d56Sopenharmony_ci    }
12967db96d56Sopenharmony_ci    if (gcstate->debug & DEBUG_STATS) {
12977db96d56Sopenharmony_ci        double d = _PyTime_AsSecondsDouble(_PyTime_GetPerfCounter() - t1);
12987db96d56Sopenharmony_ci        PySys_WriteStderr(
12997db96d56Sopenharmony_ci            "gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n",
13007db96d56Sopenharmony_ci            n+m, n, d);
13017db96d56Sopenharmony_ci    }
13027db96d56Sopenharmony_ci
13037db96d56Sopenharmony_ci    /* Append instances in the uncollectable set to a Python
13047db96d56Sopenharmony_ci     * reachable list of garbage.  The programmer has to deal with
13057db96d56Sopenharmony_ci     * this if they insist on creating this type of structure.
13067db96d56Sopenharmony_ci     */
13077db96d56Sopenharmony_ci    handle_legacy_finalizers(tstate, gcstate, &finalizers, old);
13087db96d56Sopenharmony_ci    validate_list(old, collecting_clear_unreachable_clear);
13097db96d56Sopenharmony_ci
13107db96d56Sopenharmony_ci    /* Clear free list only during the collection of the highest
13117db96d56Sopenharmony_ci     * generation */
13127db96d56Sopenharmony_ci    if (generation == NUM_GENERATIONS-1) {
13137db96d56Sopenharmony_ci        clear_freelists(tstate->interp);
13147db96d56Sopenharmony_ci    }
13157db96d56Sopenharmony_ci
13167db96d56Sopenharmony_ci    if (_PyErr_Occurred(tstate)) {
13177db96d56Sopenharmony_ci        if (nofail) {
13187db96d56Sopenharmony_ci            _PyErr_Clear(tstate);
13197db96d56Sopenharmony_ci        }
13207db96d56Sopenharmony_ci        else {
13217db96d56Sopenharmony_ci            _PyErr_WriteUnraisableMsg("in garbage collection", NULL);
13227db96d56Sopenharmony_ci        }
13237db96d56Sopenharmony_ci    }
13247db96d56Sopenharmony_ci
13257db96d56Sopenharmony_ci    /* Update stats */
13267db96d56Sopenharmony_ci    if (n_collected) {
13277db96d56Sopenharmony_ci        *n_collected = m;
13287db96d56Sopenharmony_ci    }
13297db96d56Sopenharmony_ci    if (n_uncollectable) {
13307db96d56Sopenharmony_ci        *n_uncollectable = n;
13317db96d56Sopenharmony_ci    }
13327db96d56Sopenharmony_ci
13337db96d56Sopenharmony_ci    struct gc_generation_stats *stats = &gcstate->generation_stats[generation];
13347db96d56Sopenharmony_ci    stats->collections++;
13357db96d56Sopenharmony_ci    stats->collected += m;
13367db96d56Sopenharmony_ci    stats->uncollectable += n;
13377db96d56Sopenharmony_ci
13387db96d56Sopenharmony_ci    if (PyDTrace_GC_DONE_ENABLED()) {
13397db96d56Sopenharmony_ci        PyDTrace_GC_DONE(n + m);
13407db96d56Sopenharmony_ci    }
13417db96d56Sopenharmony_ci
13427db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
13437db96d56Sopenharmony_ci    return n + m;
13447db96d56Sopenharmony_ci}
13457db96d56Sopenharmony_ci
13467db96d56Sopenharmony_ci/* Invoke progress callbacks to notify clients that garbage collection
13477db96d56Sopenharmony_ci * is starting or stopping
13487db96d56Sopenharmony_ci */
13497db96d56Sopenharmony_cistatic void
13507db96d56Sopenharmony_ciinvoke_gc_callback(PyThreadState *tstate, const char *phase,
13517db96d56Sopenharmony_ci                   int generation, Py_ssize_t collected,
13527db96d56Sopenharmony_ci                   Py_ssize_t uncollectable)
13537db96d56Sopenharmony_ci{
13547db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
13557db96d56Sopenharmony_ci
13567db96d56Sopenharmony_ci    /* we may get called very early */
13577db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
13587db96d56Sopenharmony_ci    if (gcstate->callbacks == NULL) {
13597db96d56Sopenharmony_ci        return;
13607db96d56Sopenharmony_ci    }
13617db96d56Sopenharmony_ci
13627db96d56Sopenharmony_ci    /* The local variable cannot be rebound, check it for sanity */
13637db96d56Sopenharmony_ci    assert(PyList_CheckExact(gcstate->callbacks));
13647db96d56Sopenharmony_ci    PyObject *info = NULL;
13657db96d56Sopenharmony_ci    if (PyList_GET_SIZE(gcstate->callbacks) != 0) {
13667db96d56Sopenharmony_ci        info = Py_BuildValue("{sisnsn}",
13677db96d56Sopenharmony_ci            "generation", generation,
13687db96d56Sopenharmony_ci            "collected", collected,
13697db96d56Sopenharmony_ci            "uncollectable", uncollectable);
13707db96d56Sopenharmony_ci        if (info == NULL) {
13717db96d56Sopenharmony_ci            PyErr_WriteUnraisable(NULL);
13727db96d56Sopenharmony_ci            return;
13737db96d56Sopenharmony_ci        }
13747db96d56Sopenharmony_ci    }
13757db96d56Sopenharmony_ci    for (Py_ssize_t i=0; i<PyList_GET_SIZE(gcstate->callbacks); i++) {
13767db96d56Sopenharmony_ci        PyObject *r, *cb = PyList_GET_ITEM(gcstate->callbacks, i);
13777db96d56Sopenharmony_ci        Py_INCREF(cb); /* make sure cb doesn't go away */
13787db96d56Sopenharmony_ci        r = PyObject_CallFunction(cb, "sO", phase, info);
13797db96d56Sopenharmony_ci        if (r == NULL) {
13807db96d56Sopenharmony_ci            PyErr_WriteUnraisable(cb);
13817db96d56Sopenharmony_ci        }
13827db96d56Sopenharmony_ci        else {
13837db96d56Sopenharmony_ci            Py_DECREF(r);
13847db96d56Sopenharmony_ci        }
13857db96d56Sopenharmony_ci        Py_DECREF(cb);
13867db96d56Sopenharmony_ci    }
13877db96d56Sopenharmony_ci    Py_XDECREF(info);
13887db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
13897db96d56Sopenharmony_ci}
13907db96d56Sopenharmony_ci
13917db96d56Sopenharmony_ci/* Perform garbage collection of a generation and invoke
13927db96d56Sopenharmony_ci * progress callbacks.
13937db96d56Sopenharmony_ci */
13947db96d56Sopenharmony_cistatic Py_ssize_t
13957db96d56Sopenharmony_cigc_collect_with_callback(PyThreadState *tstate, int generation)
13967db96d56Sopenharmony_ci{
13977db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
13987db96d56Sopenharmony_ci    Py_ssize_t result, collected, uncollectable;
13997db96d56Sopenharmony_ci    invoke_gc_callback(tstate, "start", generation, 0, 0);
14007db96d56Sopenharmony_ci    result = gc_collect_main(tstate, generation, &collected, &uncollectable, 0);
14017db96d56Sopenharmony_ci    invoke_gc_callback(tstate, "stop", generation, collected, uncollectable);
14027db96d56Sopenharmony_ci    assert(!_PyErr_Occurred(tstate));
14037db96d56Sopenharmony_ci    return result;
14047db96d56Sopenharmony_ci}
14057db96d56Sopenharmony_ci
14067db96d56Sopenharmony_cistatic Py_ssize_t
14077db96d56Sopenharmony_cigc_collect_generations(PyThreadState *tstate)
14087db96d56Sopenharmony_ci{
14097db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
14107db96d56Sopenharmony_ci    /* Find the oldest generation (highest numbered) where the count
14117db96d56Sopenharmony_ci     * exceeds the threshold.  Objects in the that generation and
14127db96d56Sopenharmony_ci     * generations younger than it will be collected. */
14137db96d56Sopenharmony_ci    Py_ssize_t n = 0;
14147db96d56Sopenharmony_ci    for (int i = NUM_GENERATIONS-1; i >= 0; i--) {
14157db96d56Sopenharmony_ci        if (gcstate->generations[i].count > gcstate->generations[i].threshold) {
14167db96d56Sopenharmony_ci            /* Avoid quadratic performance degradation in number
14177db96d56Sopenharmony_ci               of tracked objects (see also issue #4074):
14187db96d56Sopenharmony_ci
14197db96d56Sopenharmony_ci               To limit the cost of garbage collection, there are two strategies;
14207db96d56Sopenharmony_ci                 - make each collection faster, e.g. by scanning fewer objects
14217db96d56Sopenharmony_ci                 - do less collections
14227db96d56Sopenharmony_ci               This heuristic is about the latter strategy.
14237db96d56Sopenharmony_ci
14247db96d56Sopenharmony_ci               In addition to the various configurable thresholds, we only trigger a
14257db96d56Sopenharmony_ci               full collection if the ratio
14267db96d56Sopenharmony_ci
14277db96d56Sopenharmony_ci                long_lived_pending / long_lived_total
14287db96d56Sopenharmony_ci
14297db96d56Sopenharmony_ci               is above a given value (hardwired to 25%).
14307db96d56Sopenharmony_ci
14317db96d56Sopenharmony_ci               The reason is that, while "non-full" collections (i.e., collections of
14327db96d56Sopenharmony_ci               the young and middle generations) will always examine roughly the same
14337db96d56Sopenharmony_ci               number of objects -- determined by the aforementioned thresholds --,
14347db96d56Sopenharmony_ci               the cost of a full collection is proportional to the total number of
14357db96d56Sopenharmony_ci               long-lived objects, which is virtually unbounded.
14367db96d56Sopenharmony_ci
14377db96d56Sopenharmony_ci               Indeed, it has been remarked that doing a full collection every
14387db96d56Sopenharmony_ci               <constant number> of object creations entails a dramatic performance
14397db96d56Sopenharmony_ci               degradation in workloads which consist in creating and storing lots of
14407db96d56Sopenharmony_ci               long-lived objects (e.g. building a large list of GC-tracked objects would
14417db96d56Sopenharmony_ci               show quadratic performance, instead of linear as expected: see issue #4074).
14427db96d56Sopenharmony_ci
14437db96d56Sopenharmony_ci               Using the above ratio, instead, yields amortized linear performance in
14447db96d56Sopenharmony_ci               the total number of objects (the effect of which can be summarized
14457db96d56Sopenharmony_ci               thusly: "each full garbage collection is more and more costly as the
14467db96d56Sopenharmony_ci               number of objects grows, but we do fewer and fewer of them").
14477db96d56Sopenharmony_ci
14487db96d56Sopenharmony_ci               This heuristic was suggested by Martin von Löwis on python-dev in
14497db96d56Sopenharmony_ci               June 2008. His original analysis and proposal can be found at:
14507db96d56Sopenharmony_ci               http://mail.python.org/pipermail/python-dev/2008-June/080579.html
14517db96d56Sopenharmony_ci            */
14527db96d56Sopenharmony_ci            if (i == NUM_GENERATIONS - 1
14537db96d56Sopenharmony_ci                && gcstate->long_lived_pending < gcstate->long_lived_total / 4)
14547db96d56Sopenharmony_ci                continue;
14557db96d56Sopenharmony_ci            n = gc_collect_with_callback(tstate, i);
14567db96d56Sopenharmony_ci            break;
14577db96d56Sopenharmony_ci        }
14587db96d56Sopenharmony_ci    }
14597db96d56Sopenharmony_ci    return n;
14607db96d56Sopenharmony_ci}
14617db96d56Sopenharmony_ci
14627db96d56Sopenharmony_ci#include "clinic/gcmodule.c.h"
14637db96d56Sopenharmony_ci
14647db96d56Sopenharmony_ci/*[clinic input]
14657db96d56Sopenharmony_cigc.enable
14667db96d56Sopenharmony_ci
14677db96d56Sopenharmony_ciEnable automatic garbage collection.
14687db96d56Sopenharmony_ci[clinic start generated code]*/
14697db96d56Sopenharmony_ci
14707db96d56Sopenharmony_cistatic PyObject *
14717db96d56Sopenharmony_cigc_enable_impl(PyObject *module)
14727db96d56Sopenharmony_ci/*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/
14737db96d56Sopenharmony_ci{
14747db96d56Sopenharmony_ci    PyGC_Enable();
14757db96d56Sopenharmony_ci    Py_RETURN_NONE;
14767db96d56Sopenharmony_ci}
14777db96d56Sopenharmony_ci
14787db96d56Sopenharmony_ci/*[clinic input]
14797db96d56Sopenharmony_cigc.disable
14807db96d56Sopenharmony_ci
14817db96d56Sopenharmony_ciDisable automatic garbage collection.
14827db96d56Sopenharmony_ci[clinic start generated code]*/
14837db96d56Sopenharmony_ci
14847db96d56Sopenharmony_cistatic PyObject *
14857db96d56Sopenharmony_cigc_disable_impl(PyObject *module)
14867db96d56Sopenharmony_ci/*[clinic end generated code: output=97d1030f7aa9d279 input=8c2e5a14e800d83b]*/
14877db96d56Sopenharmony_ci{
14887db96d56Sopenharmony_ci    PyGC_Disable();
14897db96d56Sopenharmony_ci    Py_RETURN_NONE;
14907db96d56Sopenharmony_ci}
14917db96d56Sopenharmony_ci
14927db96d56Sopenharmony_ci/*[clinic input]
14937db96d56Sopenharmony_cigc.isenabled -> bool
14947db96d56Sopenharmony_ci
14957db96d56Sopenharmony_ciReturns true if automatic garbage collection is enabled.
14967db96d56Sopenharmony_ci[clinic start generated code]*/
14977db96d56Sopenharmony_ci
14987db96d56Sopenharmony_cistatic int
14997db96d56Sopenharmony_cigc_isenabled_impl(PyObject *module)
15007db96d56Sopenharmony_ci/*[clinic end generated code: output=1874298331c49130 input=30005e0422373b31]*/
15017db96d56Sopenharmony_ci{
15027db96d56Sopenharmony_ci    return PyGC_IsEnabled();
15037db96d56Sopenharmony_ci}
15047db96d56Sopenharmony_ci
15057db96d56Sopenharmony_ci/*[clinic input]
15067db96d56Sopenharmony_cigc.collect -> Py_ssize_t
15077db96d56Sopenharmony_ci
15087db96d56Sopenharmony_ci    generation: int(c_default="NUM_GENERATIONS - 1") = 2
15097db96d56Sopenharmony_ci
15107db96d56Sopenharmony_ciRun the garbage collector.
15117db96d56Sopenharmony_ci
15127db96d56Sopenharmony_ciWith no arguments, run a full collection.  The optional argument
15137db96d56Sopenharmony_cimay be an integer specifying which generation to collect.  A ValueError
15147db96d56Sopenharmony_ciis raised if the generation number is invalid.
15157db96d56Sopenharmony_ci
15167db96d56Sopenharmony_ciThe number of unreachable objects is returned.
15177db96d56Sopenharmony_ci[clinic start generated code]*/
15187db96d56Sopenharmony_ci
15197db96d56Sopenharmony_cistatic Py_ssize_t
15207db96d56Sopenharmony_cigc_collect_impl(PyObject *module, int generation)
15217db96d56Sopenharmony_ci/*[clinic end generated code: output=b697e633043233c7 input=40720128b682d879]*/
15227db96d56Sopenharmony_ci{
15237db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
15247db96d56Sopenharmony_ci
15257db96d56Sopenharmony_ci    if (generation < 0 || generation >= NUM_GENERATIONS) {
15267db96d56Sopenharmony_ci        _PyErr_SetString(tstate, PyExc_ValueError, "invalid generation");
15277db96d56Sopenharmony_ci        return -1;
15287db96d56Sopenharmony_ci    }
15297db96d56Sopenharmony_ci
15307db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
15317db96d56Sopenharmony_ci    Py_ssize_t n;
15327db96d56Sopenharmony_ci    if (gcstate->collecting) {
15337db96d56Sopenharmony_ci        /* already collecting, don't do anything */
15347db96d56Sopenharmony_ci        n = 0;
15357db96d56Sopenharmony_ci    }
15367db96d56Sopenharmony_ci    else {
15377db96d56Sopenharmony_ci        gcstate->collecting = 1;
15387db96d56Sopenharmony_ci        n = gc_collect_with_callback(tstate, generation);
15397db96d56Sopenharmony_ci        gcstate->collecting = 0;
15407db96d56Sopenharmony_ci    }
15417db96d56Sopenharmony_ci    return n;
15427db96d56Sopenharmony_ci}
15437db96d56Sopenharmony_ci
15447db96d56Sopenharmony_ci/*[clinic input]
15457db96d56Sopenharmony_cigc.set_debug
15467db96d56Sopenharmony_ci
15477db96d56Sopenharmony_ci    flags: int
15487db96d56Sopenharmony_ci        An integer that can have the following bits turned on:
15497db96d56Sopenharmony_ci          DEBUG_STATS - Print statistics during collection.
15507db96d56Sopenharmony_ci          DEBUG_COLLECTABLE - Print collectable objects found.
15517db96d56Sopenharmony_ci          DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects
15527db96d56Sopenharmony_ci            found.
15537db96d56Sopenharmony_ci          DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.
15547db96d56Sopenharmony_ci          DEBUG_LEAK - Debug leaking programs (everything but STATS).
15557db96d56Sopenharmony_ci    /
15567db96d56Sopenharmony_ci
15577db96d56Sopenharmony_ciSet the garbage collection debugging flags.
15587db96d56Sopenharmony_ci
15597db96d56Sopenharmony_ciDebugging information is written to sys.stderr.
15607db96d56Sopenharmony_ci[clinic start generated code]*/
15617db96d56Sopenharmony_ci
15627db96d56Sopenharmony_cistatic PyObject *
15637db96d56Sopenharmony_cigc_set_debug_impl(PyObject *module, int flags)
15647db96d56Sopenharmony_ci/*[clinic end generated code: output=7c8366575486b228 input=5e5ce15e84fbed15]*/
15657db96d56Sopenharmony_ci{
15667db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
15677db96d56Sopenharmony_ci    gcstate->debug = flags;
15687db96d56Sopenharmony_ci    Py_RETURN_NONE;
15697db96d56Sopenharmony_ci}
15707db96d56Sopenharmony_ci
15717db96d56Sopenharmony_ci/*[clinic input]
15727db96d56Sopenharmony_cigc.get_debug -> int
15737db96d56Sopenharmony_ci
15747db96d56Sopenharmony_ciGet the garbage collection debugging flags.
15757db96d56Sopenharmony_ci[clinic start generated code]*/
15767db96d56Sopenharmony_ci
15777db96d56Sopenharmony_cistatic int
15787db96d56Sopenharmony_cigc_get_debug_impl(PyObject *module)
15797db96d56Sopenharmony_ci/*[clinic end generated code: output=91242f3506cd1e50 input=91a101e1c3b98366]*/
15807db96d56Sopenharmony_ci{
15817db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
15827db96d56Sopenharmony_ci    return gcstate->debug;
15837db96d56Sopenharmony_ci}
15847db96d56Sopenharmony_ci
15857db96d56Sopenharmony_ciPyDoc_STRVAR(gc_set_thresh__doc__,
15867db96d56Sopenharmony_ci"set_threshold(threshold0, [threshold1, threshold2]) -> None\n"
15877db96d56Sopenharmony_ci"\n"
15887db96d56Sopenharmony_ci"Sets the collection thresholds.  Setting threshold0 to zero disables\n"
15897db96d56Sopenharmony_ci"collection.\n");
15907db96d56Sopenharmony_ci
15917db96d56Sopenharmony_cistatic PyObject *
15927db96d56Sopenharmony_cigc_set_threshold(PyObject *self, PyObject *args)
15937db96d56Sopenharmony_ci{
15947db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
15957db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "i|ii:set_threshold",
15967db96d56Sopenharmony_ci                          &gcstate->generations[0].threshold,
15977db96d56Sopenharmony_ci                          &gcstate->generations[1].threshold,
15987db96d56Sopenharmony_ci                          &gcstate->generations[2].threshold))
15997db96d56Sopenharmony_ci        return NULL;
16007db96d56Sopenharmony_ci    for (int i = 3; i < NUM_GENERATIONS; i++) {
16017db96d56Sopenharmony_ci        /* generations higher than 2 get the same threshold */
16027db96d56Sopenharmony_ci        gcstate->generations[i].threshold = gcstate->generations[2].threshold;
16037db96d56Sopenharmony_ci    }
16047db96d56Sopenharmony_ci    Py_RETURN_NONE;
16057db96d56Sopenharmony_ci}
16067db96d56Sopenharmony_ci
16077db96d56Sopenharmony_ci/*[clinic input]
16087db96d56Sopenharmony_cigc.get_threshold
16097db96d56Sopenharmony_ci
16107db96d56Sopenharmony_ciReturn the current collection thresholds.
16117db96d56Sopenharmony_ci[clinic start generated code]*/
16127db96d56Sopenharmony_ci
16137db96d56Sopenharmony_cistatic PyObject *
16147db96d56Sopenharmony_cigc_get_threshold_impl(PyObject *module)
16157db96d56Sopenharmony_ci/*[clinic end generated code: output=7902bc9f41ecbbd8 input=286d79918034d6e6]*/
16167db96d56Sopenharmony_ci{
16177db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
16187db96d56Sopenharmony_ci    return Py_BuildValue("(iii)",
16197db96d56Sopenharmony_ci                         gcstate->generations[0].threshold,
16207db96d56Sopenharmony_ci                         gcstate->generations[1].threshold,
16217db96d56Sopenharmony_ci                         gcstate->generations[2].threshold);
16227db96d56Sopenharmony_ci}
16237db96d56Sopenharmony_ci
16247db96d56Sopenharmony_ci/*[clinic input]
16257db96d56Sopenharmony_cigc.get_count
16267db96d56Sopenharmony_ci
16277db96d56Sopenharmony_ciReturn a three-tuple of the current collection counts.
16287db96d56Sopenharmony_ci[clinic start generated code]*/
16297db96d56Sopenharmony_ci
16307db96d56Sopenharmony_cistatic PyObject *
16317db96d56Sopenharmony_cigc_get_count_impl(PyObject *module)
16327db96d56Sopenharmony_ci/*[clinic end generated code: output=354012e67b16398f input=a392794a08251751]*/
16337db96d56Sopenharmony_ci{
16347db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
16357db96d56Sopenharmony_ci    return Py_BuildValue("(iii)",
16367db96d56Sopenharmony_ci                         gcstate->generations[0].count,
16377db96d56Sopenharmony_ci                         gcstate->generations[1].count,
16387db96d56Sopenharmony_ci                         gcstate->generations[2].count);
16397db96d56Sopenharmony_ci}
16407db96d56Sopenharmony_ci
16417db96d56Sopenharmony_cistatic int
16427db96d56Sopenharmony_cireferrersvisit(PyObject* obj, PyObject *objs)
16437db96d56Sopenharmony_ci{
16447db96d56Sopenharmony_ci    Py_ssize_t i;
16457db96d56Sopenharmony_ci    for (i = 0; i < PyTuple_GET_SIZE(objs); i++)
16467db96d56Sopenharmony_ci        if (PyTuple_GET_ITEM(objs, i) == obj)
16477db96d56Sopenharmony_ci            return 1;
16487db96d56Sopenharmony_ci    return 0;
16497db96d56Sopenharmony_ci}
16507db96d56Sopenharmony_ci
16517db96d56Sopenharmony_cistatic int
16527db96d56Sopenharmony_cigc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist)
16537db96d56Sopenharmony_ci{
16547db96d56Sopenharmony_ci    PyGC_Head *gc;
16557db96d56Sopenharmony_ci    PyObject *obj;
16567db96d56Sopenharmony_ci    traverseproc traverse;
16577db96d56Sopenharmony_ci    for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(gc)) {
16587db96d56Sopenharmony_ci        obj = FROM_GC(gc);
16597db96d56Sopenharmony_ci        traverse = Py_TYPE(obj)->tp_traverse;
16607db96d56Sopenharmony_ci        if (obj == objs || obj == resultlist)
16617db96d56Sopenharmony_ci            continue;
16627db96d56Sopenharmony_ci        if (traverse(obj, (visitproc)referrersvisit, objs)) {
16637db96d56Sopenharmony_ci            if (PyList_Append(resultlist, obj) < 0)
16647db96d56Sopenharmony_ci                return 0; /* error */
16657db96d56Sopenharmony_ci        }
16667db96d56Sopenharmony_ci    }
16677db96d56Sopenharmony_ci    return 1; /* no error */
16687db96d56Sopenharmony_ci}
16697db96d56Sopenharmony_ci
16707db96d56Sopenharmony_ciPyDoc_STRVAR(gc_get_referrers__doc__,
16717db96d56Sopenharmony_ci"get_referrers(*objs) -> list\n\
16727db96d56Sopenharmony_ciReturn the list of objects that directly refer to any of objs.");
16737db96d56Sopenharmony_ci
16747db96d56Sopenharmony_cistatic PyObject *
16757db96d56Sopenharmony_cigc_get_referrers(PyObject *self, PyObject *args)
16767db96d56Sopenharmony_ci{
16777db96d56Sopenharmony_ci    if (PySys_Audit("gc.get_referrers", "(O)", args) < 0) {
16787db96d56Sopenharmony_ci        return NULL;
16797db96d56Sopenharmony_ci    }
16807db96d56Sopenharmony_ci
16817db96d56Sopenharmony_ci    PyObject *result = PyList_New(0);
16827db96d56Sopenharmony_ci    if (!result) {
16837db96d56Sopenharmony_ci        return NULL;
16847db96d56Sopenharmony_ci    }
16857db96d56Sopenharmony_ci
16867db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
16877db96d56Sopenharmony_ci    for (int i = 0; i < NUM_GENERATIONS; i++) {
16887db96d56Sopenharmony_ci        if (!(gc_referrers_for(args, GEN_HEAD(gcstate, i), result))) {
16897db96d56Sopenharmony_ci            Py_DECREF(result);
16907db96d56Sopenharmony_ci            return NULL;
16917db96d56Sopenharmony_ci        }
16927db96d56Sopenharmony_ci    }
16937db96d56Sopenharmony_ci    return result;
16947db96d56Sopenharmony_ci}
16957db96d56Sopenharmony_ci
16967db96d56Sopenharmony_ci/* Append obj to list; return true if error (out of memory), false if OK. */
16977db96d56Sopenharmony_cistatic int
16987db96d56Sopenharmony_cireferentsvisit(PyObject *obj, PyObject *list)
16997db96d56Sopenharmony_ci{
17007db96d56Sopenharmony_ci    return PyList_Append(list, obj) < 0;
17017db96d56Sopenharmony_ci}
17027db96d56Sopenharmony_ci
17037db96d56Sopenharmony_ciPyDoc_STRVAR(gc_get_referents__doc__,
17047db96d56Sopenharmony_ci"get_referents(*objs) -> list\n\
17057db96d56Sopenharmony_ciReturn the list of objects that are directly referred to by objs.");
17067db96d56Sopenharmony_ci
17077db96d56Sopenharmony_cistatic PyObject *
17087db96d56Sopenharmony_cigc_get_referents(PyObject *self, PyObject *args)
17097db96d56Sopenharmony_ci{
17107db96d56Sopenharmony_ci    Py_ssize_t i;
17117db96d56Sopenharmony_ci    if (PySys_Audit("gc.get_referents", "(O)", args) < 0) {
17127db96d56Sopenharmony_ci        return NULL;
17137db96d56Sopenharmony_ci    }
17147db96d56Sopenharmony_ci    PyObject *result = PyList_New(0);
17157db96d56Sopenharmony_ci
17167db96d56Sopenharmony_ci    if (result == NULL)
17177db96d56Sopenharmony_ci        return NULL;
17187db96d56Sopenharmony_ci
17197db96d56Sopenharmony_ci    for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
17207db96d56Sopenharmony_ci        traverseproc traverse;
17217db96d56Sopenharmony_ci        PyObject *obj = PyTuple_GET_ITEM(args, i);
17227db96d56Sopenharmony_ci
17237db96d56Sopenharmony_ci        if (!_PyObject_IS_GC(obj))
17247db96d56Sopenharmony_ci            continue;
17257db96d56Sopenharmony_ci        traverse = Py_TYPE(obj)->tp_traverse;
17267db96d56Sopenharmony_ci        if (! traverse)
17277db96d56Sopenharmony_ci            continue;
17287db96d56Sopenharmony_ci        if (traverse(obj, (visitproc)referentsvisit, result)) {
17297db96d56Sopenharmony_ci            Py_DECREF(result);
17307db96d56Sopenharmony_ci            return NULL;
17317db96d56Sopenharmony_ci        }
17327db96d56Sopenharmony_ci    }
17337db96d56Sopenharmony_ci    return result;
17347db96d56Sopenharmony_ci}
17357db96d56Sopenharmony_ci
17367db96d56Sopenharmony_ci/*[clinic input]
17377db96d56Sopenharmony_cigc.get_objects
17387db96d56Sopenharmony_ci    generation: Py_ssize_t(accept={int, NoneType}, c_default="-1") = None
17397db96d56Sopenharmony_ci        Generation to extract the objects from.
17407db96d56Sopenharmony_ci
17417db96d56Sopenharmony_ciReturn a list of objects tracked by the collector (excluding the list returned).
17427db96d56Sopenharmony_ci
17437db96d56Sopenharmony_ciIf generation is not None, return only the objects tracked by the collector
17447db96d56Sopenharmony_cithat are in that generation.
17457db96d56Sopenharmony_ci[clinic start generated code]*/
17467db96d56Sopenharmony_ci
17477db96d56Sopenharmony_cistatic PyObject *
17487db96d56Sopenharmony_cigc_get_objects_impl(PyObject *module, Py_ssize_t generation)
17497db96d56Sopenharmony_ci/*[clinic end generated code: output=48b35fea4ba6cb0e input=ef7da9df9806754c]*/
17507db96d56Sopenharmony_ci{
17517db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
17527db96d56Sopenharmony_ci    int i;
17537db96d56Sopenharmony_ci    PyObject* result;
17547db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
17557db96d56Sopenharmony_ci
17567db96d56Sopenharmony_ci    if (PySys_Audit("gc.get_objects", "n", generation) < 0) {
17577db96d56Sopenharmony_ci        return NULL;
17587db96d56Sopenharmony_ci    }
17597db96d56Sopenharmony_ci
17607db96d56Sopenharmony_ci    result = PyList_New(0);
17617db96d56Sopenharmony_ci    if (result == NULL) {
17627db96d56Sopenharmony_ci        return NULL;
17637db96d56Sopenharmony_ci    }
17647db96d56Sopenharmony_ci
17657db96d56Sopenharmony_ci    /* If generation is passed, we extract only that generation */
17667db96d56Sopenharmony_ci    if (generation != -1) {
17677db96d56Sopenharmony_ci        if (generation >= NUM_GENERATIONS) {
17687db96d56Sopenharmony_ci            _PyErr_Format(tstate, PyExc_ValueError,
17697db96d56Sopenharmony_ci                          "generation parameter must be less than the number of "
17707db96d56Sopenharmony_ci                          "available generations (%i)",
17717db96d56Sopenharmony_ci                           NUM_GENERATIONS);
17727db96d56Sopenharmony_ci            goto error;
17737db96d56Sopenharmony_ci        }
17747db96d56Sopenharmony_ci
17757db96d56Sopenharmony_ci        if (generation < 0) {
17767db96d56Sopenharmony_ci            _PyErr_SetString(tstate, PyExc_ValueError,
17777db96d56Sopenharmony_ci                             "generation parameter cannot be negative");
17787db96d56Sopenharmony_ci            goto error;
17797db96d56Sopenharmony_ci        }
17807db96d56Sopenharmony_ci
17817db96d56Sopenharmony_ci        if (append_objects(result, GEN_HEAD(gcstate, generation))) {
17827db96d56Sopenharmony_ci            goto error;
17837db96d56Sopenharmony_ci        }
17847db96d56Sopenharmony_ci
17857db96d56Sopenharmony_ci        return result;
17867db96d56Sopenharmony_ci    }
17877db96d56Sopenharmony_ci
17887db96d56Sopenharmony_ci    /* If generation is not passed or None, get all objects from all generations */
17897db96d56Sopenharmony_ci    for (i = 0; i < NUM_GENERATIONS; i++) {
17907db96d56Sopenharmony_ci        if (append_objects(result, GEN_HEAD(gcstate, i))) {
17917db96d56Sopenharmony_ci            goto error;
17927db96d56Sopenharmony_ci        }
17937db96d56Sopenharmony_ci    }
17947db96d56Sopenharmony_ci    return result;
17957db96d56Sopenharmony_ci
17967db96d56Sopenharmony_cierror:
17977db96d56Sopenharmony_ci    Py_DECREF(result);
17987db96d56Sopenharmony_ci    return NULL;
17997db96d56Sopenharmony_ci}
18007db96d56Sopenharmony_ci
18017db96d56Sopenharmony_ci/*[clinic input]
18027db96d56Sopenharmony_cigc.get_stats
18037db96d56Sopenharmony_ci
18047db96d56Sopenharmony_ciReturn a list of dictionaries containing per-generation statistics.
18057db96d56Sopenharmony_ci[clinic start generated code]*/
18067db96d56Sopenharmony_ci
18077db96d56Sopenharmony_cistatic PyObject *
18087db96d56Sopenharmony_cigc_get_stats_impl(PyObject *module)
18097db96d56Sopenharmony_ci/*[clinic end generated code: output=a8ab1d8a5d26f3ab input=1ef4ed9d17b1a470]*/
18107db96d56Sopenharmony_ci{
18117db96d56Sopenharmony_ci    int i;
18127db96d56Sopenharmony_ci    struct gc_generation_stats stats[NUM_GENERATIONS], *st;
18137db96d56Sopenharmony_ci
18147db96d56Sopenharmony_ci    /* To get consistent values despite allocations while constructing
18157db96d56Sopenharmony_ci       the result list, we use a snapshot of the running stats. */
18167db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
18177db96d56Sopenharmony_ci    for (i = 0; i < NUM_GENERATIONS; i++) {
18187db96d56Sopenharmony_ci        stats[i] = gcstate->generation_stats[i];
18197db96d56Sopenharmony_ci    }
18207db96d56Sopenharmony_ci
18217db96d56Sopenharmony_ci    PyObject *result = PyList_New(0);
18227db96d56Sopenharmony_ci    if (result == NULL)
18237db96d56Sopenharmony_ci        return NULL;
18247db96d56Sopenharmony_ci
18257db96d56Sopenharmony_ci    for (i = 0; i < NUM_GENERATIONS; i++) {
18267db96d56Sopenharmony_ci        PyObject *dict;
18277db96d56Sopenharmony_ci        st = &stats[i];
18287db96d56Sopenharmony_ci        dict = Py_BuildValue("{snsnsn}",
18297db96d56Sopenharmony_ci                             "collections", st->collections,
18307db96d56Sopenharmony_ci                             "collected", st->collected,
18317db96d56Sopenharmony_ci                             "uncollectable", st->uncollectable
18327db96d56Sopenharmony_ci                            );
18337db96d56Sopenharmony_ci        if (dict == NULL)
18347db96d56Sopenharmony_ci            goto error;
18357db96d56Sopenharmony_ci        if (PyList_Append(result, dict)) {
18367db96d56Sopenharmony_ci            Py_DECREF(dict);
18377db96d56Sopenharmony_ci            goto error;
18387db96d56Sopenharmony_ci        }
18397db96d56Sopenharmony_ci        Py_DECREF(dict);
18407db96d56Sopenharmony_ci    }
18417db96d56Sopenharmony_ci    return result;
18427db96d56Sopenharmony_ci
18437db96d56Sopenharmony_cierror:
18447db96d56Sopenharmony_ci    Py_XDECREF(result);
18457db96d56Sopenharmony_ci    return NULL;
18467db96d56Sopenharmony_ci}
18477db96d56Sopenharmony_ci
18487db96d56Sopenharmony_ci
18497db96d56Sopenharmony_ci/*[clinic input]
18507db96d56Sopenharmony_cigc.is_tracked
18517db96d56Sopenharmony_ci
18527db96d56Sopenharmony_ci    obj: object
18537db96d56Sopenharmony_ci    /
18547db96d56Sopenharmony_ci
18557db96d56Sopenharmony_ciReturns true if the object is tracked by the garbage collector.
18567db96d56Sopenharmony_ci
18577db96d56Sopenharmony_ciSimple atomic objects will return false.
18587db96d56Sopenharmony_ci[clinic start generated code]*/
18597db96d56Sopenharmony_ci
18607db96d56Sopenharmony_cistatic PyObject *
18617db96d56Sopenharmony_cigc_is_tracked(PyObject *module, PyObject *obj)
18627db96d56Sopenharmony_ci/*[clinic end generated code: output=14f0103423b28e31 input=d83057f170ea2723]*/
18637db96d56Sopenharmony_ci{
18647db96d56Sopenharmony_ci    PyObject *result;
18657db96d56Sopenharmony_ci
18667db96d56Sopenharmony_ci    if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj))
18677db96d56Sopenharmony_ci        result = Py_True;
18687db96d56Sopenharmony_ci    else
18697db96d56Sopenharmony_ci        result = Py_False;
18707db96d56Sopenharmony_ci    Py_INCREF(result);
18717db96d56Sopenharmony_ci    return result;
18727db96d56Sopenharmony_ci}
18737db96d56Sopenharmony_ci
18747db96d56Sopenharmony_ci/*[clinic input]
18757db96d56Sopenharmony_cigc.is_finalized
18767db96d56Sopenharmony_ci
18777db96d56Sopenharmony_ci    obj: object
18787db96d56Sopenharmony_ci    /
18797db96d56Sopenharmony_ci
18807db96d56Sopenharmony_ciReturns true if the object has been already finalized by the GC.
18817db96d56Sopenharmony_ci[clinic start generated code]*/
18827db96d56Sopenharmony_ci
18837db96d56Sopenharmony_cistatic PyObject *
18847db96d56Sopenharmony_cigc_is_finalized(PyObject *module, PyObject *obj)
18857db96d56Sopenharmony_ci/*[clinic end generated code: output=e1516ac119a918ed input=201d0c58f69ae390]*/
18867db96d56Sopenharmony_ci{
18877db96d56Sopenharmony_ci    if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) {
18887db96d56Sopenharmony_ci         Py_RETURN_TRUE;
18897db96d56Sopenharmony_ci    }
18907db96d56Sopenharmony_ci    Py_RETURN_FALSE;
18917db96d56Sopenharmony_ci}
18927db96d56Sopenharmony_ci
18937db96d56Sopenharmony_ci/*[clinic input]
18947db96d56Sopenharmony_cigc.freeze
18957db96d56Sopenharmony_ci
18967db96d56Sopenharmony_ciFreeze all current tracked objects and ignore them for future collections.
18977db96d56Sopenharmony_ci
18987db96d56Sopenharmony_ciThis can be used before a POSIX fork() call to make the gc copy-on-write friendly.
18997db96d56Sopenharmony_ciNote: collection before a POSIX fork() call may free pages for future allocation
19007db96d56Sopenharmony_ciwhich can cause copy-on-write.
19017db96d56Sopenharmony_ci[clinic start generated code]*/
19027db96d56Sopenharmony_ci
19037db96d56Sopenharmony_cistatic PyObject *
19047db96d56Sopenharmony_cigc_freeze_impl(PyObject *module)
19057db96d56Sopenharmony_ci/*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/
19067db96d56Sopenharmony_ci{
19077db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
19087db96d56Sopenharmony_ci    for (int i = 0; i < NUM_GENERATIONS; ++i) {
19097db96d56Sopenharmony_ci        gc_list_merge(GEN_HEAD(gcstate, i), &gcstate->permanent_generation.head);
19107db96d56Sopenharmony_ci        gcstate->generations[i].count = 0;
19117db96d56Sopenharmony_ci    }
19127db96d56Sopenharmony_ci    Py_RETURN_NONE;
19137db96d56Sopenharmony_ci}
19147db96d56Sopenharmony_ci
19157db96d56Sopenharmony_ci/*[clinic input]
19167db96d56Sopenharmony_cigc.unfreeze
19177db96d56Sopenharmony_ci
19187db96d56Sopenharmony_ciUnfreeze all objects in the permanent generation.
19197db96d56Sopenharmony_ci
19207db96d56Sopenharmony_ciPut all objects in the permanent generation back into oldest generation.
19217db96d56Sopenharmony_ci[clinic start generated code]*/
19227db96d56Sopenharmony_ci
19237db96d56Sopenharmony_cistatic PyObject *
19247db96d56Sopenharmony_cigc_unfreeze_impl(PyObject *module)
19257db96d56Sopenharmony_ci/*[clinic end generated code: output=1c15f2043b25e169 input=2dd52b170f4cef6c]*/
19267db96d56Sopenharmony_ci{
19277db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
19287db96d56Sopenharmony_ci    gc_list_merge(&gcstate->permanent_generation.head,
19297db96d56Sopenharmony_ci                  GEN_HEAD(gcstate, NUM_GENERATIONS-1));
19307db96d56Sopenharmony_ci    Py_RETURN_NONE;
19317db96d56Sopenharmony_ci}
19327db96d56Sopenharmony_ci
19337db96d56Sopenharmony_ci/*[clinic input]
19347db96d56Sopenharmony_cigc.get_freeze_count -> Py_ssize_t
19357db96d56Sopenharmony_ci
19367db96d56Sopenharmony_ciReturn the number of objects in the permanent generation.
19377db96d56Sopenharmony_ci[clinic start generated code]*/
19387db96d56Sopenharmony_ci
19397db96d56Sopenharmony_cistatic Py_ssize_t
19407db96d56Sopenharmony_cigc_get_freeze_count_impl(PyObject *module)
19417db96d56Sopenharmony_ci/*[clinic end generated code: output=61cbd9f43aa032e1 input=45ffbc65cfe2a6ed]*/
19427db96d56Sopenharmony_ci{
19437db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
19447db96d56Sopenharmony_ci    return gc_list_size(&gcstate->permanent_generation.head);
19457db96d56Sopenharmony_ci}
19467db96d56Sopenharmony_ci
19477db96d56Sopenharmony_ci
19487db96d56Sopenharmony_ciPyDoc_STRVAR(gc__doc__,
19497db96d56Sopenharmony_ci"This module provides access to the garbage collector for reference cycles.\n"
19507db96d56Sopenharmony_ci"\n"
19517db96d56Sopenharmony_ci"enable() -- Enable automatic garbage collection.\n"
19527db96d56Sopenharmony_ci"disable() -- Disable automatic garbage collection.\n"
19537db96d56Sopenharmony_ci"isenabled() -- Returns true if automatic collection is enabled.\n"
19547db96d56Sopenharmony_ci"collect() -- Do a full collection right now.\n"
19557db96d56Sopenharmony_ci"get_count() -- Return the current collection counts.\n"
19567db96d56Sopenharmony_ci"get_stats() -- Return list of dictionaries containing per-generation stats.\n"
19577db96d56Sopenharmony_ci"set_debug() -- Set debugging flags.\n"
19587db96d56Sopenharmony_ci"get_debug() -- Get debugging flags.\n"
19597db96d56Sopenharmony_ci"set_threshold() -- Set the collection thresholds.\n"
19607db96d56Sopenharmony_ci"get_threshold() -- Return the current the collection thresholds.\n"
19617db96d56Sopenharmony_ci"get_objects() -- Return a list of all objects tracked by the collector.\n"
19627db96d56Sopenharmony_ci"is_tracked() -- Returns true if a given object is tracked.\n"
19637db96d56Sopenharmony_ci"is_finalized() -- Returns true if a given object has been already finalized.\n"
19647db96d56Sopenharmony_ci"get_referrers() -- Return the list of objects that refer to an object.\n"
19657db96d56Sopenharmony_ci"get_referents() -- Return the list of objects that an object refers to.\n"
19667db96d56Sopenharmony_ci"freeze() -- Freeze all tracked objects and ignore them for future collections.\n"
19677db96d56Sopenharmony_ci"unfreeze() -- Unfreeze all objects in the permanent generation.\n"
19687db96d56Sopenharmony_ci"get_freeze_count() -- Return the number of objects in the permanent generation.\n");
19697db96d56Sopenharmony_ci
19707db96d56Sopenharmony_cistatic PyMethodDef GcMethods[] = {
19717db96d56Sopenharmony_ci    GC_ENABLE_METHODDEF
19727db96d56Sopenharmony_ci    GC_DISABLE_METHODDEF
19737db96d56Sopenharmony_ci    GC_ISENABLED_METHODDEF
19747db96d56Sopenharmony_ci    GC_SET_DEBUG_METHODDEF
19757db96d56Sopenharmony_ci    GC_GET_DEBUG_METHODDEF
19767db96d56Sopenharmony_ci    GC_GET_COUNT_METHODDEF
19777db96d56Sopenharmony_ci    {"set_threshold",  gc_set_threshold, METH_VARARGS, gc_set_thresh__doc__},
19787db96d56Sopenharmony_ci    GC_GET_THRESHOLD_METHODDEF
19797db96d56Sopenharmony_ci    GC_COLLECT_METHODDEF
19807db96d56Sopenharmony_ci    GC_GET_OBJECTS_METHODDEF
19817db96d56Sopenharmony_ci    GC_GET_STATS_METHODDEF
19827db96d56Sopenharmony_ci    GC_IS_TRACKED_METHODDEF
19837db96d56Sopenharmony_ci    GC_IS_FINALIZED_METHODDEF
19847db96d56Sopenharmony_ci    {"get_referrers",  gc_get_referrers, METH_VARARGS,
19857db96d56Sopenharmony_ci        gc_get_referrers__doc__},
19867db96d56Sopenharmony_ci    {"get_referents",  gc_get_referents, METH_VARARGS,
19877db96d56Sopenharmony_ci        gc_get_referents__doc__},
19887db96d56Sopenharmony_ci    GC_FREEZE_METHODDEF
19897db96d56Sopenharmony_ci    GC_UNFREEZE_METHODDEF
19907db96d56Sopenharmony_ci    GC_GET_FREEZE_COUNT_METHODDEF
19917db96d56Sopenharmony_ci    {NULL,      NULL}           /* Sentinel */
19927db96d56Sopenharmony_ci};
19937db96d56Sopenharmony_ci
19947db96d56Sopenharmony_cistatic int
19957db96d56Sopenharmony_cigcmodule_exec(PyObject *module)
19967db96d56Sopenharmony_ci{
19977db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
19987db96d56Sopenharmony_ci
19997db96d56Sopenharmony_ci    /* garbage and callbacks are initialized by _PyGC_Init() early in
20007db96d56Sopenharmony_ci     * interpreter lifecycle. */
20017db96d56Sopenharmony_ci    assert(gcstate->garbage != NULL);
20027db96d56Sopenharmony_ci    if (PyModule_AddObjectRef(module, "garbage", gcstate->garbage) < 0) {
20037db96d56Sopenharmony_ci        return -1;
20047db96d56Sopenharmony_ci    }
20057db96d56Sopenharmony_ci    assert(gcstate->callbacks != NULL);
20067db96d56Sopenharmony_ci    if (PyModule_AddObjectRef(module, "callbacks", gcstate->callbacks) < 0) {
20077db96d56Sopenharmony_ci        return -1;
20087db96d56Sopenharmony_ci    }
20097db96d56Sopenharmony_ci
20107db96d56Sopenharmony_ci#define ADD_INT(NAME) if (PyModule_AddIntConstant(module, #NAME, NAME) < 0) { return -1; }
20117db96d56Sopenharmony_ci    ADD_INT(DEBUG_STATS);
20127db96d56Sopenharmony_ci    ADD_INT(DEBUG_COLLECTABLE);
20137db96d56Sopenharmony_ci    ADD_INT(DEBUG_UNCOLLECTABLE);
20147db96d56Sopenharmony_ci    ADD_INT(DEBUG_SAVEALL);
20157db96d56Sopenharmony_ci    ADD_INT(DEBUG_LEAK);
20167db96d56Sopenharmony_ci#undef ADD_INT
20177db96d56Sopenharmony_ci    return 0;
20187db96d56Sopenharmony_ci}
20197db96d56Sopenharmony_ci
20207db96d56Sopenharmony_cistatic PyModuleDef_Slot gcmodule_slots[] = {
20217db96d56Sopenharmony_ci    {Py_mod_exec, gcmodule_exec},
20227db96d56Sopenharmony_ci    {0, NULL}
20237db96d56Sopenharmony_ci};
20247db96d56Sopenharmony_ci
20257db96d56Sopenharmony_cistatic struct PyModuleDef gcmodule = {
20267db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
20277db96d56Sopenharmony_ci    .m_name = "gc",
20287db96d56Sopenharmony_ci    .m_doc = gc__doc__,
20297db96d56Sopenharmony_ci    .m_size = 0,  // per interpreter state, see: get_gc_state()
20307db96d56Sopenharmony_ci    .m_methods = GcMethods,
20317db96d56Sopenharmony_ci    .m_slots = gcmodule_slots
20327db96d56Sopenharmony_ci};
20337db96d56Sopenharmony_ci
20347db96d56Sopenharmony_ciPyMODINIT_FUNC
20357db96d56Sopenharmony_ciPyInit_gc(void)
20367db96d56Sopenharmony_ci{
20377db96d56Sopenharmony_ci    return PyModuleDef_Init(&gcmodule);
20387db96d56Sopenharmony_ci}
20397db96d56Sopenharmony_ci
20407db96d56Sopenharmony_ci/* C API for controlling the state of the garbage collector */
20417db96d56Sopenharmony_ciint
20427db96d56Sopenharmony_ciPyGC_Enable(void)
20437db96d56Sopenharmony_ci{
20447db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
20457db96d56Sopenharmony_ci    int old_state = gcstate->enabled;
20467db96d56Sopenharmony_ci    gcstate->enabled = 1;
20477db96d56Sopenharmony_ci    return old_state;
20487db96d56Sopenharmony_ci}
20497db96d56Sopenharmony_ci
20507db96d56Sopenharmony_ciint
20517db96d56Sopenharmony_ciPyGC_Disable(void)
20527db96d56Sopenharmony_ci{
20537db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
20547db96d56Sopenharmony_ci    int old_state = gcstate->enabled;
20557db96d56Sopenharmony_ci    gcstate->enabled = 0;
20567db96d56Sopenharmony_ci    return old_state;
20577db96d56Sopenharmony_ci}
20587db96d56Sopenharmony_ci
20597db96d56Sopenharmony_ciint
20607db96d56Sopenharmony_ciPyGC_IsEnabled(void)
20617db96d56Sopenharmony_ci{
20627db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
20637db96d56Sopenharmony_ci    return gcstate->enabled;
20647db96d56Sopenharmony_ci}
20657db96d56Sopenharmony_ci
20667db96d56Sopenharmony_ci/* Public API to invoke gc.collect() from C */
20677db96d56Sopenharmony_ciPy_ssize_t
20687db96d56Sopenharmony_ciPyGC_Collect(void)
20697db96d56Sopenharmony_ci{
20707db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
20717db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
20727db96d56Sopenharmony_ci
20737db96d56Sopenharmony_ci    if (!gcstate->enabled) {
20747db96d56Sopenharmony_ci        return 0;
20757db96d56Sopenharmony_ci    }
20767db96d56Sopenharmony_ci
20777db96d56Sopenharmony_ci    Py_ssize_t n;
20787db96d56Sopenharmony_ci    if (gcstate->collecting) {
20797db96d56Sopenharmony_ci        /* already collecting, don't do anything */
20807db96d56Sopenharmony_ci        n = 0;
20817db96d56Sopenharmony_ci    }
20827db96d56Sopenharmony_ci    else {
20837db96d56Sopenharmony_ci        PyObject *exc, *value, *tb;
20847db96d56Sopenharmony_ci        gcstate->collecting = 1;
20857db96d56Sopenharmony_ci        _PyErr_Fetch(tstate, &exc, &value, &tb);
20867db96d56Sopenharmony_ci        n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1);
20877db96d56Sopenharmony_ci        _PyErr_Restore(tstate, exc, value, tb);
20887db96d56Sopenharmony_ci        gcstate->collecting = 0;
20897db96d56Sopenharmony_ci    }
20907db96d56Sopenharmony_ci
20917db96d56Sopenharmony_ci    return n;
20927db96d56Sopenharmony_ci}
20937db96d56Sopenharmony_ci
20947db96d56Sopenharmony_ciPy_ssize_t
20957db96d56Sopenharmony_ci_PyGC_CollectNoFail(PyThreadState *tstate)
20967db96d56Sopenharmony_ci{
20977db96d56Sopenharmony_ci    /* Ideally, this function is only called on interpreter shutdown,
20987db96d56Sopenharmony_ci       and therefore not recursively.  Unfortunately, when there are daemon
20997db96d56Sopenharmony_ci       threads, a daemon thread can start a cyclic garbage collection
21007db96d56Sopenharmony_ci       during interpreter shutdown (and then never finish it).
21017db96d56Sopenharmony_ci       See http://bugs.python.org/issue8713#msg195178 for an example.
21027db96d56Sopenharmony_ci       */
21037db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
21047db96d56Sopenharmony_ci    if (gcstate->collecting) {
21057db96d56Sopenharmony_ci        return 0;
21067db96d56Sopenharmony_ci    }
21077db96d56Sopenharmony_ci
21087db96d56Sopenharmony_ci    Py_ssize_t n;
21097db96d56Sopenharmony_ci    gcstate->collecting = 1;
21107db96d56Sopenharmony_ci    n = gc_collect_main(tstate, NUM_GENERATIONS - 1, NULL, NULL, 1);
21117db96d56Sopenharmony_ci    gcstate->collecting = 0;
21127db96d56Sopenharmony_ci    return n;
21137db96d56Sopenharmony_ci}
21147db96d56Sopenharmony_ci
21157db96d56Sopenharmony_civoid
21167db96d56Sopenharmony_ci_PyGC_DumpShutdownStats(PyInterpreterState *interp)
21177db96d56Sopenharmony_ci{
21187db96d56Sopenharmony_ci    GCState *gcstate = &interp->gc;
21197db96d56Sopenharmony_ci    if (!(gcstate->debug & DEBUG_SAVEALL)
21207db96d56Sopenharmony_ci        && gcstate->garbage != NULL && PyList_GET_SIZE(gcstate->garbage) > 0) {
21217db96d56Sopenharmony_ci        const char *message;
21227db96d56Sopenharmony_ci        if (gcstate->debug & DEBUG_UNCOLLECTABLE)
21237db96d56Sopenharmony_ci            message = "gc: %zd uncollectable objects at " \
21247db96d56Sopenharmony_ci                "shutdown";
21257db96d56Sopenharmony_ci        else
21267db96d56Sopenharmony_ci            message = "gc: %zd uncollectable objects at " \
21277db96d56Sopenharmony_ci                "shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them";
21287db96d56Sopenharmony_ci        /* PyErr_WarnFormat does too many things and we are at shutdown,
21297db96d56Sopenharmony_ci           the warnings module's dependencies (e.g. linecache) may be gone
21307db96d56Sopenharmony_ci           already. */
21317db96d56Sopenharmony_ci        if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
21327db96d56Sopenharmony_ci                                     "gc", NULL, message,
21337db96d56Sopenharmony_ci                                     PyList_GET_SIZE(gcstate->garbage)))
21347db96d56Sopenharmony_ci            PyErr_WriteUnraisable(NULL);
21357db96d56Sopenharmony_ci        if (gcstate->debug & DEBUG_UNCOLLECTABLE) {
21367db96d56Sopenharmony_ci            PyObject *repr = NULL, *bytes = NULL;
21377db96d56Sopenharmony_ci            repr = PyObject_Repr(gcstate->garbage);
21387db96d56Sopenharmony_ci            if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr)))
21397db96d56Sopenharmony_ci                PyErr_WriteUnraisable(gcstate->garbage);
21407db96d56Sopenharmony_ci            else {
21417db96d56Sopenharmony_ci                PySys_WriteStderr(
21427db96d56Sopenharmony_ci                    "      %s\n",
21437db96d56Sopenharmony_ci                    PyBytes_AS_STRING(bytes)
21447db96d56Sopenharmony_ci                    );
21457db96d56Sopenharmony_ci            }
21467db96d56Sopenharmony_ci            Py_XDECREF(repr);
21477db96d56Sopenharmony_ci            Py_XDECREF(bytes);
21487db96d56Sopenharmony_ci        }
21497db96d56Sopenharmony_ci    }
21507db96d56Sopenharmony_ci}
21517db96d56Sopenharmony_ci
21527db96d56Sopenharmony_ci
21537db96d56Sopenharmony_cistatic void
21547db96d56Sopenharmony_cigc_fini_untrack(PyGC_Head *list)
21557db96d56Sopenharmony_ci{
21567db96d56Sopenharmony_ci    PyGC_Head *gc;
21577db96d56Sopenharmony_ci    for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) {
21587db96d56Sopenharmony_ci        PyObject *op = FROM_GC(gc);
21597db96d56Sopenharmony_ci        _PyObject_GC_UNTRACK(op);
21607db96d56Sopenharmony_ci        // gh-92036: If a deallocator function expect the object to be tracked
21617db96d56Sopenharmony_ci        // by the GC (ex: func_dealloc()), it can crash if called on an object
21627db96d56Sopenharmony_ci        // which is no longer tracked by the GC. Leak one strong reference on
21637db96d56Sopenharmony_ci        // purpose so the object is never deleted and its deallocator is not
21647db96d56Sopenharmony_ci        // called.
21657db96d56Sopenharmony_ci        Py_INCREF(op);
21667db96d56Sopenharmony_ci    }
21677db96d56Sopenharmony_ci}
21687db96d56Sopenharmony_ci
21697db96d56Sopenharmony_ci
21707db96d56Sopenharmony_civoid
21717db96d56Sopenharmony_ci_PyGC_Fini(PyInterpreterState *interp)
21727db96d56Sopenharmony_ci{
21737db96d56Sopenharmony_ci    GCState *gcstate = &interp->gc;
21747db96d56Sopenharmony_ci    Py_CLEAR(gcstate->garbage);
21757db96d56Sopenharmony_ci    Py_CLEAR(gcstate->callbacks);
21767db96d56Sopenharmony_ci
21777db96d56Sopenharmony_ci    if (!_Py_IsMainInterpreter(interp)) {
21787db96d56Sopenharmony_ci        // bpo-46070: Explicitly untrack all objects currently tracked by the
21797db96d56Sopenharmony_ci        // GC. Otherwise, if an object is used later by another interpreter,
21807db96d56Sopenharmony_ci        // calling PyObject_GC_UnTrack() on the object crashs if the previous
21817db96d56Sopenharmony_ci        // or the next object of the PyGC_Head structure became a dangling
21827db96d56Sopenharmony_ci        // pointer.
21837db96d56Sopenharmony_ci        for (int i = 0; i < NUM_GENERATIONS; i++) {
21847db96d56Sopenharmony_ci            PyGC_Head *gen = GEN_HEAD(gcstate, i);
21857db96d56Sopenharmony_ci            gc_fini_untrack(gen);
21867db96d56Sopenharmony_ci        }
21877db96d56Sopenharmony_ci    }
21887db96d56Sopenharmony_ci}
21897db96d56Sopenharmony_ci
21907db96d56Sopenharmony_ci/* for debugging */
21917db96d56Sopenharmony_civoid
21927db96d56Sopenharmony_ci_PyGC_Dump(PyGC_Head *g)
21937db96d56Sopenharmony_ci{
21947db96d56Sopenharmony_ci    _PyObject_Dump(FROM_GC(g));
21957db96d56Sopenharmony_ci}
21967db96d56Sopenharmony_ci
21977db96d56Sopenharmony_ci
21987db96d56Sopenharmony_ci#ifdef Py_DEBUG
21997db96d56Sopenharmony_cistatic int
22007db96d56Sopenharmony_civisit_validate(PyObject *op, void *parent_raw)
22017db96d56Sopenharmony_ci{
22027db96d56Sopenharmony_ci    PyObject *parent = _PyObject_CAST(parent_raw);
22037db96d56Sopenharmony_ci    if (_PyObject_IsFreed(op)) {
22047db96d56Sopenharmony_ci        _PyObject_ASSERT_FAILED_MSG(parent,
22057db96d56Sopenharmony_ci                                    "PyObject_GC_Track() object is not valid");
22067db96d56Sopenharmony_ci    }
22077db96d56Sopenharmony_ci    return 0;
22087db96d56Sopenharmony_ci}
22097db96d56Sopenharmony_ci#endif
22107db96d56Sopenharmony_ci
22117db96d56Sopenharmony_ci
22127db96d56Sopenharmony_ci/* extension modules might be compiled with GC support so these
22137db96d56Sopenharmony_ci   functions must always be available */
22147db96d56Sopenharmony_ci
22157db96d56Sopenharmony_civoid
22167db96d56Sopenharmony_ciPyObject_GC_Track(void *op_raw)
22177db96d56Sopenharmony_ci{
22187db96d56Sopenharmony_ci    PyObject *op = _PyObject_CAST(op_raw);
22197db96d56Sopenharmony_ci    if (_PyObject_GC_IS_TRACKED(op)) {
22207db96d56Sopenharmony_ci        _PyObject_ASSERT_FAILED_MSG(op,
22217db96d56Sopenharmony_ci                                    "object already tracked "
22227db96d56Sopenharmony_ci                                    "by the garbage collector");
22237db96d56Sopenharmony_ci    }
22247db96d56Sopenharmony_ci    _PyObject_GC_TRACK(op);
22257db96d56Sopenharmony_ci
22267db96d56Sopenharmony_ci#ifdef Py_DEBUG
22277db96d56Sopenharmony_ci    /* Check that the object is valid: validate objects traversed
22287db96d56Sopenharmony_ci       by tp_traverse() */
22297db96d56Sopenharmony_ci    traverseproc traverse = Py_TYPE(op)->tp_traverse;
22307db96d56Sopenharmony_ci    (void)traverse(op, visit_validate, op);
22317db96d56Sopenharmony_ci#endif
22327db96d56Sopenharmony_ci}
22337db96d56Sopenharmony_ci
22347db96d56Sopenharmony_civoid
22357db96d56Sopenharmony_ciPyObject_GC_UnTrack(void *op_raw)
22367db96d56Sopenharmony_ci{
22377db96d56Sopenharmony_ci    PyObject *op = _PyObject_CAST(op_raw);
22387db96d56Sopenharmony_ci    /* Obscure:  the Py_TRASHCAN mechanism requires that we be able to
22397db96d56Sopenharmony_ci     * call PyObject_GC_UnTrack twice on an object.
22407db96d56Sopenharmony_ci     */
22417db96d56Sopenharmony_ci    if (_PyObject_GC_IS_TRACKED(op)) {
22427db96d56Sopenharmony_ci        _PyObject_GC_UNTRACK(op);
22437db96d56Sopenharmony_ci    }
22447db96d56Sopenharmony_ci}
22457db96d56Sopenharmony_ci
22467db96d56Sopenharmony_ciint
22477db96d56Sopenharmony_ciPyObject_IS_GC(PyObject *obj)
22487db96d56Sopenharmony_ci{
22497db96d56Sopenharmony_ci    return _PyObject_IS_GC(obj);
22507db96d56Sopenharmony_ci}
22517db96d56Sopenharmony_ci
22527db96d56Sopenharmony_civoid
22537db96d56Sopenharmony_ci_PyObject_GC_Link(PyObject *op)
22547db96d56Sopenharmony_ci{
22557db96d56Sopenharmony_ci    PyGC_Head *g = AS_GC(op);
22567db96d56Sopenharmony_ci    assert(((uintptr_t)g & (sizeof(uintptr_t)-1)) == 0);  // g must be correctly aligned
22577db96d56Sopenharmony_ci
22587db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
22597db96d56Sopenharmony_ci    GCState *gcstate = &tstate->interp->gc;
22607db96d56Sopenharmony_ci    g->_gc_next = 0;
22617db96d56Sopenharmony_ci    g->_gc_prev = 0;
22627db96d56Sopenharmony_ci    gcstate->generations[0].count++; /* number of allocated GC objects */
22637db96d56Sopenharmony_ci    if (gcstate->generations[0].count > gcstate->generations[0].threshold &&
22647db96d56Sopenharmony_ci        gcstate->enabled &&
22657db96d56Sopenharmony_ci        gcstate->generations[0].threshold &&
22667db96d56Sopenharmony_ci        !gcstate->collecting &&
22677db96d56Sopenharmony_ci        !_PyErr_Occurred(tstate))
22687db96d56Sopenharmony_ci    {
22697db96d56Sopenharmony_ci        gcstate->collecting = 1;
22707db96d56Sopenharmony_ci        gc_collect_generations(tstate);
22717db96d56Sopenharmony_ci        gcstate->collecting = 0;
22727db96d56Sopenharmony_ci    }
22737db96d56Sopenharmony_ci}
22747db96d56Sopenharmony_ci
22757db96d56Sopenharmony_cistatic PyObject *
22767db96d56Sopenharmony_cigc_alloc(size_t basicsize, size_t presize)
22777db96d56Sopenharmony_ci{
22787db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
22797db96d56Sopenharmony_ci    if (basicsize > PY_SSIZE_T_MAX - presize) {
22807db96d56Sopenharmony_ci        return _PyErr_NoMemory(tstate);
22817db96d56Sopenharmony_ci    }
22827db96d56Sopenharmony_ci    size_t size = presize + basicsize;
22837db96d56Sopenharmony_ci    char *mem = PyObject_Malloc(size);
22847db96d56Sopenharmony_ci    if (mem == NULL) {
22857db96d56Sopenharmony_ci        return _PyErr_NoMemory(tstate);
22867db96d56Sopenharmony_ci    }
22877db96d56Sopenharmony_ci    ((PyObject **)mem)[0] = NULL;
22887db96d56Sopenharmony_ci    ((PyObject **)mem)[1] = NULL;
22897db96d56Sopenharmony_ci    PyObject *op = (PyObject *)(mem + presize);
22907db96d56Sopenharmony_ci    _PyObject_GC_Link(op);
22917db96d56Sopenharmony_ci    return op;
22927db96d56Sopenharmony_ci}
22937db96d56Sopenharmony_ci
22947db96d56Sopenharmony_ciPyObject *
22957db96d56Sopenharmony_ci_PyObject_GC_New(PyTypeObject *tp)
22967db96d56Sopenharmony_ci{
22977db96d56Sopenharmony_ci    size_t presize = _PyType_PreHeaderSize(tp);
22987db96d56Sopenharmony_ci    PyObject *op = gc_alloc(_PyObject_SIZE(tp), presize);
22997db96d56Sopenharmony_ci    if (op == NULL) {
23007db96d56Sopenharmony_ci        return NULL;
23017db96d56Sopenharmony_ci    }
23027db96d56Sopenharmony_ci    _PyObject_Init(op, tp);
23037db96d56Sopenharmony_ci    return op;
23047db96d56Sopenharmony_ci}
23057db96d56Sopenharmony_ci
23067db96d56Sopenharmony_ciPyVarObject *
23077db96d56Sopenharmony_ci_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
23087db96d56Sopenharmony_ci{
23097db96d56Sopenharmony_ci    size_t size;
23107db96d56Sopenharmony_ci    PyVarObject *op;
23117db96d56Sopenharmony_ci
23127db96d56Sopenharmony_ci    if (nitems < 0) {
23137db96d56Sopenharmony_ci        PyErr_BadInternalCall();
23147db96d56Sopenharmony_ci        return NULL;
23157db96d56Sopenharmony_ci    }
23167db96d56Sopenharmony_ci    size_t presize = _PyType_PreHeaderSize(tp);
23177db96d56Sopenharmony_ci    size = _PyObject_VAR_SIZE(tp, nitems);
23187db96d56Sopenharmony_ci    op = (PyVarObject *)gc_alloc(size, presize);
23197db96d56Sopenharmony_ci    if (op == NULL) {
23207db96d56Sopenharmony_ci        return NULL;
23217db96d56Sopenharmony_ci    }
23227db96d56Sopenharmony_ci    _PyObject_InitVar(op, tp, nitems);
23237db96d56Sopenharmony_ci    return op;
23247db96d56Sopenharmony_ci}
23257db96d56Sopenharmony_ci
23267db96d56Sopenharmony_ciPyVarObject *
23277db96d56Sopenharmony_ci_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems)
23287db96d56Sopenharmony_ci{
23297db96d56Sopenharmony_ci    const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems);
23307db96d56Sopenharmony_ci    _PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op));
23317db96d56Sopenharmony_ci    if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) {
23327db96d56Sopenharmony_ci        return (PyVarObject *)PyErr_NoMemory();
23337db96d56Sopenharmony_ci    }
23347db96d56Sopenharmony_ci
23357db96d56Sopenharmony_ci    PyGC_Head *g = AS_GC(op);
23367db96d56Sopenharmony_ci    g = (PyGC_Head *)PyObject_Realloc(g,  sizeof(PyGC_Head) + basicsize);
23377db96d56Sopenharmony_ci    if (g == NULL)
23387db96d56Sopenharmony_ci        return (PyVarObject *)PyErr_NoMemory();
23397db96d56Sopenharmony_ci    op = (PyVarObject *) FROM_GC(g);
23407db96d56Sopenharmony_ci    Py_SET_SIZE(op, nitems);
23417db96d56Sopenharmony_ci    return op;
23427db96d56Sopenharmony_ci}
23437db96d56Sopenharmony_ci
23447db96d56Sopenharmony_civoid
23457db96d56Sopenharmony_ciPyObject_GC_Del(void *op)
23467db96d56Sopenharmony_ci{
23477db96d56Sopenharmony_ci    size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type);
23487db96d56Sopenharmony_ci    PyGC_Head *g = AS_GC(op);
23497db96d56Sopenharmony_ci    if (_PyObject_GC_IS_TRACKED(op)) {
23507db96d56Sopenharmony_ci#ifdef Py_DEBUG
23517db96d56Sopenharmony_ci        if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
23527db96d56Sopenharmony_ci                                     "gc", NULL, "Object of type %s is not untracked before destruction",
23537db96d56Sopenharmony_ci                                     ((PyObject*)op)->ob_type->tp_name)) {
23547db96d56Sopenharmony_ci            PyErr_WriteUnraisable(NULL);
23557db96d56Sopenharmony_ci        }
23567db96d56Sopenharmony_ci#endif
23577db96d56Sopenharmony_ci        gc_list_remove(g);
23587db96d56Sopenharmony_ci    }
23597db96d56Sopenharmony_ci    GCState *gcstate = get_gc_state();
23607db96d56Sopenharmony_ci    if (gcstate->generations[0].count > 0) {
23617db96d56Sopenharmony_ci        gcstate->generations[0].count--;
23627db96d56Sopenharmony_ci    }
23637db96d56Sopenharmony_ci    PyObject_Free(((char *)op)-presize);
23647db96d56Sopenharmony_ci}
23657db96d56Sopenharmony_ci
23667db96d56Sopenharmony_ciint
23677db96d56Sopenharmony_ciPyObject_GC_IsTracked(PyObject* obj)
23687db96d56Sopenharmony_ci{
23697db96d56Sopenharmony_ci    if (_PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)) {
23707db96d56Sopenharmony_ci        return 1;
23717db96d56Sopenharmony_ci    }
23727db96d56Sopenharmony_ci    return 0;
23737db96d56Sopenharmony_ci}
23747db96d56Sopenharmony_ci
23757db96d56Sopenharmony_ciint
23767db96d56Sopenharmony_ciPyObject_GC_IsFinalized(PyObject *obj)
23777db96d56Sopenharmony_ci{
23787db96d56Sopenharmony_ci    if (_PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(AS_GC(obj))) {
23797db96d56Sopenharmony_ci         return 1;
23807db96d56Sopenharmony_ci    }
23817db96d56Sopenharmony_ci    return 0;
23827db96d56Sopenharmony_ci}
2383