diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index 4263370861302b..fc74ba28c78c77 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -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. */
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 8796dfe2f6b8cf..ed113032241a75 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -37,6 +37,10 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
#define _Py_FatalRefcountError(message) \
_Py_FatalRefcountErrorFunc(__func__, (message))
+#ifdef Py_REF_DEBUG
+# define _Py_RefTotal (_PyRuntime.object_state.reftotal)
+#endif
+
// Increment reference count by n
static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
{
diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h
new file mode 100644
index 00000000000000..02d90c6381ee45
--- /dev/null
+++ b/Include/internal/pycore_object_state.h
@@ -0,0 +1,21 @@
+#ifndef Py_INTERNAL_OBJECT_H
+#define Py_INTERNAL_OBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+struct _py_object_runtime_state {
+#ifdef Py_REF_DEBUG
+ Py_ssize_t reftotal;
+#endif
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_OBJECT_H */
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index fe2de5feb47ae3..d3ea11a01e633f 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -17,6 +17,7 @@ extern "C" {
#include "pycore_global_objects.h" // struct _Py_global_objects
#include "pycore_import.h" // struct _import_runtime_state
#include "pycore_interp.h" // PyInterpreterState
+#include "pycore_object_state.h" // struct _py_object_runtime_state
#include "pycore_parser.h" // struct _parser_runtime_state
#include "pycore_pymem.h" // struct _pymem_allocators
#include "pycore_pyhash.h" // struct pyhash_runtime_state
@@ -151,6 +152,7 @@ typedef struct pyruntimestate {
void *open_code_userdata;
_Py_AuditHookEntry *audit_hook_head;
+ struct _py_object_runtime_state obj_state;
struct _Py_float_runtime_state float_state;
struct _Py_unicode_runtime_state unicode_state;
struct _Py_dict_runtime_state dict_state;
diff --git a/Include/object.h b/Include/object.h
index 3774f126730005..6152200a316eff 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -490,7 +490,6 @@ you can count such references to the type object.)
*/
#ifdef Py_REF_DEBUG
-PyAPI_DATA(Py_ssize_t) _Py_RefTotal;
PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno,
PyObject *op);
#endif /* Py_REF_DEBUG */
diff --git a/Makefile.pre.in b/Makefile.pre.in
index de42d684f16602..92e31e606e6f0a 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1653,6 +1653,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_moduleobject.h \
$(srcdir)/Include/internal/pycore_namespace.h \
$(srcdir)/Include/internal/pycore_object.h \
+ $(srcdir)/Include/internal/pycore_object_state.h \
$(srcdir)/Include/internal/pycore_obmalloc.h \
$(srcdir)/Include/internal/pycore_obmalloc_init.h \
$(srcdir)/Include/internal/pycore_pathconfig.h \
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 83eef73a875d9d..a465a714a7a8e0 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1643,15 +1643,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 *
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 0fd10fa00d16fa..83147e910528c2 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -3058,21 +3058,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_RefTotal--;
+#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';
diff --git a/Objects/object.c b/Objects/object.c
index 687bd36d2b4af1..68a96e872bbfc6 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -54,8 +54,6 @@ _PyObject_CheckConsistency(PyObject *op, int check_content)
#ifdef Py_REF_DEBUG
-Py_ssize_t _Py_RefTotal;
-
Py_ssize_t
_Py_GetRefTotal(void)
{
@@ -238,17 +236,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;
}
@@ -2001,21 +1994,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
+ _Py_RefTotal++;
+#endif
+ new_reference(op);
+}
+
+void
+_Py_NewReferenceNoTotal(PyObject *op)
+{
+ new_reference(op);
+}
+
#ifdef Py_TRACE_REFS
void
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index e1b9953226c0d7..6e54e777434e36 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -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);
}
@@ -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_RefTotal--;
+#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,
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index b721ccd805edf1..f21b13a9d2fb79 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -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
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 35fbff320f4661..d192677668183e 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -235,6 +235,7 @@
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 19cb5cf1c80735..3c9c6e86e24e39 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -609,6 +609,9 @@
Include\internal
+
+ Include\internal
+
Include\internal