Skip to content

Commit de64e75

Browse files
gh-94673: More Per-Interpreter Fields for Builtin Static Types (gh-103912)
his involves moving tp_dict, tp_bases, and tp_mro to PyInterpreterState, in the same way we did for tp_subclasses. Those three fields are effectively const for builtin static types (unlike tp_subclasses). In theory we only need to make their values immortal, along with their contents. However, that isn't such a simple proposition. (See gh-103823.) In the meantime the simplest solution is to move the fields into the interpreter. One alternative is to statically allocate the values, but that's its own can of worms.
1 parent 872cbc6 commit de64e75

File tree

5 files changed

+185
-86
lines changed

5 files changed

+185
-86
lines changed

Include/internal/pycore_typeobject.h

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ struct type_cache {
4444

4545
typedef struct {
4646
PyTypeObject *type;
47+
int readying;
48+
int ready;
49+
// XXX tp_dict, tp_bases, and tp_mro can probably be statically
50+
// allocated, instead of dynamically and stored on the interpreter.
51+
PyObject *tp_dict;
52+
PyObject *tp_bases;
53+
PyObject *tp_mro;
4754
PyObject *tp_subclasses;
4855
/* We never clean up weakrefs for static builtin types since
4956
they will effectively never get triggered. However, there

Modules/_abc.c

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "pycore_moduleobject.h" // _PyModule_GetState()
88
#include "pycore_object.h" // _PyType_GetSubclasses()
99
#include "pycore_runtime.h" // _Py_ID()
10+
#include "pycore_typeobject.h" // _PyType_GetMRO()
1011
#include "clinic/_abc.c.h"
1112

1213
/*[clinic input]

Modules/gcmodule.c

+3-28
Original file line numberDiff line numberDiff line change
@@ -2174,41 +2174,16 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp)
21742174
}
21752175

21762176

2177-
static void
2178-
gc_fini_untrack(PyGC_Head *list)
2179-
{
2180-
PyGC_Head *gc;
2181-
for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) {
2182-
PyObject *op = FROM_GC(gc);
2183-
_PyObject_GC_UNTRACK(op);
2184-
// gh-92036: If a deallocator function expect the object to be tracked
2185-
// by the GC (ex: func_dealloc()), it can crash if called on an object
2186-
// which is no longer tracked by the GC. Leak one strong reference on
2187-
// purpose so the object is never deleted and its deallocator is not
2188-
// called.
2189-
Py_INCREF(op);
2190-
}
2191-
}
2192-
2193-
21942177
void
21952178
_PyGC_Fini(PyInterpreterState *interp)
21962179
{
21972180
GCState *gcstate = &interp->gc;
21982181
Py_CLEAR(gcstate->garbage);
21992182
Py_CLEAR(gcstate->callbacks);
22002183

2201-
if (!_Py_IsMainInterpreter(interp)) {
2202-
// bpo-46070: Explicitly untrack all objects currently tracked by the
2203-
// GC. Otherwise, if an object is used later by another interpreter,
2204-
// calling PyObject_GC_UnTrack() on the object crashs if the previous
2205-
// or the next object of the PyGC_Head structure became a dangling
2206-
// pointer.
2207-
for (int i = 0; i < NUM_GENERATIONS; i++) {
2208-
PyGC_Head *gen = GEN_HEAD(gcstate, i);
2209-
gc_fini_untrack(gen);
2210-
}
2211-
}
2184+
/* We expect that none of this interpreters objects are shared
2185+
with other interpreters.
2186+
See https://github.com/python/cpython/issues/90228. */
22122187
}
22132188

22142189
/* for debugging */

Objects/structseq.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,6 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
511511
Py_ssize_t n_members = count_members(desc, &n_unnamed_members);
512512
PyMemberDef *members = NULL;
513513

514-
int initialized = 1;
515514
if ((type->tp_flags & Py_TPFLAGS_READY) == 0) {
516515
assert(type->tp_name == NULL);
517516
assert(type->tp_members == NULL);
@@ -524,7 +523,6 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
524523
initialize_static_fields(type, desc, members, tp_flags);
525524

526525
_Py_SetImmortal(type);
527-
initialized = 0;
528526
}
529527
#ifndef NDEBUG
530528
else {
@@ -543,13 +541,10 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
543541
desc->name);
544542
goto error;
545543
}
546-
// This should be dropped if tp_dict is made per-interpreter.
547-
if (initialized) {
548-
return 0;
549-
}
550544

551545
if (initialize_structseq_dict(
552-
desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) {
546+
desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0)
547+
{
553548
goto error;
554549
}
555550

0 commit comments

Comments
 (0)