Skip to content
2 changes: 1 addition & 1 deletion Doc/c-api/structures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ the definition of all other Python objects.

This macro is used to access the :attr:`ob_refcnt` member of a Python
object.
It expands to::
It might expand to::

(((PyObject*)(o))->ob_refcnt)

Expand Down
57 changes: 38 additions & 19 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ whose size is determined when the object is allocated.

#define PyObject_HEAD_INIT(type) \
{ _PyObject_EXTRA_INIT \
1, type },
0, type },

#define PyVarObject_HEAD_INIT(type, size) \
{ PyObject_HEAD_INIT(type) size },
Expand All @@ -134,7 +134,7 @@ whose size is determined when the object is allocated.
*/
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
Py_ssize_t *ob_refcnt_ptr;
struct _typeobject *ob_type;
} PyObject;

Expand All @@ -143,7 +143,17 @@ typedef struct {
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
/* API Functions for allocating the refcount. */
void _PyRefcount_New(PyObject *);
void _PyRefcount_Del(PyObject *);

/* Read-only access to the refcount (for most uses). */
#define Py_REFCNT(ob) ((const Py_ssize_t)*(((PyObject*)(ob))->ob_refcnt_ptr))
/* Read-write access to the refcount (without checking pointer validity). */
#define _Py_REFCNT(ob) (*((PyObject*)(ob))->ob_refcnt_ptr)
/* Assignment to refcount, without checking pointer validity. */
#define Py_SET_REFCNT(ob, val) (_Py_REFCNT(ob) = (val))

#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)

Expand Down Expand Up @@ -737,17 +747,18 @@ you can count such references to the type object.)
* e.g, defining _Py_NewReference five different times in a maze of nested
* #ifdefs (we used to do that -- it was impenetrable).
*/
PyAPI_FUNC(PyObject *) _PyDict_Dummy(void);

#ifdef Py_REF_DEBUG
PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
PyAPI_FUNC(void) _Py_NegativeRefcount(const char *fname,
int lineno, PyObject *op);
PyAPI_FUNC(PyObject *) _PyDict_Dummy(void);
PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
#define _Py_INC_REFTOTAL _Py_RefTotal++
#define _Py_DEC_REFTOTAL _Py_RefTotal--
#define _Py_REF_DEBUG_COMMA ,
#define _Py_CHECK_REFCNT(OP) \
{ if (((PyObject*)OP)->ob_refcnt < 0) \
{ if (Py_REFCNT((PyObject*)OP) < 0) \
_Py_NegativeRefcount(__FILE__, __LINE__, \
(PyObject *)(OP)); \
}
Expand Down Expand Up @@ -794,9 +805,11 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force);
#define _Py_NewReference(op) ( \
_Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
Py_REFCNT(op) = 1)
_PyRefcount_New(op))

#define _Py_ForgetReference(op) _Py_INC_TPFREES(op)
#define _Py_ForgetReference(op) ( \
_Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \
_PyRefcount_Del(op))

#ifdef Py_LIMITED_API
PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
Expand All @@ -807,14 +820,20 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
#endif
#endif /* !Py_TRACE_REFS */

/* For PyModuleDefs and other objects that are statically initialized,
* allocate the refcount iff it isn't already allocated. Can't do this in
* the general case as the object may consist of uninitialized memory. */
#define _Py_MaybeNewReference(op) ( \
((PyObject *)(op))->ob_refcnt_ptr == NULL ? _Py_NewReference(op) : 0)

#ifdef PY_TIME_REFCOUNTS

