Skip to content

bpo-35059: Enhance _PyObject_GC_TRACK() macros #20931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 17, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)


/* Tell the GC to track this object.
*
* The object must not be tracked by the GC.
*
* NB: While the object is tracked by the collector, it must be safe to call the
* ob_traverse method.
Expand All @@ -61,20 +63,24 @@ _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)
* because it's not object header. So we don't use _PyGCHead_PREV() and
* _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations.
*
* The PyObject_GC_Track() function is the public version of this macro.
* See also the public PyObject_GC_Track() function.
*/
static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno,
PyObject *op)
static inline void _PyObject_GC_TRACK(
// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined
#ifndef NDEBUG
const char *filename, int lineno,
#endif
PyObject *op)
{
_PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op),
"object already tracked by the garbage collector",
filename, lineno, "_PyObject_GC_TRACK");
filename, lineno, __func__);

PyGC_Head *gc = _Py_AS_GC(op);
_PyObject_ASSERT_FROM(op,
(gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0,
"object is in generation which is garbage collected",
filename, lineno, "_PyObject_GC_TRACK");
filename, lineno, __func__);

PyThreadState *tstate = _PyThreadState_GET();
PyGC_Head *generation0 = tstate->interp->gc.generation0;
Expand All @@ -85,24 +91,26 @@ static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno,
generation0->_gc_prev = (uintptr_t)gc;
}

#define _PyObject_GC_TRACK(op) \
_PyObject_GC_TRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op))

/* Tell the GC to stop tracking this object.
*
* Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING
* must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept.
*
* The object must be tracked by the GC.
*
* The PyObject_GC_UnTrack() function is the public version of this macro.
* See also the public PyObject_GC_UnTrack() which accept an object which is
* not tracked.
*/
static inline void _PyObject_GC_UNTRACK_impl(const char *filename, int lineno,
PyObject *op)
static inline void _PyObject_GC_UNTRACK(
// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined
#ifndef NDEBUG
const char *filename, int lineno,
#endif
PyObject *op)
{
_PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op),
"object not tracked by the garbage collector",
filename, lineno, "_PyObject_GC_UNTRACK");
filename, lineno, __func__);

PyGC_Head *gc = _Py_AS_GC(op);
PyGC_Head *prev = _PyGCHead_PREV(gc);
Expand All @@ -113,8 +121,20 @@ static inline void _PyObject_GC_UNTRACK_impl(const char *filename, int lineno,
gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED;
}

#define _PyObject_GC_UNTRACK(op) \
_PyObject_GC_UNTRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op))
// Macros to accept any type for the parameter, and to automatically pass
// the filename and the filename (if NDEBUG is not defined) where the macro
// is called.
#ifdef NDEBUG
# define _PyObject_GC_TRACK(op) \
_PyObject_GC_TRACK(_PyObject_CAST(op))
# define _PyObject_GC_UNTRACK(op) \
_PyObject_GC_UNTRACK(_PyObject_CAST(op))
#else
# define _PyObject_GC_TRACK(op) \
_PyObject_GC_TRACK(__FILE__, __LINE__, _PyObject_CAST(op))
# define _PyObject_GC_UNTRACK(op) \
_PyObject_GC_UNTRACK(__FILE__, __LINE__, _PyObject_CAST(op))
#endif

#ifdef Py_REF_DEBUG
extern void _PyDebug_PrintTotalRefs(void);
Expand Down