summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2022-07-26 23:26:43 (GMT)
committerGitHub <noreply@github.com>2022-07-26 23:26:43 (GMT)
commit47e75a0025529fa538bc24d55b27ae4823d3df9d (patch)
tree9b95e72bfa40ba54e1da3dd216f297a6e870984d /Objects
parent7ac5bb3e6a1cf780aea8164fdba09db993a21d6f (diff)
downloadcpython-47e75a0025529fa538bc24d55b27ae4823d3df9d.zip
cpython-47e75a0025529fa538bc24d55b27ae4823d3df9d.tar.gz
cpython-47e75a0025529fa538bc24d55b27ae4823d3df9d.tar.bz2
gh-94673: Add Per-Interpreter Storage for Static Builtin Types (#95255)
This is the last precursor to storing tp_subclasses (and tp_weaklist) on the interpreter state for static builtin types. Here we add per-type storage on PyInterpreterState, but only for the static builtin types. This involves the following: * add PyInterpreterState.types * move PyInterpreterState.type_cache to it * add a "num_builtins_initialized" field * add a "builtins" field (a static array big enough for all the static builtin types) * add _PyStaticType_GetState() to look up a static builtin type's state * (temporarily) add PyTypeObject.tp_static_builtin_index (to hold the type's index into PyInterpreterState.types.builtins) We will be eliminating tp_static_builtin_index in a later change.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c111
1 files changed, 106 insertions, 5 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index f9e6f63..9eb2390 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -67,6 +67,88 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value);
static inline PyTypeObject * subclass_from_ref(PyObject *ref);
+
+/* helpers for for static builtin types */
+
+static inline int
+static_builtin_index_is_set(PyTypeObject *self)
+{
+ return self->tp_static_builtin_index > 0;
+}
+
+static inline size_t
+static_builtin_index_get(PyTypeObject *self)
+{
+ assert(static_builtin_index_is_set(self));
+ /* We store a 1-based index so 0 can mean "not initialized". */
+ return self->tp_static_builtin_index - 1;
+}
+
+static inline void
+static_builtin_index_set(PyTypeObject *self, size_t index)
+{
+ assert(index < _Py_MAX_STATIC_BUILTIN_TYPES);
+ /* We store a 1-based index so 0 can mean "not initialized". */
+ self->tp_static_builtin_index = index + 1;
+}
+
+static inline void
+static_builtin_index_clear(PyTypeObject *self)
+{
+ self->tp_static_builtin_index = 0;
+}
+
+static inline static_builtin_state *
+static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self)
+{
+ return &(interp->types.builtins[static_builtin_index_get(self)]);
+}
+
+/* For static types we store some state in an array on each interpreter. */
+static_builtin_state *
+_PyStaticType_GetState(PyTypeObject *self)
+{
+ assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ return static_builtin_state_get(interp, self);
+}
+
+static void
+static_builtin_state_init(PyTypeObject *self)
+{
+ /* Set the type's per-interpreter state. */
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+
+ /* It should only be called once for each builtin type. */
+ assert(!static_builtin_index_is_set(self));
+
+ static_builtin_index_set(self, interp->types.num_builtins_initialized);
+ interp->types.num_builtins_initialized++;
+
+ static_builtin_state *state = static_builtin_state_get(interp, self);
+ state->type = self;
+}
+
+static void
+static_builtin_state_clear(PyTypeObject *self)
+{
+ /* Reset the type's per-interpreter state.
+ This basically undoes what static_builtin_state_init() did. */
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+
+ static_builtin_state *state = static_builtin_state_get(interp, self);
+ state->type = NULL;
+ static_builtin_index_clear(self);
+
+ assert(interp->types.num_builtins_initialized > 0);
+ interp->types.num_builtins_initialized--;
+}
+
+// Also see _PyStaticType_InitBuiltin() and _PyStaticType_Dealloc().
+
+/* end static builtin helpers */
+
+
/*
* finds the beginning of the docstring's introspection signature.
* if present, returns a pointer pointing to the first '('.
@@ -206,7 +288,7 @@ static struct type_cache*
get_type_cache(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
- return &interp->type_cache;
+ return &interp->types.type_cache;
}
@@ -225,7 +307,7 @@ type_cache_clear(struct type_cache *cache, PyObject *value)
void
_PyType_InitCache(PyInterpreterState *interp)
{
- struct type_cache *cache = &interp->type_cache;
+ struct type_cache *cache = &interp->types.type_cache;
for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
struct type_cache_entry *entry = &cache->hashtable[i];
assert(entry->name == NULL);
@@ -242,7 +324,7 @@ _PyType_InitCache(PyInterpreterState *interp)
static unsigned int
_PyType_ClearCache(PyInterpreterState *interp)
{
- struct type_cache *cache = &interp->type_cache;
+ struct type_cache *cache = &interp->types.type_cache;
#if MCACHE_STATS
size_t total = cache->hits + cache->collisions + cache->misses;
fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n",
@@ -274,11 +356,17 @@ PyType_ClearCache(void)
void
_PyTypes_Fini(PyInterpreterState *interp)
{
- struct type_cache *cache = &interp->type_cache;
+ struct type_cache *cache = &interp->types.type_cache;
type_cache_clear(cache, NULL);
if (_Py_IsMainInterpreter(interp)) {
clear_slotdefs();
}
+
+ assert(interp->types.num_builtins_initialized == 0);
+ // All the static builtin types should have been finalized already.
+ for (size_t i = 0; i < _Py_MAX_STATIC_BUILTIN_TYPES; i++) {
+ assert(interp->types.builtins[i].type == NULL);
+ }
}
@@ -4247,6 +4335,8 @@ clear_static_tp_subclasses(PyTypeObject *type)
void
_PyStaticType_Dealloc(PyTypeObject *type)
{
+ assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE));
+
type_dealloc_common(type);
Py_CLEAR(type->tp_dict);
@@ -4261,6 +4351,11 @@ _PyStaticType_Dealloc(PyTypeObject *type)
}
type->tp_flags &= ~Py_TPFLAGS_READY;
+
+ if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
+ static_builtin_state_clear(type);
+ /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */
+ }
}
@@ -6679,7 +6774,13 @@ _PyStaticType_InitBuiltin(PyTypeObject *self)
{
self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN;
- return PyType_Ready(self);
+ static_builtin_state_init(self);
+
+ int res = PyType_Ready(self);
+ if (res < 0) {
+ static_builtin_state_clear(self);
+ }
+ return res;
}