Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
pycore_gc.h379 linesDownload Raw Back to internal
1#ifndef Py_INTERNAL_GC_H2#define Py_INTERNAL_GC_H3#ifdef __cplusplus4extern "C" {5#endif6 7#ifndef Py_BUILD_CORE8#  error "this header requires Py_BUILD_CORE define"9#endif10 11#include "pycore_interp_structs.h" // PyGC_Head12#include "pycore_pystate.h"       // _PyInterpreterState_GET()13#include "pycore_typedefs.h"      // _PyInterpreterFrame14 15 16/* Get an object's GC head */17static inline PyGC_Head* _Py_AS_GC(PyObject *op) {18    char *gc = ((char*)op) - sizeof(PyGC_Head);19    return (PyGC_Head*)gc;20}21 22/* Get the object given the GC head */23static inline PyObject* _Py_FROM_GC(PyGC_Head *gc) {24    char *op = ((char *)gc) + sizeof(PyGC_Head);25    return (PyObject *)op;26}27 28 29/* Bit flags for ob_gc_bits (in Py_GIL_DISABLED builds)30 *31 * Setting the bits requires a relaxed store. The per-object lock must also be32 * held, except when the object is only visible to a single thread (e.g. during33 * object initialization or destruction).34 *35 * Reading the bits requires using a relaxed load, but does not require holding36 * the per-object lock.37 */38#ifdef Py_GIL_DISABLED39#  define _PyGC_BITS_TRACKED        (1<<0)     // Tracked by the GC40#  define _PyGC_BITS_FINALIZED      (1<<1)     // tp_finalize was called41#  define _PyGC_BITS_UNREACHABLE    (1<<2)42#  define _PyGC_BITS_FROZEN         (1<<3)43#  define _PyGC_BITS_SHARED         (1<<4)44#  define _PyGC_BITS_ALIVE          (1<<5)    // Reachable from a known root.45#  define _PyGC_BITS_DEFERRED       (1<<6)    // Use deferred reference counting46#endif47 48#ifdef Py_GIL_DISABLED49 50static inline void51_PyObject_SET_GC_BITS(PyObject *op, uint8_t new_bits)52{53    uint8_t bits = _Py_atomic_load_uint8_relaxed(&op->ob_gc_bits);54    _Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, bits | new_bits);55}56 57static inline int58_PyObject_HAS_GC_BITS(PyObject *op, uint8_t bits)59{60    return (_Py_atomic_load_uint8_relaxed(&op->ob_gc_bits) & bits) != 0;61}62 63static inline void64_PyObject_CLEAR_GC_BITS(PyObject *op, uint8_t bits_to_clear)65{66    uint8_t bits = _Py_atomic_load_uint8_relaxed(&op->ob_gc_bits);67    _Py_atomic_store_uint8_relaxed(&op->ob_gc_bits, bits & ~bits_to_clear);68}69 70#endif71 72/* True if the object is currently tracked by the GC. */73static inline int _PyObject_GC_IS_TRACKED(PyObject *op) {74#ifdef Py_GIL_DISABLED75    return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_TRACKED);76#else77    PyGC_Head *gc = _Py_AS_GC(op);78    return (gc->_gc_next != 0);79#endif80}81#define _PyObject_GC_IS_TRACKED(op) _PyObject_GC_IS_TRACKED(_Py_CAST(PyObject*, op))82 83/* True if the object may be tracked by the GC in the future, or already is.84   This can be useful to implement some optimizations. */85static inline int _PyObject_GC_MAY_BE_TRACKED(PyObject *obj) {86    if (!PyObject_IS_GC(obj)) {87        return 0;88    }89    if (PyTuple_CheckExact(obj)) {90        return _PyObject_GC_IS_TRACKED(obj);91    }92    return 1;93}94 95#ifdef Py_GIL_DISABLED96 97/* True if memory the object references is shared between98 * multiple threads and needs special purpose when freeing99 * those references due to the possibility of in-flight100 * lock-free reads occurring.  The object is responsible101 * for calling _PyMem_FreeDelayed on the referenced102 * memory. */103static inline int _PyObject_GC_IS_SHARED(PyObject *op) {104    return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_SHARED);105}106#define _PyObject_GC_IS_SHARED(op) _PyObject_GC_IS_SHARED(_Py_CAST(PyObject*, op))107 108static inline void _PyObject_GC_SET_SHARED(PyObject *op) {109    _PyObject_SET_GC_BITS(op, _PyGC_BITS_SHARED);110}111#define _PyObject_GC_SET_SHARED(op) _PyObject_GC_SET_SHARED(_Py_CAST(PyObject*, op))112 113#endif114 115/* Bit flags for _gc_prev */116/* Bit 0 is set when tp_finalize is called */117#define _PyGC_PREV_MASK_FINALIZED  ((uintptr_t)1)118/* Bit 1 is set when the object is in generation which is GCed currently. */119#define _PyGC_PREV_MASK_COLLECTING ((uintptr_t)2)120 121/* Bit 0 in _gc_next is the old space bit.122 * It is set as follows:123 * Young: gcstate->visited_space124 * old[0]: 0125 * old[1]: 1126 * permanent: 0127 *128 * During a collection all objects handled should have the bit set to129 * gcstate->visited_space, as objects are moved from the young gen130 * and the increment into old[gcstate->visited_space].131 * When object are moved from the pending space, old[gcstate->visited_space^1]132 * into the increment, the old space bit is flipped.133*/134#define _PyGC_NEXT_MASK_OLD_SPACE_1    1135 136#define _PyGC_PREV_SHIFT           2137#define _PyGC_PREV_MASK            (((uintptr_t) -1) << _PyGC_PREV_SHIFT)138 139/* set for debugging information */140#define _PyGC_DEBUG_STATS             (1<<0) /* print collection statistics */141#define _PyGC_DEBUG_COLLECTABLE       (1<<1) /* print collectable objects */142#define _PyGC_DEBUG_UNCOLLECTABLE     (1<<2) /* print uncollectable objects */143#define _PyGC_DEBUG_SAVEALL           (1<<5) /* save all garbage in gc.garbage */144#define _PyGC_DEBUG_LEAK              _PyGC_DEBUG_COLLECTABLE | \145                                      _PyGC_DEBUG_UNCOLLECTABLE | \146                                      _PyGC_DEBUG_SAVEALL147 148typedef enum {149    // GC was triggered by heap allocation150    _Py_GC_REASON_HEAP,151 152    // GC was called during shutdown153    _Py_GC_REASON_SHUTDOWN,154 155    // GC was called by gc.collect() or PyGC_Collect()156    _Py_GC_REASON_MANUAL157} _PyGC_Reason;158 159// Lowest bit of _gc_next is used for flags only in GC.160// But it is always 0 for normal code.161static inline PyGC_Head* _PyGCHead_NEXT(PyGC_Head *gc) {162    uintptr_t next = gc->_gc_next & _PyGC_PREV_MASK;163    return (PyGC_Head*)next;164}165static inline void _PyGCHead_SET_NEXT(PyGC_Head *gc, PyGC_Head *next) {166    uintptr_t unext = (uintptr_t)next;167    assert((unext & ~_PyGC_PREV_MASK) == 0);168    gc->_gc_next = (gc->_gc_next & ~_PyGC_PREV_MASK) | unext;169}170 171// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.172static inline PyGC_Head* _PyGCHead_PREV(PyGC_Head *gc) {173    uintptr_t prev = (gc->_gc_prev & _PyGC_PREV_MASK);174    return (PyGC_Head*)prev;175}176 177static inline void _PyGCHead_SET_PREV(PyGC_Head *gc, PyGC_Head *prev) {178    uintptr_t uprev = (uintptr_t)prev;179    assert((uprev & ~_PyGC_PREV_MASK) == 0);180    gc->_gc_prev = ((gc->_gc_prev & ~_PyGC_PREV_MASK) | uprev);181}182 183static inline int _PyGC_FINALIZED(PyObject *op) {184#ifdef Py_GIL_DISABLED185    return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_FINALIZED);186#else187    PyGC_Head *gc = _Py_AS_GC(op);188    return ((gc->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0);189#endif190}191static inline void _PyGC_SET_FINALIZED(PyObject *op) {192#ifdef Py_GIL_DISABLED193    _PyObject_SET_GC_BITS(op, _PyGC_BITS_FINALIZED);194#else195    PyGC_Head *gc = _Py_AS_GC(op);196    gc->_gc_prev |= _PyGC_PREV_MASK_FINALIZED;197#endif198}199static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) {200#ifdef Py_GIL_DISABLED201    _PyObject_CLEAR_GC_BITS(op, _PyGC_BITS_FINALIZED);202#else203    PyGC_Head *gc = _Py_AS_GC(op);204    gc->_gc_prev &= ~_PyGC_PREV_MASK_FINALIZED;205#endif206}207 208extern void _Py_ScheduleGC(PyThreadState *tstate);209 210#ifndef Py_GIL_DISABLED211extern void _Py_TriggerGC(struct _gc_runtime_state *gcstate);212#endif213 214 215/* Tell the GC to track this object.216 *217 * The object must not be tracked by the GC.218 *219 * NB: While the object is tracked by the collector, it must be safe to call the220 * ob_traverse method.221 *222 * Internal note: interp->gc.generation0->_gc_prev doesn't have any bit flags223 * because it's not object header.  So we don't use _PyGCHead_PREV() and224 * _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations.225 *226 * See also the public PyObject_GC_Track() function.227 */228static inline void _PyObject_GC_TRACK(229// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined230#ifndef NDEBUG231    const char *filename, int lineno,232#endif233    PyObject *op)234{235    _PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op),236                          "object already tracked by the garbage collector",237                          filename, lineno, __func__);238#ifdef Py_GIL_DISABLED239    _PyObject_SET_GC_BITS(op, _PyGC_BITS_TRACKED);240#else241    PyGC_Head *gc = _Py_AS_GC(op);242    _PyObject_ASSERT_FROM(op,243                          (gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0,244                          "object is in generation which is garbage collected",245                          filename, lineno, __func__);246 247    struct _gc_runtime_state *gcstate = &_PyInterpreterState_GET()->gc;248    PyGC_Head *generation0 = &gcstate->young.head;249    PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev);250    _PyGCHead_SET_NEXT(last, gc);251    _PyGCHead_SET_PREV(gc, last);252    uintptr_t not_visited = 1 ^ gcstate->visited_space;253    gc->_gc_next = ((uintptr_t)generation0) | not_visited;254    generation0->_gc_prev = (uintptr_t)gc;255    gcstate->young.count++; /* number of tracked GC objects */256    gcstate->heap_size++;257    if (gcstate->young.count > gcstate->young.threshold) {258        _Py_TriggerGC(gcstate);259    }260#endif261}262 263/* Tell the GC to stop tracking this object.264 *265 * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING266 * must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept.267 *268 * The object must be tracked by the GC.269 *270 * See also the public PyObject_GC_UnTrack() which accept an object which is271 * not tracked.272 */273static inline void _PyObject_GC_UNTRACK(274// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined275#ifndef NDEBUG276    const char *filename, int lineno,277#endif278    PyObject *op)279{280    _PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op),281                          "object not tracked by the garbage collector",282                          filename, lineno, __func__);283 284#ifdef Py_GIL_DISABLED285    _PyObject_CLEAR_GC_BITS(op, _PyGC_BITS_TRACKED);286#else287    PyGC_Head *gc = _Py_AS_GC(op);288    PyGC_Head *prev = _PyGCHead_PREV(gc);289    PyGC_Head *next = _PyGCHead_NEXT(gc);290    _PyGCHead_SET_NEXT(prev, next);291    _PyGCHead_SET_PREV(next, prev);292    gc->_gc_next = 0;293    gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED;294    struct _gc_runtime_state *gcstate = &_PyInterpreterState_GET()->gc;295    if (gcstate->young.count > 0) {296        gcstate->young.count--;297    }298    gcstate->heap_size--;299#endif300}301 302 303 304/*305   NOTE: about untracking of mutable objects.306 307   Certain types of container cannot participate in a reference cycle, and308   so do not need to be tracked by the garbage collector. Untracking these309   objects reduces the cost of garbage collections. However, determining310   which objects may be untracked is not free, and the costs must be311   weighed against the benefits for garbage collection.312 313   There are two possible strategies for when to untrack a container:314 315   i) When the container is created.316   ii) When the container is examined by the garbage collector.317 318   Tuples containing only immutable objects (integers, strings etc, and319   recursively, tuples of immutable objects) do not need to be tracked.320   The interpreter creates a large number of tuples, many of which will321   not survive until garbage collection. It is therefore not worthwhile322   to untrack eligible tuples at creation time.323 324   Instead, all tuples except the empty tuple are tracked when created.325   During garbage collection it is determined whether any surviving tuples326   can be untracked. A tuple can be untracked if all of its contents are327   already not tracked. Tuples are examined for untracking in all garbage328   collection cycles. It may take more than one cycle to untrack a tuple.329 330   Dictionaries containing only immutable objects also do not need to be331   tracked. Dictionaries are untracked when created. If a tracked item is332   inserted into a dictionary (either as a key or value), the dictionary333   becomes tracked. During a full garbage collection (all generations),334   the collector will untrack any dictionaries whose contents are not335   tracked.336 337   The module provides the python function is_tracked(obj), which returns338   the CURRENT tracking status of the object. Subsequent garbage339   collections may change the tracking status of the object.340 341   Untracking of certain containers was introduced in issue #4688, and342   the algorithm was refined in response to issue #14775.343*/344 345extern void _PyGC_InitState(struct _gc_runtime_state *);346 347extern Py_ssize_t _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason);348extern void _PyGC_CollectNoFail(PyThreadState *tstate);349 350/* Freeze objects tracked by the GC and ignore them in future collections. */351extern void _PyGC_Freeze(PyInterpreterState *interp);352/* Unfreezes objects placing them in the oldest generation */353extern void _PyGC_Unfreeze(PyInterpreterState *interp);354/* Number of frozen objects */355extern Py_ssize_t _PyGC_GetFreezeCount(PyInterpreterState *interp);356 357extern PyObject *_PyGC_GetObjects(PyInterpreterState *interp, int generation);358extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs);359 360// Functions to clear types free lists361extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp);362extern void _Py_RunGC(PyThreadState *tstate);363 364union _PyStackRef;365 366// GC visit callback for tracked interpreter frames367extern int _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg);368extern int _PyGC_VisitStackRef(union _PyStackRef *ref, visitproc visit, void *arg);369 370#ifdef Py_GIL_DISABLED371extern void _PyGC_VisitObjectsWorldStopped(PyInterpreterState *interp,372                                           gcvisitobjects_t callback, void *arg);373#endif374 375#ifdef __cplusplus376}377#endif378#endif /* !Py_INTERNAL_GC_H */379 
codekingpro/portable-devtools · Team Ai