Py_LOCAL_INLINE(int) __py_incref__(PyObject *o) {
uint64_t start, delta;
py_time_refcounts_t *t = PyState_GetThisThreadPyTimeRefcounts();
_Py_INC_REFTOTAL;
start = fast_get_cycles();
ATOMIC_INC(&o->ob_refcnt);
ATOMIC_INC(&_Py_REFCNT(o));
delta = fast_get_cycles() - start;
PY_TIME_FETCH_AND_ADD(t, total_refcount_time, delta);
PY_TIME_FETCH_AND_ADD(t, total_refcounts, 1);
Expand All @@ -826,7 +845,7 @@ Py_LOCAL_INLINE(void) __py_decref__(PyObject *o) {
py_time_refcounts_t *t = PyState_GetThisThreadPyTimeRefcounts();
_Py_DEC_REFTOTAL;
start = fast_get_cycles();
new_rc = ATOMIC_DEC(&(o->ob_refcnt), 1);
new_rc = ATOMIC_DEC(&_Py_REFCNT(o), 1);
delta = fast_get_cycles() - start;
PY_TIME_FETCH_AND_ADD(t, total_refcount_time, delta);
PY_TIME_FETCH_AND_ADD(t, total_refcounts, 1);
Expand All @@ -846,16 +865,16 @@ Py_LOCAL_INLINE(void) __py_decref__(PyObject *o) {

#define Py_INCREF(op) ( \
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
ATOMIC_INC(&(((PyObject *)(op))->ob_refcnt)) )

#define Py_DECREF(op) \
do { \
PyObject *_py_decref_tmp = (PyObject *)(op); \
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
ATOMIC_DEC(&(_py_decref_tmp->ob_refcnt)) != 0) \
_Py_CHECK_REFCNT(_py_decref_tmp) \
else \
_Py_Dealloc(_py_decref_tmp); \
ATOMIC_INC(&_Py_REFCNT(op)))

#define Py_DECREF(op) \
do { \
PyObject *_py_decref_tmp = (PyObject *)(op); \
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
ATOMIC_DEC(&_Py_REFCNT(_py_decref_tmp)) != 0) \
_Py_CHECK_REFCNT(_py_decref_tmp) \
else \
_Py_Dealloc(_py_decref_tmp); \
} while (0)

#endif /* PY_TIME_REFCOUNTS */
Expand Down
2 changes: 1 addition & 1 deletion Modules/_functoolsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ functools_reduce(PyObject *self, PyObject *args)
for (;;) {
PyObject *op2;

if (args->ob_refcnt > 1) {
if (Py_REFCNT(args) > 1) {
Py_DECREF(args);
if ((args = PyTuple_New(2)) == NULL)
goto Fail;
Expand Down
2 changes: 2 additions & 0 deletions Modules/_testbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2836,10 +2836,12 @@ PyInit__testbuffer(void)
return NULL;

Py_TYPE(&NDArray_Type) = &PyType_Type;
PyType_Ready(&NDArray_Type);
Py_INCREF(&NDArray_Type);
PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type);

Py_TYPE(&StaticArray_Type) = &PyType_Type;
PyType_Ready(&StaticArray_Type);
Py_INCREF(&StaticArray_Type);
PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type);

Expand Down
13 changes: 7 additions & 6 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2710,8 +2710,8 @@ slot_tp_del(PyObject *self)
PyObject *error_type, *error_value, *error_traceback;

/* Temporarily resurrect the object. */
assert(self->ob_refcnt == 0);
self->ob_refcnt = 1;
assert(Py_REFCNT(self) == 0);
_Py_REFCNT(self) = 1;

/* Save the current exception, if any. */
PyErr_Fetch(&error_type, &error_value, &error_traceback);
Expand All @@ -2733,17 +2733,17 @@ slot_tp_del(PyObject *self)
/* Undo the temporary resurrection; can't use DECREF here, it would
* cause a recursive call.
*/
assert(self->ob_refcnt > 0);
if (--self->ob_refcnt == 0)
assert(Py_REFCNT(self) > 0);
if (--_Py_REFCNT(self) == 0)
return; /* this is the normal path out */

/* __del__ resurrected it! Make it look like the original Py_DECREF
* never happened.
*/
{
Py_ssize_t refcnt = self->ob_refcnt;
Py_ssize_t refcnt = Py_REFCNT(self);
_Py_NewReference(self);
self->ob_refcnt = refcnt;
_Py_REFCNT(self) = refcnt;
}
assert(!PyType_IS_GC(Py_TYPE(self)) ||
_Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
Expand Down Expand Up @@ -4088,6 +4088,7 @@ PyInit__testcapi(void)
Py_TYPE(&_HashInheritanceTester_Type)=&PyType_Type;

Py_TYPE(&test_structmembersType)=&PyType_Type;
PyType_Ready(&test_structmembersType);
Py_INCREF(&test_structmembersType);
/* don't use a name starting with "test", since we don't want
test_capi to automatically call this */
Expand Down
5 changes: 3 additions & 2 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4146,7 +4146,7 @@ sock_dealloc(PySocketSockObject *s)
if (s->sock_fd != -1) {
PyObject *exc, *val, *tb;
Py_ssize_t old_refcount = Py_REFCNT(s);
++Py_REFCNT(s);
++_Py_REFCNT(s);
PyErr_Fetch(&exc, &val, &tb);
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
"unclosed %R", s))
Expand All @@ -4155,7 +4155,7 @@ sock_dealloc(PySocketSockObject *s)
PyErr_WriteUnraisable((PyObject *) s);
PyErr_Restore(exc, val, tb);
(void) SOCKETCLOSE(s->sock_fd);
Py_REFCNT(s) = old_refcount;
_Py_REFCNT(s) = old_refcount;
}
Py_TYPE(s)->tp_free((PyObject *)s);
}
Expand Down Expand Up @@ -6088,6 +6088,7 @@ PyInit__socket(void)
#endif

