Skip to content

gh-102304: Consolidate Direct Usage of _Py_RefTotal #102514

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
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#endif

PyAPI_FUNC(void) _Py_NewReference(PyObject *op);
PyAPI_FUNC(void) _Py_NewReferenceNoTotal(PyObject *op);

#ifdef Py_TRACE_REFS
/* Py_TRACE_REFS is such major surgery that we call external routines. */
Expand Down
23 changes: 20 additions & 3 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,23 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
#define _Py_FatalRefcountError(message) \
_Py_FatalRefcountErrorFunc(__func__, (message))


#ifdef Py_REF_DEBUG
/* The symbol is only exposed in the API for the sake of extensions
built against the pre-3.12 stable ABI. */
PyAPI_DATA(Py_ssize_t) _Py_RefTotal;

extern void _Py_AddRefTotal(Py_ssize_t);
extern void _Py_IncRefTotal(void);
extern void _Py_DecRefTotal(void);
# define _Py_DEC_REFTOTAL() _Py_RefTotal--
#endif

// Increment reference count by n
static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
{
#ifdef Py_REF_DEBUG
_Py_RefTotal += n;
_Py_AddRefTotal(n);
#endif
op->ob_refcnt += n;
}
Expand All @@ -52,7 +64,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
{
_Py_DECREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
_Py_DEC_REFTOTAL();
#endif
if (--op->ob_refcnt != 0) {
assert(op->ob_refcnt > 0);
Expand All @@ -70,7 +82,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
{
_Py_DECREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
_Py_DEC_REFTOTAL();
#endif
op->ob_refcnt--;
#ifdef Py_DEBUG
Expand All @@ -80,6 +92,11 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
#endif
}

#ifdef Py_REF_DEBUG
# undef _Py_DEC_REFTOTAL
#endif


PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type);
PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content);

Expand Down
25 changes: 21 additions & 4 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,21 @@ you can count such references to the type object.)
*/

