Skip to content

Commit

Permalink
pythongh-94673: Clarify About Runtime State Related to Static Builtin…
Browse files Browse the repository at this point in the history
… Types (pythongh-117761)

Guido pointed out to me that some details about the per-interpreter state for the builtin types aren't especially clear.  I'm addressing that by:

* adding a comment explaining that state
* adding some asserts to point out the relationship between each index and the interp/global runtime state
  • Loading branch information
ericsnowcurrently committed Apr 12, 2024
1 parent 30f0643 commit eca5362
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
37 changes: 37 additions & 0 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,43 @@ struct types_state {
unsigned int next_version_tag;

struct type_cache type_cache;

/* Every static builtin type is initialized for each interpreter
during its own initialization, including for the main interpreter
during global runtime initialization. This is done by calling
_PyStaticType_InitBuiltin().
The first time a static builtin type is initialized, all the
normal PyType_Ready() stuff happens. The only difference from
normal is that there are three PyTypeObject fields holding
objects which are stored here (on PyInterpreterState) rather
than in the corresponding PyTypeObject fields. Those are:
tp_dict (cls.__dict__), tp_subclasses (cls.__subclasses__),
and tp_weaklist.
When a subinterpreter is initialized, each static builtin type
is still initialized, but only the interpreter-specific portion,
namely those three objects.
Those objects are stored in the PyInterpreterState.types.builtins
array, at the index corresponding to each specific static builtin
type. That index (a size_t value) is stored in the tp_subclasses
field. For static builtin types, we re-purposed the now-unused
tp_subclasses to avoid adding another field to PyTypeObject.
In all other cases tp_subclasses holds a dict like before.
(The field was previously defined as PyObject*, but is now void*
to reflect its dual use.)
The index for each static builtin type isn't statically assigned.
Instead it is calculated the first time a type is initialized
(by the main interpreter). The index matches the order in which
the type was initialized relative to the others. The actual
value comes from the current value of num_builtins_initialized,
as each type is initialized for the main interpreter.
num_builtins_initialized is incremented once for each static
builtin type. Once initialization is over for a subinterpreter,
the value will be the same as for all other interpreters. */
size_t num_builtins_initialized;
static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
PyMutex mutex;
Expand Down
7 changes: 6 additions & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,14 @@ _PyStaticType_GetState(PyInterpreterState *interp, PyTypeObject *self)
static void
static_builtin_state_init(PyInterpreterState *interp, PyTypeObject *self)
{
if (!static_builtin_index_is_set(self)) {
if (_Py_IsMainInterpreter(interp)) {
assert(!static_builtin_index_is_set(self));
static_builtin_index_set(self, interp->types.num_builtins_initialized);
}
else {
assert(static_builtin_index_get(self) ==
interp->types.num_builtins_initialized);
}
static_builtin_state *state = static_builtin_state_get(interp, self);

/* It should only be called once for each builtin type. */
Expand Down

0 comments on commit eca5362

Please sign in to comment.