Py_TYPE(&sock_type) = &PyType_Type;
PyType_Ready(&sock_type);
m = PyModule_Create(&socketmodule);
if (m == NULL)
return NULL;
Expand Down
1 change: 1 addition & 0 deletions Modules/unicodedata.c
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ PyInit_unicodedata(void)
PyObject *m, *v;

Py_TYPE(&UCD_Type) = &PyType_Type;
PyType_Ready(&UCD_Type);

m = PyModule_Create(&unicodedatamodule);
if (!m)
Expand Down
6 changes: 2 additions & 4 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,11 @@ static PyObject _dummy_struct;

#define dummy (&_dummy_struct)

#ifdef Py_REF_DEBUG
PyObject *
_PyDict_Dummy(void)
{
return dummy;
}
#endif

/* forward declarations */
static PyDictKeyEntry *lookdict(PyDictObject *mp, PyObject *key,
Expand Down Expand Up @@ -3450,7 +3448,7 @@ static PyObject *dictiter_iternextitem(dictiterobject *di)
if (i > mask)
goto fail;

if (result->ob_refcnt == 1) {
if (Py_REFCNT(result) == 1) {
Py_INCREF(result);
Py_DECREF(PyTuple_GET_ITEM(result, 0));
Py_DECREF(PyTuple_GET_ITEM(result, 1));
Expand Down Expand Up @@ -4240,6 +4238,6 @@ static PyTypeObject PyDictDummy_Type = {

static PyObject _dummy_struct = {
_PyObject_EXTRA_INIT
2, &PyDictDummy_Type
NULL, &PyDictDummy_Type
};

4 changes: 2 additions & 2 deletions Objects/enumobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ enum_next_long(enumobject *en, PyObject* next_item)
return NULL;
en->en_longindex = stepped_up;

if (result->ob_refcnt == 1) {
if (Py_REFCNT(result) == 1) {
Py_INCREF(result);
Py_DECREF(PyTuple_GET_ITEM(result, 0));
Py_DECREF(PyTuple_GET_ITEM(result, 1));
Expand Down Expand Up @@ -141,7 +141,7 @@ enum_next(enumobject *en)
}
en->en_index++;

if (result->ob_refcnt == 1) {
if (Py_REFCNT(result) == 1) {
Py_INCREF(result);
Py_DECREF(PyTuple_GET_ITEM(result, 0));
Py_DECREF(PyTuple_GET_ITEM(result, 1));
Expand Down
2 changes: 1 addition & 1 deletion Objects/fileobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ PyFile_GetLine(PyObject *f, int n)
"EOF when reading a line");
}
else if (s[len-1] == '\n') {
if (result->ob_refcnt == 1)
if (Py_REFCNT(result) == 1)
_PyBytes_Resize(&result, len-1);
else {
PyObject *v;
Expand Down
2 changes: 1 addition & 1 deletion Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5361,7 +5361,7 @@ _PyLong_Init(void)
/* _Py_NewReference sets the ref count to 1 but
* the ref count might be larger. Set the refcnt
* to the original refcnt + 1 */
Py_REFCNT(op) = refcnt + 1;
Py_SET_REFCNT(op, refcnt + 1);
assert(Py_SIZE(op) == size);
assert(v->ob_digit[0] == (digit)abs(ival));
}
Expand Down
2 changes: 1 addition & 1 deletion Objects/moduleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ PyModuleDef_Init(struct PyModuleDef* def)
{
if (PyType_Ready(&PyModuleDef_Type) < 0)
return NULL;
_Py_MaybeNewReference(def);
if (def->m_base.m_index == 0) {
max_module_number++;
Py_REFCNT(def) = 1;
Py_TYPE(def) = &PyModuleDef_Type;
def->m_base.m_index = max_module_number;
}
Expand Down
Loading