#ifdef Py_REF_DEBUG
PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
# if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030A0000
extern Py_ssize_t _Py_RefTotal;
# define _Py_INC_REFTOTAL() _Py_RefTotal++
# define _Py_DEC_REFTOTAL() _Py_RefTotal--
# elif defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
extern void _Py_IncRefTotal(void);
extern void _Py_DecRefTotal(void);
# define _Py_INC_REFTOTAL() _Py_IncRefTotal()
# define _Py_DEC_REFTOTAL() _Py_DecRefTotal()
# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000
extern void _Py_IncRefTotal_DO_NOT_USE_THIS(void);
extern void _Py_DecRefTotal_DO_NOT_USE_THIS(void);
# define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS()
# define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS()
# endif
PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno,
PyObject *op);
#endif /* Py_REF_DEBUG */
Expand Down Expand Up @@ -519,8 +533,8 @@ static inline void Py_INCREF(PyObject *op)
// Non-limited C API and limited C API for Python 3.9 and older access
// directly PyObject.ob_refcnt.
#ifdef Py_REF_DEBUG
_Py_RefTotal++;
#endif
_Py_INC_REFTOTAL();
#endif // Py_REF_DEBUG
op->ob_refcnt++;
#endif
}
Expand All @@ -539,7 +553,7 @@ static inline void Py_DECREF(PyObject *op) {
static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
{
_Py_DECREF_STAT_INC();
_Py_RefTotal--;
_Py_DEC_REFTOTAL();
if (--op->ob_refcnt != 0) {
if (op->ob_refcnt < 0) {
_Py_NegativeRefcount(filename, lineno, op);
Expand All @@ -564,6 +578,9 @@ static inline void Py_DECREF(PyObject *op)
#define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op))
#endif

#undef _Py_INC_REFTOTAL
#undef _Py_DEC_REFTOTAL


/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear
* and tp_dealloc implementations.
Expand Down
7 changes: 1 addition & 6 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1654,15 +1654,10 @@ slot_tp_del(PyObject *self)
*/
{
Py_ssize_t refcnt = Py_REFCNT(self);
_Py_NewReference(self);
_Py_NewReferenceNoTotal(self);
Py_SET_REFCNT(self, refcnt);
}
assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self));
/* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased
_Py_RefTotal, so we need to undo that. */
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
#endif
}

static PyObject *
Expand Down
9 changes: 4 additions & 5 deletions Objects/bytesobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3060,21 +3060,20 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
Py_DECREF(v);
return 0;
}
/* XXX UNREF/NEWREF interface should be more symmetrical */
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
#endif
#ifdef Py_TRACE_REFS
_Py_ForgetReference(v);
#endif
*pv = (PyObject *)
PyObject_Realloc(v, PyBytesObject_SIZE + newsize);
if (*pv == NULL) {
#ifdef Py_REF_DEBUG
_Py_DecRefTotal();
#endif
PyObject_Free(v);
PyErr_NoMemory();
return -1;
}
_Py_NewReference(*pv);
_Py_NewReferenceNoTotal(*pv);
sv = (PyBytesObject *) *pv;
Py_SET_SIZE(sv, newsize);
sv->ob_sval[newsize] = '\0';
Expand Down
10 changes: 5 additions & 5 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ static inline void
dictkeys_incref(PyDictKeysObject *dk)
{
#ifdef Py_REF_DEBUG
_Py_RefTotal++;
_Py_IncRefTotal();
#endif
dk->dk_refcnt++;
}
Expand All @@ -313,7 +313,7 @@ dictkeys_decref(PyDictKeysObject *dk)
{
assert(dk->dk_refcnt > 0);
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
_Py_DecRefTotal();
#endif
if (--dk->dk_refcnt == 0) {
free_keys_object(dk);
Expand Down Expand Up @@ -633,7 +633,7 @@ new_keys_object(uint8_t log2_size, bool unicode)
}
}
#ifdef Py_REF_DEBUG
_Py_RefTotal++;
_Py_IncRefTotal();
#endif
dk->dk_refcnt = 1;
dk->dk_log2_size = log2_size;
Expand Down Expand Up @@ -821,7 +821,7 @@ clone_combined_dict_keys(PyDictObject *orig)
we have it now; calling dictkeys_incref would be an error as
keys->dk_refcnt is already set to 1 (after memcpy). */
#ifdef Py_REF_DEBUG
_Py_RefTotal++;
_Py_IncRefTotal();
#endif
return keys;
}
Expand Down Expand Up @@ -1520,7 +1520,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode)
// We can not use free_keys_object here because key's reference
// are moved already.
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
_Py_DecRefTotal();
#endif
if (oldkeys == Py_EMPTY_KEYS) {
oldkeys->dk_refcnt--;
Expand Down
79 changes: 68 additions & 11 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ _PyObject_CheckConsistency(PyObject *op, int check_content)
#ifdef Py_REF_DEBUG
Py_ssize_t _Py_RefTotal;

static inline void
reftotal_increment(void)
{
_Py_RefTotal++;
}

static inline void
reftotal_decrement(void)
{
_Py_RefTotal--;
}

void
_Py_AddRefTotal(Py_ssize_t n)
{
_Py_RefTotal += n;
}

Py_ssize_t
_Py_GetRefTotal(void)
{
Expand Down Expand Up @@ -121,6 +139,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op)
filename, lineno, __func__);
}

/* This is exposed strictly for use in Py_INCREF(). */
PyAPI_FUNC(void)
_Py_IncRefTotal_DO_NOT_USE_THIS(void)
{
reftotal_increment();
}

/* This is exposed strictly for use in Py_DECREF(). */
PyAPI_FUNC(void)
_Py_DecRefTotal_DO_NOT_USE_THIS(void)
{
reftotal_decrement();
}

void
_Py_IncRefTotal(void)
{
reftotal_increment();
}

void
_Py_DecRefTotal(void)
{
reftotal_decrement();
}

#endif /* Py_REF_DEBUG */

