diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index e9e8add6c1..ad72947695 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -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) diff --git a/Include/object.h b/Include/object.h index 2f6819b71b..191c9e32d2 100644 --- a/Include/object.h +++ b/Include/object.h @@ -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 }, @@ -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; @@ -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) @@ -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)); \ } @@ -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 *); @@ -807,6 +820,12 @@ 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) { @@ -814,7 +833,7 @@ Py_LOCAL_INLINE(int) __py_incref__(PyObject *o) { 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); @@ -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); @@ -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 */ diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 035d3d9c59..05e5d2bb1f 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -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; diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index 13d3cccfa4..8b4da6e608 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -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); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index fbb4aa4674..e21b93b85e 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -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); @@ -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); @@ -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 */ diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 7ab534e07a..c428fd1599 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -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)) @@ -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); } @@ -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; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 7d518fa257..cc076e7e11 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -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) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index d9be08b230..f8fd11e5e4 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -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, @@ -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)); @@ -4240,6 +4238,6 @@ static PyTypeObject PyDictDummy_Type = { static PyObject _dummy_struct = { _PyObject_EXTRA_INIT - 2, &PyDictDummy_Type + NULL, &PyDictDummy_Type }; diff --git a/Objects/enumobject.c b/Objects/enumobject.c index c458cfe73d..3fb1b9a312 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -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)); @@ -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)); diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 234d07e5c6..3623f04085 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -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; diff --git a/Objects/longobject.c b/Objects/longobject.c index d05de8bf07..7f5abbb8e7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -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)); } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index bc9875fe1c..3bec3e5b88 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -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; } diff --git a/Objects/object.c b/Objects/object.c index d3e96d3385..0951f6c3fa 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -3,6 +3,7 @@ #include "Python.h" #include "frameobject.h" +#include #ifdef __cplusplus extern "C" { @@ -27,10 +28,10 @@ _Py_GetRefTotal(void) hash table code is well-tested) */ o = _PyDict_Dummy(); if (o != NULL) - total -= o->ob_refcnt; + total -= Py_REFCNT(o); o = _PySet_Dummy; if (o != NULL) - total -= o->ob_refcnt; + total -= Py_REFCNT(o); return total; } @@ -215,7 +216,7 @@ _Py_NegativeRefcount(const char *fname, int lineno, PyObject *op) PyOS_snprintf(buf, sizeof(buf), "%s:%i object at %p has negative ref count " "%" PY_FORMAT_SIZE_T "d", - fname, lineno, op, op->ob_refcnt); + fname, lineno, op, Py_REFCNT(op)); Py_FatalError(buf); } @@ -302,27 +303,27 @@ PyObject_CallFinalizerFromDealloc(PyObject *self) Py_ssize_t refcnt; /* Temporarily resurrect the object. */ - if (self->ob_refcnt != 0) { + if (Py_REFCNT(self) != 0) { Py_FatalError("PyObject_CallFinalizerFromDealloc called on " "object with a non-zero refcount"); } - self->ob_refcnt = 1; + Py_SET_REFCNT(self, 1); PyObject_CallFinalizer(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 0; /* this is the normal path out */ /* tp_finalize resurrected it! Make it look like the original Py_DECREF * never happened. */ - refcnt = self->ob_refcnt; + refcnt = Py_REFCNT(self); _Py_NewReference(self); - self->ob_refcnt = refcnt; + Py_SET_REFCNT(self, refcnt); if (PyType_IS_GC(Py_TYPE(self))) { assert(_PyGC_REFS(self) != _PyGC_REFS_UNTRACKED); @@ -362,12 +363,12 @@ PyObject_Print(PyObject *op, FILE *fp, int flags) Py_END_ALLOW_THREADS } else { - if (op->ob_refcnt <= 0) + if (Py_REFCNT(op) <= 0) /* XXX(twouters) cast refcount to long until %zd is universally available */ Py_BEGIN_ALLOW_THREADS fprintf(fp, "", - (long)op->ob_refcnt, op); + (long)Py_REFCNT(op), op); Py_END_ALLOW_THREADS else { PyObject *s; @@ -449,7 +450,7 @@ _PyObject_Dump(PyObject* op) "refcount: %ld\n" "address : %p\n", Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name, - (long)op->ob_refcnt, + (long)Py_REFCNT(op), op); } } @@ -939,7 +940,7 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) return err; } Py_DECREF(name); - assert(name->ob_refcnt >= 1); + assert(PyObject(name) >= 1); if (tp->tp_getattr == NULL && tp->tp_getattro == NULL) PyErr_Format(PyExc_TypeError, "'%.100s' object has no attributes " @@ -1518,7 +1519,7 @@ PyTypeObject _PyNone_Type = { PyObject _Py_NoneStruct = { _PyObject_EXTRA_INIT - 1, &_PyNone_Type + NULL, &_PyNone_Type }; /* NotImplemented is an object that can be used to signal that an @@ -1603,12 +1604,20 @@ PyTypeObject _PyNotImplemented_Type = { PyObject _Py_NotImplementedStruct = { _PyObject_EXTRA_INIT - 1, &_PyNotImplemented_Type + NULL, &_PyNotImplemented_Type }; void _Py_ReadyTypes(void) { + _Py_NewReference(Py_False); + _Py_NewReference(Py_True); + _Py_NewReference(Py_None); + _Py_NewReference(Py_NotImplemented); + _Py_NewReference(Py_Ellipsis); + _Py_NewReference(_PyDict_Dummy()); + _Py_NewReference(_PySet_Dummy); + if (PyType_Ready(&PyBaseObject_Type) < 0) Py_FatalError("Can't initialize object type"); @@ -1634,11 +1643,23 @@ _Py_ReadyTypes(void) Py_FatalError("Can't initialize bytearray type"); if (PyType_Ready(&PyBytes_Type) < 0) - Py_FatalError("Can't initialize 'str'"); + Py_FatalError("Can't initialize bytes type"); + + if (PyType_Ready(&PyBytesIter_Type) < 0) + Py_FatalError("Can't initialize bytes iterator type"); + + if (PyType_Ready(&PyByteArrayIter_Type) < 0) + Py_FatalError("Can't initialize bytearray iterator type"); if (PyType_Ready(&PyList_Type) < 0) Py_FatalError("Can't initialize list type"); + if (PyType_Ready(&PyListIter_Type) < 0) + Py_FatalError("Can't initialize list iter type"); + + if (PyType_Ready(&PyListRevIter_Type) < 0) + Py_FatalError("Can't initialize list reverse iter type"); + if (PyType_Ready(&_PyNone_Type) < 0) Py_FatalError("Can't initialize None type"); @@ -1654,12 +1675,27 @@ _Py_ReadyTypes(void) if (PyType_Ready(&PyRange_Type) < 0) Py_FatalError("Can't initialize range type"); + if (PyType_Ready(&PyRangeIter_Type) < 0) + Py_FatalError("Can't initialize range iterator type"); + if (PyType_Ready(&PyDict_Type) < 0) Py_FatalError("Can't initialize dict type"); + if (PyType_Ready(&PyDictIterKey_Type) < 0) + Py_FatalError("Can't initialize dict iter key type"); + + if (PyType_Ready(&PyDictIterValue_Type) < 0) + Py_FatalError("Can't initialize dict iter values type"); + + if (PyType_Ready(&PyDictIterItem_Type) < 0) + Py_FatalError("Can't initialize dict iter values type"); + if (PyType_Ready(&PyODict_Type) < 0) Py_FatalError("Can't initialize OrderedDict type"); + if (PyType_Ready(&PyDictIterKey_Type) < 0) + Py_FatalError("Can't initialize dict iter key type"); + if (PyType_Ready(&PyODictKeys_Type) < 0) Py_FatalError("Can't initialize odict_keys type"); @@ -1675,15 +1711,24 @@ _Py_ReadyTypes(void) if (PyType_Ready(&PySet_Type) < 0) Py_FatalError("Can't initialize set type"); + if (PyType_Ready(&PySetIter_Type) < 0) + Py_FatalError("Can't initialize set iterator type"); + if (PyType_Ready(&PyUnicode_Type) < 0) Py_FatalError("Can't initialize str type"); + if (PyType_Ready(&PyUnicodeIter_Type) < 0) + Py_FatalError("Can't initialize str iter type"); + if (PyType_Ready(&PySlice_Type) < 0) Py_FatalError("Can't initialize slice type"); if (PyType_Ready(&PyStaticMethod_Type) < 0) Py_FatalError("Can't initialize static method type"); + if (PyType_Ready(&PyClassMethod_Type) < 0) + Py_FatalError("Can't initialize classmethod type"); + if (PyType_Ready(&PyComplex_Type) < 0) Py_FatalError("Can't initialize complex type"); @@ -1705,6 +1750,9 @@ _Py_ReadyTypes(void) if (PyType_Ready(&PyTuple_Type) < 0) Py_FatalError("Can't initialize tuple type"); + if (PyType_Ready(&PyTupleIter_Type) < 0) + Py_FatalError("Can't initialize tuple iter type"); + if (PyType_Ready(&PyEnum_Type) < 0) Py_FatalError("Can't initialize enumerate type"); @@ -1782,6 +1830,7 @@ _Py_ReadyTypes(void) if (PyType_Ready(&_PyCoroWrapper_Type) < 0) Py_FatalError("Can't initialize coroutine wrapper type"); + } @@ -1791,7 +1840,7 @@ void _Py_NewReference(PyObject *op) { _Py_INC_REFTOTAL; - op->ob_refcnt = 1; + Py_SET_REFCNT(op, 1); _Py_AddToAllObjects(op, 1); _Py_INC_TPALLOCS(op); } @@ -1802,7 +1851,7 @@ _Py_ForgetReference(PyObject *op) #ifdef SLOW_UNREF_CHECK PyObject *p; #endif - if (op->ob_refcnt < 0) + if (Py_REFCNT(op) < 0) Py_FatalError("UNREF negative refcnt"); if (op == &refchain || op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) { @@ -1845,7 +1894,7 @@ _Py_PrintReferences(FILE *fp) PyObject *op; fprintf(fp, "Remaining objects:\n"); for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { - fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] ", op, op->ob_refcnt); + fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] ", op, Py_REFCNT(op)); if (PyObject_Print(op, fp, 0) != 0) PyErr_Clear(); putc('\n', fp); @@ -1862,7 +1911,7 @@ _Py_PrintReferenceAddresses(FILE *fp) fprintf(fp, "Remaining object addresses:\n"); for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] %s\n", op, - op->ob_refcnt, Py_TYPE(op)->tp_name); + Py_REFCNT(op), Py_TYPE(op)->tp_name); } PyObject * @@ -2007,7 +2056,7 @@ _PyTrash_deposit_object(PyObject *op) { assert(PyObject_IS_GC(op)); assert(_PyGC_REFS(op) == _PyGC_REFS_UNTRACKED); - assert(op->ob_refcnt == 0); + assert(Py_REFCNT(op) == 0); _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; _PyTrash_delete_later = op; } @@ -2019,7 +2068,7 @@ _PyTrash_thread_deposit_object(PyObject *op) PyThreadState *tstate = PyThreadState_GET(); assert(PyObject_IS_GC(op)); assert(_PyGC_REFS(op) == _PyGC_REFS_UNTRACKED); - assert(op->ob_refcnt == 0); + assert(Py_REFCNT(op) == 0); _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *) tstate->trash_delete_later; tstate->trash_delete_later = op; } @@ -2043,7 +2092,7 @@ _PyTrash_destroy_chain(void) * assorted non-release builds calling Py_DECREF again ends * up distorting allocation statistics. */ - assert(op->ob_refcnt == 0); + assert(Py_REFCNT(op) == 0); ++_PyTrash_delete_nesting; (*dealloc)(op); --_PyTrash_delete_nesting; @@ -2068,7 +2117,7 @@ _PyTrash_thread_destroy_chain(void) * assorted non-release builds calling Py_DECREF again ends * up distorting allocation statistics. */ - assert(op->ob_refcnt == 0); + assert(Py_REFCNT(op) == 0); ++tstate->trash_delete_nesting; (*dealloc)(op); --tstate->trash_delete_nesting; @@ -2091,3 +2140,73 @@ _Py_Dealloc(PyObject *op) #ifdef __cplusplus } #endif + +/* TODO(twouters): refactor into a separate file */ + +/* Remote refcount management */ + +#define REFCOUNTLINKS_PER_PAGE 32768 +#define LAST_REFCOUNTLINK (REFCOUNTLINKS_PER_PAGE - 1) + +typedef union refcountlink { + Py_ssize_t refcount; + union refcountlink *link; +} refcountlink; + +refcountlink *next_free = NULL; +refcountlink *first_page = NULL; +refcountlink *last_page = NULL; + +static futex_t refcountlinks_lock = FUTEX_STATIC_INIT("refcountlinks lock"); + +static void +alloc_refcount_links(void) +{ + ptrdiff_t diff; + int i; + refcountlink *new_page; + + new_page = PyMem_MALLOC(REFCOUNTLINKS_PER_PAGE * sizeof(refcountlink)); + if (new_page == NULL) { + Py_FatalError("Unable to allocate memory for refcounts"); + } + if (first_page == NULL) + first_page = new_page; + if (last_page != NULL) + last_page[LAST_REFCOUNTLINK].link = new_page; + new_page[0].link = last_page; + last_page = new_page; + diff = &new_page[1] - &new_page[0]; + for (i = 1; i < REFCOUNTLINKS_PER_PAGE - 1; i++) + new_page[i].link = &new_page[i] + diff; + new_page[LAST_REFCOUNTLINK].link = NULL; + next_free = &new_page[1]; +} + +void +_PyRefcount_New(PyObject *ob) +{ + refcountlink *link; + futex_lock(&refcountlinks_lock); + if (next_free == NULL) + alloc_refcount_links(); + if (next_free == NULL) + abort(); + link = next_free; + next_free = link->link; + ob->ob_refcnt_ptr = &(link->refcount); + Py_SET_REFCNT(ob, 1); + futex_unlock(&refcountlinks_lock); +} + +void +_PyRefcount_Del(PyObject *ob) +{ + refcountlink *link = (refcountlink *)ob->ob_refcnt_ptr; + assert(Py_REFCNT(ob) == 0); + ob->ob_refcnt_ptr = NULL; + futex_lock(&refcountlinks_lock); + link->link = next_free; + next_free = link; + futex_unlock(&refcountlinks_lock); +} diff --git a/Objects/setobject.c b/Objects/setobject.c index ae4febba2c..4506e9aa0e 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2619,6 +2619,6 @@ static PyTypeObject _PySetDummy_Type = { static PyObject _dummy_struct = { _PyObject_EXTRA_INIT - 2, &_PySetDummy_Type + NULL, &_PySetDummy_Type }; diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 104952333a..23b83d0aaa 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -87,7 +87,7 @@ PyTypeObject PyEllipsis_Type = { PyObject _Py_EllipsisObject = { _PyObject_EXTRA_INIT - 1, &PyEllipsis_Type + NULL, &PyEllipsis_Type }; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 48d928973b..7a6dd61355 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -177,7 +177,7 @@ int PyTuple_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem) { PyObject **p; - if (!PyTuple_Check(op) || op->ob_refcnt != 1) { + if (!PyTuple_Check(op) || Py_REFCNT(op) != 1) { Py_XDECREF(newitem); PyErr_BadInternalCall(); return -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 46fb27e339..8eef0a6ae6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1095,7 +1095,7 @@ subtype_dealloc(PyObject *self) } if (type->tp_del) { type->tp_del(self); - if (self->ob_refcnt > 0) + if (Py_REFCNT(self) > 0) return; } @@ -1163,7 +1163,7 @@ subtype_dealloc(PyObject *self) if (type->tp_del) { type->tp_del(self); - if (self->ob_refcnt > 0) { + if (Py_REFCNT(self) > 0) { /* Resurrected */ goto endlabel; } @@ -4813,6 +4813,7 @@ PyType_Ready(PyTypeObject *type) assert((type->tp_flags & Py_TPFLAGS_READYING) == 0); type->tp_flags |= Py_TPFLAGS_READYING; + _Py_NewReference(type); #ifdef Py_TRACE_REFS /* PyType_Ready is the closest thing we have to a choke point diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index fb79bd94f6..c80776ad98 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -172,12 +172,12 @@ extern "C" { #endif /* This dictionary holds all interned unicode strings. Note that references - to strings in this dictionary are *not* counted in the string's ob_refcnt. + to strings in this dictionary are *not* counted in the string's refcount. When the interned string reaches a refcnt of 0 the string deallocation function will delete the reference from this dictionary. Another way to look at this is that to say that the actual reference - count of a string is: s->ob_refcnt + (s->state ? 2 : 0) + count of a string is: Py_REFCNT(s) + (s->state ? 2 : 0) */ static PyObject *interned = NULL; @@ -1745,7 +1745,7 @@ unicode_dealloc(PyObject *unicode) case SSTATE_INTERNED_MORTAL: /* revive dead object temporarily for DelItem */ - Py_REFCNT(unicode) = 3; + _Py_REFCNT(unicode) = 3; if (PyDict_DelItem(interned, unicode) != 0) Py_FatalError( "deletion of interned string failed"); @@ -15271,7 +15271,7 @@ PyUnicode_InternInPlace(PyObject **p) PyThreadState_GET()->recursion_critical = 0; /* The two references in interned are not counted by refcnt. The deallocator will take care of this */ - Py_REFCNT(s) -= 2; + _Py_REFCNT(s) -= 2; _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; } @@ -15330,11 +15330,11 @@ _Py_ReleaseInternedUnicodeStrings(void) /* XXX Shouldn't happen */ break; case SSTATE_INTERNED_IMMORTAL: - Py_REFCNT(s) += 1; + _Py_REFCNT(s) += 1; immortal_size += PyUnicode_GET_LENGTH(s); break; case SSTATE_INTERNED_MORTAL: - Py_REFCNT(s) += 2; + _Py_REFCNT(s) += 2; mortal_size += PyUnicode_GET_LENGTH(s); break; default: diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index f42fe3d59d..0d5ba43993 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -886,7 +886,7 @@ PyObject_ClearWeakRefs(PyObject *object) if (object == NULL || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)) - || object->ob_refcnt != 0) { + || Py_REFCNT(object) != 0) { PyErr_BadInternalCall(); return; } @@ -909,7 +909,7 @@ PyObject_ClearWeakRefs(PyObject *object) current->wr_callback = NULL; clear_weakref(current); if (callback != NULL) { - if (((PyObject *)current)->ob_refcnt > 0) + if (Py_REFCNT((PyObject *)current) > 0) handle_callback(current, callback); Py_DECREF(callback); } @@ -927,7 +927,7 @@ PyObject_ClearWeakRefs(PyObject *object) for (i = 0; i < count; ++i) { PyWeakReference *next = current->wr_next; - if (((PyObject *)current)->ob_refcnt > 0) + if (Py_REFCNT((PyObject *)current) > 0) { Py_INCREF(current); PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); diff --git a/Python/pyarena.c b/Python/pyarena.c index 103603fcdf..3bfdf0a980 100644 --- a/Python/pyarena.c +++ b/Python/pyarena.c @@ -169,7 +169,7 @@ PyArena_Free(PyArena *arena) block_free(arena->a_head); /* This property normally holds, except when the code being compiled is sys.getobjects(0), in which case there will be two references. - assert(arena->a_objects->ob_refcnt == 1); + assert(Py_REFCNT(arena->a_objects) == 1); */ Py_DECREF(arena->a_objects); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 702e8f0f9f..5de027c2f0 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1012,7 +1012,7 @@ Return the size of object in bytes."); static PyObject * sys_getrefcount(PyObject *self, PyObject *arg) { - return PyLong_FromSsize_t(arg->ob_refcnt); + return PyLong_FromSsize_t(Py_REFCNT(arg)); } #ifdef Py_REF_DEBUG