summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2024-10-23 16:10:06 (GMT)
committerGitHub <noreply@github.com>2024-10-23 16:10:06 (GMT)
commit6f26d496d3c894970ee18a125e9100791ebc2b36 (patch)
tree62999ec30e17bb0334c82ae7137b10a6d64f3e48 /Objects
parentde0d5c6e2e12f24ade1ccc457afaf5fb2c650c64 (diff)
downloadcpython-6f26d496d3c894970ee18a125e9100791ebc2b36.zip
cpython-6f26d496d3c894970ee18a125e9100791ebc2b36.tar.gz
cpython-6f26d496d3c894970ee18a125e9100791ebc2b36.tar.bz2
gh-125286: Share the Main Refchain With Legacy Interpreters (gh-125709)
They used to be shared, before 3.12. Returning to sharing them resolves a failure on Py_TRACE_REFS builds. Co-authored-by: Petr Viktorin <encukou@gmail.com>
Diffstat (limited to 'Objects')
-rw-r--r--Objects/object.c92
-rw-r--r--Objects/unicodeobject.c8
2 files changed, 44 insertions, 56 deletions
diff --git a/Objects/object.c b/Objects/object.c
index 1a15b70..7cc74a8 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -171,6 +171,48 @@ _PyDebug_PrintTotalRefs(void) {
#define REFCHAIN(interp) interp->object_state.refchain
#define REFCHAIN_VALUE ((void*)(uintptr_t)1)
+static inline int
+has_own_refchain(PyInterpreterState *interp)
+{
+ if (interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC) {
+ return (_Py_IsMainInterpreter(interp)
+ || _PyInterpreterState_Main() == NULL);
+ }
+ return 1;
+}
+
+static int
+refchain_init(PyInterpreterState *interp)
+{
+ if (!has_own_refchain(interp)) {
+ // Legacy subinterpreters share a refchain with the main interpreter.
+ REFCHAIN(interp) = REFCHAIN(_PyInterpreterState_Main());
+ return 0;
+ }
+ _Py_hashtable_allocator_t alloc = {
+ // Don't use default PyMem_Malloc() and PyMem_Free() which
+ // require the caller to hold the GIL.
+ .malloc = PyMem_RawMalloc,
+ .free = PyMem_RawFree,
+ };
+ REFCHAIN(interp) = _Py_hashtable_new_full(
+ _Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,
+ NULL, NULL, &alloc);
+ if (REFCHAIN(interp) == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static void
+refchain_fini(PyInterpreterState *interp)
+{
+ if (has_own_refchain(interp) && REFCHAIN(interp) != NULL) {
+ _Py_hashtable_destroy(REFCHAIN(interp));
+ }
+ REFCHAIN(interp) = NULL;
+}
+
bool
_PyRefchain_IsTraced(PyInterpreterState *interp, PyObject *obj)
{
@@ -2191,16 +2233,7 @@ PyStatus
_PyObject_InitState(PyInterpreterState *interp)
{
#ifdef Py_TRACE_REFS
- _Py_hashtable_allocator_t alloc = {
- // Don't use default PyMem_Malloc() and PyMem_Free() which
- // require the caller to hold the GIL.
- .malloc = PyMem_RawMalloc,
- .free = PyMem_RawFree,
- };
- REFCHAIN(interp) = _Py_hashtable_new_full(
- _Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,
- NULL, NULL, &alloc);
- if (REFCHAIN(interp) == NULL) {
+ if (refchain_init(interp) < 0) {
return _PyStatus_NO_MEMORY();
}
#endif
@@ -2211,8 +2244,7 @@ void
_PyObject_FiniState(PyInterpreterState *interp)
{
#ifdef Py_TRACE_REFS
- _Py_hashtable_destroy(REFCHAIN(interp));
- REFCHAIN(interp) = NULL;
+ refchain_fini(interp);
#endif
}
@@ -2501,42 +2533,6 @@ _Py_ResurrectReference(PyObject *op)
#ifdef Py_TRACE_REFS
-/* Make sure the ref is associated with the right interpreter.
- * This only needs special attention for heap-allocated objects
- * that have been immortalized, and only when the object might
- * outlive the interpreter where it was created. That means the
- * object was necessarily created using a global allocator
- * (i.e. from the main interpreter). Thus in that specific case
- * we move the object over to the main interpreter's refchain.
- *
- * This was added for the sake of the immortal interned strings,
- * where legacy subinterpreters share the main interpreter's
- * interned dict (and allocator), and therefore the strings can
- * outlive the subinterpreter.
- *
- * It may make sense to fold this into _Py_SetImmortalUntracked(),
- * but that requires further investigation. In the meantime, it is
- * up to the caller to know if this is needed. There should be
- * very few cases.
- */
-void
-_Py_NormalizeImmortalReference(PyObject *op)
-{
- assert(_Py_IsImmortal(op));
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (!_PyRefchain_IsTraced(interp, op)) {
- return;
- }
- PyInterpreterState *main_interp = _PyInterpreterState_Main();
- if (interp != main_interp
- && interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC)
- {
- assert(!_PyRefchain_IsTraced(main_interp, op));
- _PyRefchain_Remove(interp, op);
- _PyRefchain_Trace(main_interp, op);
- }
-}
-
void
_Py_ForgetReference(PyObject *op)
{
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index b94a74c..9cd9781 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -15444,10 +15444,6 @@ _PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **p)
assert(*p);
}
-#ifdef Py_TRACE_REFS
-extern void _Py_NormalizeImmortalReference(PyObject *);
-#endif
-
static void
immortalize_interned(PyObject *s)
{
@@ -15463,10 +15459,6 @@ immortalize_interned(PyObject *s)
#endif
_PyUnicode_STATE(s).interned = SSTATE_INTERNED_IMMORTAL;
_Py_SetImmortal(s);
-#ifdef Py_TRACE_REFS
- /* Make sure the ref is associated with the right interpreter. */
- _Py_NormalizeImmortalReference(s);
-#endif
}
static /* non-null */ PyObject*