void
Expand All @@ -138,12 +182,18 @@ Py_DecRef(PyObject *o)
void
_Py_IncRef(PyObject *o)
{
#ifdef Py_REF_DEBUG
reftotal_increment();
#endif
Py_INCREF(o);
}

void
_Py_DecRef(PyObject *o)
{
#ifdef Py_REF_DEBUG
reftotal_decrement();
#endif
Py_DECREF(o);
}

Expand Down Expand Up @@ -238,17 +288,12 @@ PyObject_CallFinalizerFromDealloc(PyObject *self)
/* tp_finalize resurrected it! Make it look like the original Py_DECREF
* never happened. */
Py_ssize_t refcnt = Py_REFCNT(self);
_Py_NewReference(self);
_Py_NewReferenceNoTotal(self);
Py_SET_REFCNT(self, refcnt);

_PyObject_ASSERT(self,
(!_PyType_IS_GC(Py_TYPE(self))
|| _PyObject_GC_IS_TRACKED(self)));
/* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased
_Py_RefTotal, so we need to undo that. */
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
#endif
return -1;
}

Expand Down Expand Up @@ -2014,21 +2059,33 @@ _PyTypes_FiniTypes(PyInterpreterState *interp)
}


void
_Py_NewReference(PyObject *op)
static inline void
new_reference(PyObject *op)
{
if (_PyRuntime.tracemalloc.config.tracing) {
_PyTraceMalloc_NewReference(op);
}
#ifdef Py_REF_DEBUG
_Py_RefTotal++;
#endif
Py_SET_REFCNT(op, 1);
#ifdef Py_TRACE_REFS
_Py_AddToAllObjects(op, 1);
#endif
}

void
_Py_NewReference(PyObject *op)
{
#ifdef Py_REF_DEBUG
reftotal_increment();
#endif
new_reference(op);
}

void
_Py_NewReferenceNoTotal(PyObject *op)
{
new_reference(op);
}


#ifdef Py_TRACE_REFS
void
Expand Down
2 changes: 1 addition & 1 deletion Objects/structseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ _PyStructSequence_FiniType(PyTypeObject *type)
// Don't use Py_DECREF(): static type must not be deallocated
Py_SET_REFCNT(type, 0);
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
_Py_DecRefTotal();
#endif

// Make sure that _PyStructSequence_InitType() will initialize
Expand Down
9 changes: 4 additions & 5 deletions Objects/tupleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,10 +930,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
return *pv == NULL ? -1 : 0;
}

/* XXX UNREF/NEWREF interface should be more symmetrical */
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
#endif
if (_PyObject_GC_IS_TRACKED(v)) {
_PyObject_GC_UNTRACK(v);
}
Expand All @@ -947,10 +943,13 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
sv = PyObject_GC_Resize(PyTupleObject, v, newsize);
if (sv == NULL) {
*pv = NULL;
#ifdef Py_REF_DEBUG
_Py_DecRefTotal();
#endif
PyObject_GC_Del(v);
return -1;
}
_Py_NewReference((PyObject *) sv);
_Py_NewReferenceNoTotal((PyObject *) sv);
/* Zero out items added by growing */
if (newsize > oldsize)
memset(&sv->ob_item[oldsize], 0,
Expand Down
7 changes: 2 additions & 5 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -947,21 +947,18 @@ resize_compact(PyObject *unicode, Py_ssize_t length)
_PyUnicode_UTF8(unicode) = NULL;
_PyUnicode_UTF8_LENGTH(unicode) = 0;
}
#ifdef Py_REF_DEBUG
_Py_RefTotal--;
#endif
#ifdef Py_TRACE_REFS
_Py_ForgetReference(unicode);
#endif

new_unicode = (PyObject *)PyObject_Realloc(unicode, new_size);
if (new_unicode == NULL) {
_Py_NewReference(unicode);
_Py_NewReferenceNoTotal(unicode);
PyErr_NoMemory();
return NULL;
}
unicode = new_unicode;
_Py_NewReference(unicode);
_Py_NewReferenceNoTotal(unicode);

_PyUnicode_LENGTH(unicode) = length;
#ifdef Py_DEBUG
Expand Down