From 784352493ded49f321f399a0b5c2d9db34b1ef5f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 7 Jul 2022 18:40:52 -0600 Subject: [PATCH 01/30] Add PyInterpreterState.types. --- Include/internal/pycore_interp.h | 2 +- Include/internal/pycore_typeobject.h | 5 +++++ Objects/typeobject.c | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 6ce2945cd9fb7b..d71386953a0dd0 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -173,7 +173,7 @@ struct _is { struct _Py_exc_state exc_state; struct ast_state ast; - struct type_cache type_cache; + struct types_state types; struct callable_cache callable_cache; /* The following fields are here to avoid allocation during init. diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 46f3bf78b133ee..887bc6027923f1 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -39,6 +39,11 @@ struct type_cache { #endif }; +struct types_state { + struct type_cache type_cache; +}; + + extern PyStatus _PyTypes_InitSlotDefs(void); extern int _PyStaticType_InitBuiltin(PyTypeObject *type); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f9e6f6372ab4d3..9bba5ede7b20cc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -206,7 +206,7 @@ static struct type_cache* get_type_cache(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); - return &interp->type_cache; + return &interp->types.type_cache; } @@ -225,7 +225,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 +242,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,7 +274,7 @@ 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(); From 09fd0be345d0d75d3409651945c27bf6ebae8539 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 9 Jul 2022 14:48:55 -0600 Subject: [PATCH 02/30] Add PyInterpreterState.types.num_builtins_initialized. --- Include/internal/pycore_typeobject.h | 3 +++ Objects/typeobject.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 887bc6027923f1..05bf40c3a69a80 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -39,8 +39,11 @@ struct type_cache { #endif }; +#define _Py_MAX_STATIC_BUILTIN_TYPES 1000 + struct types_state { struct type_cache type_cache; + ssize_t num_builtins_initialized; }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9bba5ede7b20cc..6c39f8e7a9ed75 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6677,6 +6677,11 @@ PyType_Ready(PyTypeObject *type) int _PyStaticType_InitBuiltin(PyTypeObject *self) { + /* For static types we store them in an array on each interpreter. */ + PyInterpreterState *interp = _PyInterpreterState_GET(); + interp->types.num_builtins_initialized++; + assert(interp->types.num_builtins_initialized < _Py_MAX_STATIC_BUILTIN_TYPES); + self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; return PyType_Ready(self); From afbde1aa31842e50395ef569bee2f6a07c154906 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 18 Jul 2022 16:44:17 -0600 Subject: [PATCH 03/30] Hard-code _Py_NUM_STATIC_BUILTIN_TYPES. --- Include/internal/pycore_typeobject.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 05bf40c3a69a80..928a8519311845 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -39,7 +39,9 @@ struct type_cache { #endif }; -#define _Py_MAX_STATIC_BUILTIN_TYPES 1000 +/* For now we hard-code this to a value for which we are confident + all the static builtin types will fit (for all builds). */ +#define _Py_MAX_STATIC_BUILTIN_TYPES 200 struct types_state { struct type_cache type_cache; From f3aa6496d6cc12aa761906a98dd7496226cb9a93 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 18 Jul 2022 20:09:53 -0600 Subject: [PATCH 04/30] Store per-interpreter state for static builtin types. --- Include/cpython/object.h | 1 + Include/internal/pycore_typeobject.h | 5 +++++ Objects/typeobject.c | 29 +++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 614d6c18ee0b4a..2ee8a203c6952e 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -227,6 +227,7 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + ssize_t tp_static_builtin_index; /* 0 means "not initialized" */ }; /* This struct is used by the specializer diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 928a8519311845..bca696b38f6284 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -43,9 +43,14 @@ struct type_cache { all the static builtin types will fit (for all builds). */ #define _Py_MAX_STATIC_BUILTIN_TYPES 200 +struct builtin_static_type_state { + PyTypeObject *type; +}; + struct types_state { struct type_cache type_cache; ssize_t num_builtins_initialized; + struct builtin_static_type_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES]; }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6c39f8e7a9ed75..b39f9a890f1436 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -67,6 +67,17 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value); static inline PyTypeObject * subclass_from_ref(PyObject *ref); +static inline struct builtin_static_type_state * +lookup_static_builtin_type(PyTypeObject *self) +{ + if (self->tp_static_builtin_index == 0) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &(interp->types.builtins[self->tp_static_builtin_index - 1]); +} + + /* * finds the beginning of the docstring's introspection signature. * if present, returns a pointer pointing to the first '('. @@ -4247,6 +4258,11 @@ clear_static_tp_subclasses(PyTypeObject *type) void _PyStaticType_Dealloc(PyTypeObject *type) { + struct builtin_static_type_state *state = lookup_static_builtin_type(type); + if (state != NULL) { + state->type = NULL; + } + type_dealloc_common(type); Py_CLEAR(type->tp_dict); @@ -6677,11 +6693,22 @@ PyType_Ready(PyTypeObject *type) int _PyStaticType_InitBuiltin(PyTypeObject *self) { - /* For static types we store them in an array on each interpreter. */ + /* It should only be called once for each builtin type. */ + assert(self->tp_static_builtin_index == 0); + + /* For static types we store some state in an array on each interpreter. */ PyInterpreterState *interp = _PyInterpreterState_GET(); interp->types.num_builtins_initialized++; assert(interp->types.num_builtins_initialized < _Py_MAX_STATIC_BUILTIN_TYPES); + /* We use 1-based indexing so 0 can mean "not initialized". */ + self->tp_static_builtin_index = interp->types.num_builtins_initialized; + + /* Now we initialize the type's per-interpreter state. */ + struct builtin_static_type_state *state = lookup_static_builtin_type(self); + assert(state != NULL); + state->type = self; + self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; return PyType_Ready(self); From 9a1cc36e5a39379c8fe7f67659d9d3671ca69bff Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 19 Jul 2022 09:43:34 -0600 Subject: [PATCH 05/30] Export _PyStaticType_GetState(). --- Include/internal/pycore_typeobject.h | 7 ++++--- Objects/typeobject.c | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index bca696b38f6284..26ef070447a6a7 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -43,20 +43,21 @@ struct type_cache { all the static builtin types will fit (for all builds). */ #define _Py_MAX_STATIC_BUILTIN_TYPES 200 -struct builtin_static_type_state { +typedef struct { PyTypeObject *type; -}; +} static_builtin_type_state; struct types_state { struct type_cache type_cache; ssize_t num_builtins_initialized; - struct builtin_static_type_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES]; + static_builtin_type_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES]; }; extern PyStatus _PyTypes_InitSlotDefs(void); extern int _PyStaticType_InitBuiltin(PyTypeObject *type); +extern static_builtin_type_state * _PyStaticType_GetState(PyTypeObject *); extern void _PyStaticType_Dealloc(PyTypeObject *type); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b39f9a890f1436..70b4c4a6fc84e9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -67,8 +67,8 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value); static inline PyTypeObject * subclass_from_ref(PyObject *ref); -static inline struct builtin_static_type_state * -lookup_static_builtin_type(PyTypeObject *self) +static_builtin_type_state * +_PyStaticType_GetState(PyTypeObject *self) { if (self->tp_static_builtin_index == 0) { return NULL; @@ -4258,7 +4258,7 @@ clear_static_tp_subclasses(PyTypeObject *type) void _PyStaticType_Dealloc(PyTypeObject *type) { - struct builtin_static_type_state *state = lookup_static_builtin_type(type); + static_builtin_type_state *state = _PyStaticType_GetState(type); if (state != NULL) { state->type = NULL; } @@ -6705,7 +6705,7 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) self->tp_static_builtin_index = interp->types.num_builtins_initialized; /* Now we initialize the type's per-interpreter state. */ - struct builtin_static_type_state *state = lookup_static_builtin_type(self); + static_builtin_type_state *state = _PyStaticType_GetState(self); assert(state != NULL); state->type = self; From 375b2d9c54a7826ab1e9a1eec4c31c54fd0fa698 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 19 Jul 2022 09:46:02 -0600 Subject: [PATCH 06/30] Move _PyStaticType_GetState() down next to _PyStaticType_InitBuiltin(). --- Objects/typeobject.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 70b4c4a6fc84e9..2d04ba014314a7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -67,17 +67,6 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value); static inline PyTypeObject * subclass_from_ref(PyObject *ref); -static_builtin_type_state * -_PyStaticType_GetState(PyTypeObject *self) -{ - if (self->tp_static_builtin_index == 0) { - return NULL; - } - PyInterpreterState *interp = _PyInterpreterState_GET(); - return &(interp->types.builtins[self->tp_static_builtin_index - 1]); -} - - /* * finds the beginning of the docstring's introspection signature. * if present, returns a pointer pointing to the first '('. @@ -6714,6 +6703,16 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) return PyType_Ready(self); } +static_builtin_type_state * +_PyStaticType_GetState(PyTypeObject *self) +{ + if (self->tp_static_builtin_index == 0) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &(interp->types.builtins[self->tp_static_builtin_index - 1]); +} + static int add_subclass(PyTypeObject *base, PyTypeObject *type) From b0b32a6ce040f5d9250856c46e69f24dd0ee70b0 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 19 Jul 2022 17:19:14 +0000 Subject: [PATCH 07/30] make it compile --- Include/cpython/object.h | 2 +- Include/internal/pycore_typeobject.h | 2 +- Objects/typeobject.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 2ee8a203c6952e..1ca1a576fb2329 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -227,7 +227,7 @@ struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; - ssize_t tp_static_builtin_index; /* 0 means "not initialized" */ + size_t tp_static_builtin_index; /* 0 means "not initialized" */ }; /* This struct is used by the specializer diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 26ef070447a6a7..545e28ac32f5fc 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -49,7 +49,7 @@ typedef struct { struct types_state { struct type_cache type_cache; - ssize_t num_builtins_initialized; + size_t num_builtins_initialized; static_builtin_type_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES]; }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2d04ba014314a7..037ab3eb02709e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4266,6 +4266,8 @@ _PyStaticType_Dealloc(PyTypeObject *type) } type->tp_flags &= ~Py_TPFLAGS_READY; + // Reset tp_static_builtin_index after each finalization. + type->tp_static_builtin_index = 0; } From eb05d9b328824ac1231ea78c9d62c0fa0fee653c Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 19 Jul 2022 18:16:14 +0000 Subject: [PATCH 08/30] fix test_sys --- Lib/test/test_sys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 1dc10d8b0a39ac..f629dd5f034728 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1507,7 +1507,7 @@ def delx(self): del self.__x check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - fmt = 'P2nPI13Pl4Pn9Pn12PIP' + fmt = 'P2nPI13Pl4Pn9Pn12PIPI' s = vsize('2P' + fmt) check(int, s) # class From f5ebd235d5006682a6cb18b6bb5e5ffa34f5a253 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 20 Jul 2022 13:35:31 -0600 Subject: [PATCH 09/30] Reset tp_static_builtin_index only if a static builtin type. --- Objects/typeobject.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 037ab3eb02709e..61c621cdc181f7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4266,8 +4266,12 @@ _PyStaticType_Dealloc(PyTypeObject *type) } type->tp_flags &= ~Py_TPFLAGS_READY; - // Reset tp_static_builtin_index after each finalization. - type->tp_static_builtin_index = 0; + + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + /* Reset the type's per-interpreter state. + This basically undoes what _PyStaticType_InitBuiltin() did. */ + type->tp_static_builtin_index = 0; + } } From d94818bf9a8194ccf36432c394bb5a2ca9cacc48 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 20 Jul 2022 15:28:35 -0600 Subject: [PATCH 10/30] Factor out get_static_builtin_index() and set_static_builtin_index(). --- Objects/typeobject.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 61c621cdc181f7..2b95b12d76dc11 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4244,6 +4244,9 @@ clear_static_tp_subclasses(PyTypeObject *type) Py_CLEAR(type->tp_subclasses); } +static inline size_t get_static_builtin_index(PyTypeObject *); +static inline void set_static_builtin_index(PyTypeObject *, size_t); + void _PyStaticType_Dealloc(PyTypeObject *type) { @@ -4270,7 +4273,7 @@ _PyStaticType_Dealloc(PyTypeObject *type) if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { /* Reset the type's per-interpreter state. This basically undoes what _PyStaticType_InitBuiltin() did. */ - type->tp_static_builtin_index = 0; + set_static_builtin_index(type, 0); } } @@ -6685,11 +6688,24 @@ PyType_Ready(PyTypeObject *type) return 0; } + +static inline size_t +get_static_builtin_index(PyTypeObject *self) +{ + return self->tp_static_builtin_index; +} + +static inline void +set_static_builtin_index(PyTypeObject *self, size_t index) +{ + self->tp_static_builtin_index = index; +} + int _PyStaticType_InitBuiltin(PyTypeObject *self) { /* It should only be called once for each builtin type. */ - assert(self->tp_static_builtin_index == 0); + assert(get_static_builtin_index(self) == 0); /* For static types we store some state in an array on each interpreter. */ PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -6697,7 +6713,7 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) assert(interp->types.num_builtins_initialized < _Py_MAX_STATIC_BUILTIN_TYPES); /* We use 1-based indexing so 0 can mean "not initialized". */ - self->tp_static_builtin_index = interp->types.num_builtins_initialized; + set_static_builtin_index(self, interp->types.num_builtins_initialized); /* Now we initialize the type's per-interpreter state. */ static_builtin_type_state *state = _PyStaticType_GetState(self); @@ -6712,11 +6728,11 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) static_builtin_type_state * _PyStaticType_GetState(PyTypeObject *self) { - if (self->tp_static_builtin_index == 0) { + if (get_static_builtin_index(self) == 0) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); - return &(interp->types.builtins[self->tp_static_builtin_index - 1]); + return &(interp->types.builtins[get_static_builtin_index(self) - 1]); } From 06799d5243f5441153e3a08cad00e0e3fa37cd90 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 20 Jul 2022 18:02:51 -0600 Subject: [PATCH 11/30] Reset state->type later on. --- Objects/typeobject.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2b95b12d76dc11..f58585bf414c6e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4250,11 +4250,6 @@ static inline void set_static_builtin_index(PyTypeObject *, size_t); void _PyStaticType_Dealloc(PyTypeObject *type) { - static_builtin_type_state *state = _PyStaticType_GetState(type); - if (state != NULL) { - state->type = NULL; - } - type_dealloc_common(type); Py_CLEAR(type->tp_dict); @@ -4273,6 +4268,9 @@ _PyStaticType_Dealloc(PyTypeObject *type) if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { /* Reset the type's per-interpreter state. This basically undoes what _PyStaticType_InitBuiltin() did. */ + static_builtin_type_state *state = _PyStaticType_GetState(type); + assert(state != NULL); + state->type = NULL; set_static_builtin_index(type, 0); } } From d78f10dce9365800dcefb67ef0cbd2c59c97b9a2 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 20 Jul 2022 18:04:12 -0600 Subject: [PATCH 12/30] Add some asserts. --- Objects/typeobject.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f58585bf414c6e..15ece24ea890fb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4250,6 +4250,8 @@ static inline void set_static_builtin_index(PyTypeObject *, size_t); void _PyStaticType_Dealloc(PyTypeObject *type) { + assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)); + type_dealloc_common(type); Py_CLEAR(type->tp_dict); @@ -4268,6 +4270,7 @@ _PyStaticType_Dealloc(PyTypeObject *type) if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { /* Reset the type's per-interpreter state. This basically undoes what _PyStaticType_InitBuiltin() did. */ + assert(get_static_builtin_index(type) > 0); static_builtin_type_state *state = _PyStaticType_GetState(type); assert(state != NULL); state->type = NULL; From 44edc49bab2ca49548a546a913044ba165b95674 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 20 Jul 2022 18:07:50 -0600 Subject: [PATCH 13/30] Decrement num_builtins_initialized. --- Objects/typeobject.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 15ece24ea890fb..e231cd50bbd59a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4275,6 +4275,10 @@ _PyStaticType_Dealloc(PyTypeObject *type) assert(state != NULL); state->type = NULL; set_static_builtin_index(type, 0); + + PyInterpreterState *interp = _PyInterpreterState_GET(); + assert(interp->types.num_builtins_initialized > 0); + interp->types.num_builtins_initialized--; } } From bc7fa2620863078f6ba4ef73c75eebc43bd4f95f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 22 Jul 2022 15:47:26 -0600 Subject: [PATCH 14/30] Verify the per-interpreter type state has been cleared. --- Objects/typeobject.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e231cd50bbd59a..288b3661b4ca20 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -279,6 +279,12 @@ _PyTypes_Fini(PyInterpreterState *interp) 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); + } } From 3f20f4ab037099754b8075ffddf38350c73ce8b4 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 25 Jul 2022 15:35:30 -0600 Subject: [PATCH 15/30] Add tp_static_builtin_index to the docs. --- Doc/c-api/type.rst | 1 + Doc/c-api/typeobj.rst | 13 +++++++++++++ Doc/includes/typestruct.h | 2 ++ 3 files changed, 16 insertions(+) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index aa77c285e3b829..e18a64c95d9ba1 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -325,6 +325,7 @@ The following functions and structs are used to create * :c:member:`~PyTypeObject.tp_cache` * :c:member:`~PyTypeObject.tp_subclasses` * :c:member:`~PyTypeObject.tp_weaklist` + * :c:member:`~PyTypeObject.tp_tp_static_builtin_index` * :c:member:`~PyTypeObject.tp_vectorcall` * :c:member:`~PyTypeObject.tp_weaklistoffset` (see :ref:`PyMemberDef `) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index a331e9c1885092..b5de63e4553ee7 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -147,6 +147,8 @@ Quick Reference +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ | :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ + | [:c:member:`~PyTypeObject.tp_static_builtin_index`] | size_t | | | | | + +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ .. [#slots] A slot name in parentheses indicates it is (effectively) deprecated. @@ -2028,6 +2030,17 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. versionadded:: 3.9 (the field exists since 3.8 but it's only used since 3.9) +.. c:member:: PyObject* PyTypeObject.tp_static_builtin_index + + A static builtin type's index into the per-interpreter array of type state. + Internal use only. + + **Inheritance:** + + This field is not inherited. + + .. versionadded:: 3.12 + .. _static-types: diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index 02f8ccfe4438a5..3cf461a339cc8a 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -80,4 +80,6 @@ typedef struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; + + size_t tp_static_builtin_index; } PyTypeObject; From 9f7775d0c4c7e4178f25be1011287450d4fb8287 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 25 Jul 2022 16:05:30 -0600 Subject: [PATCH 16/30] Revert "Add tp_static_builtin_index to the docs." This reverts commit 3f20f4ab037099754b8075ffddf38350c73ce8b4. --- Doc/c-api/type.rst | 1 - Doc/c-api/typeobj.rst | 13 ------------- Doc/includes/typestruct.h | 2 -- 3 files changed, 16 deletions(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index e18a64c95d9ba1..aa77c285e3b829 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -325,7 +325,6 @@ The following functions and structs are used to create * :c:member:`~PyTypeObject.tp_cache` * :c:member:`~PyTypeObject.tp_subclasses` * :c:member:`~PyTypeObject.tp_weaklist` - * :c:member:`~PyTypeObject.tp_tp_static_builtin_index` * :c:member:`~PyTypeObject.tp_vectorcall` * :c:member:`~PyTypeObject.tp_weaklistoffset` (see :ref:`PyMemberDef `) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index b5de63e4553ee7..a331e9c1885092 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -147,8 +147,6 @@ Quick Reference +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ | :c:member:`~PyTypeObject.tp_vectorcall` | :c:type:`vectorcallfunc` | | | | | | +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ - | [:c:member:`~PyTypeObject.tp_static_builtin_index`] | size_t | | | | | - +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+ .. [#slots] A slot name in parentheses indicates it is (effectively) deprecated. @@ -2030,17 +2028,6 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. versionadded:: 3.9 (the field exists since 3.8 but it's only used since 3.9) -.. c:member:: PyObject* PyTypeObject.tp_static_builtin_index - - A static builtin type's index into the per-interpreter array of type state. - Internal use only. - - **Inheritance:** - - This field is not inherited. - - .. versionadded:: 3.12 - .. _static-types: diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h index 3cf461a339cc8a..02f8ccfe4438a5 100644 --- a/Doc/includes/typestruct.h +++ b/Doc/includes/typestruct.h @@ -80,6 +80,4 @@ typedef struct _typeobject { destructor tp_finalize; vectorcallfunc tp_vectorcall; - - size_t tp_static_builtin_index; } PyTypeObject; From cf04c2c4228bbb0a82810f8b23080bd64ab242c8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 25 Jul 2022 16:41:58 -0600 Subject: [PATCH 17/30] Update tp_flags sooner in _PyStaticType_InitBuiltin(). --- Objects/typeobject.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 288b3661b4ca20..c55de3df3f7023 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4285,6 +4285,8 @@ _PyStaticType_Dealloc(PyTypeObject *type) PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->types.num_builtins_initialized > 0); interp->types.num_builtins_initialized--; + + /* We leave tp_flags with _Py_TPFLAGS_STATIC_BUILTIN set. */ } } @@ -6715,6 +6717,8 @@ set_static_builtin_index(PyTypeObject *self, size_t index) int _PyStaticType_InitBuiltin(PyTypeObject *self) { + self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; + /* It should only be called once for each builtin type. */ assert(get_static_builtin_index(self) == 0); @@ -6731,8 +6735,6 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) assert(state != NULL); state->type = self; - self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; - return PyType_Ready(self); } From 38427a0f4dbfd277bcb8edcb23290ddeb5d1a8d2 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 11:45:18 -0600 Subject: [PATCH 18/30] Move the state/index-related helpers to the top. --- Objects/typeobject.c | 63 ++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c55de3df3f7023..20dc13d88589e0 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -67,6 +67,37 @@ 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 size_t +static_builtin_index_get(PyTypeObject *self) +{ + return self->tp_static_builtin_index; +} + +static inline void +static_builtin_index_set(PyTypeObject *self, size_t index) +{ + assert(index < _Py_MAX_STATIC_BUILTIN_TYPES); + self->tp_static_builtin_index = index; +} + +static_builtin_type_state * +_PyStaticType_GetState(PyTypeObject *self) +{ + if (static_builtin_index_get(self) == 0) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &(interp->types.builtins[static_builtin_index_get(self) - 1]); +} + +// 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 '('. @@ -4250,8 +4281,6 @@ clear_static_tp_subclasses(PyTypeObject *type) Py_CLEAR(type->tp_subclasses); } -static inline size_t get_static_builtin_index(PyTypeObject *); -static inline void set_static_builtin_index(PyTypeObject *, size_t); void _PyStaticType_Dealloc(PyTypeObject *type) @@ -4276,11 +4305,11 @@ _PyStaticType_Dealloc(PyTypeObject *type) if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { /* Reset the type's per-interpreter state. This basically undoes what _PyStaticType_InitBuiltin() did. */ - assert(get_static_builtin_index(type) > 0); + assert(static_builtin_index_get(type) > 0); static_builtin_type_state *state = _PyStaticType_GetState(type); assert(state != NULL); state->type = NULL; - set_static_builtin_index(type, 0); + static_builtin_index_set(type, 0); PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->types.num_builtins_initialized > 0); @@ -6702,25 +6731,13 @@ PyType_Ready(PyTypeObject *type) } -static inline size_t -get_static_builtin_index(PyTypeObject *self) -{ - return self->tp_static_builtin_index; -} - -static inline void -set_static_builtin_index(PyTypeObject *self, size_t index) -{ - self->tp_static_builtin_index = index; -} - int _PyStaticType_InitBuiltin(PyTypeObject *self) { self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; /* It should only be called once for each builtin type. */ - assert(get_static_builtin_index(self) == 0); + assert(static_builtin_index_get(self) == 0); /* For static types we store some state in an array on each interpreter. */ PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -6728,7 +6745,7 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) assert(interp->types.num_builtins_initialized < _Py_MAX_STATIC_BUILTIN_TYPES); /* We use 1-based indexing so 0 can mean "not initialized". */ - set_static_builtin_index(self, interp->types.num_builtins_initialized); + static_builtin_index_set(self, interp->types.num_builtins_initialized); /* Now we initialize the type's per-interpreter state. */ static_builtin_type_state *state = _PyStaticType_GetState(self); @@ -6738,16 +6755,6 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) return PyType_Ready(self); } -static_builtin_type_state * -_PyStaticType_GetState(PyTypeObject *self) -{ - if (get_static_builtin_index(self) == 0) { - return NULL; - } - PyInterpreterState *interp = _PyInterpreterState_GET(); - return &(interp->types.builtins[get_static_builtin_index(self) - 1]); -} - static int add_subclass(PyTypeObject *base, PyTypeObject *type) From d313dbd739f9d540d361c0eb4e9d08970ec7e25b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 11:49:21 -0600 Subject: [PATCH 19/30] Add static_builtin_index_is_set() and static_builtin_index_clear(). --- Objects/typeobject.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 20dc13d88589e0..8e96b62656833e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -70,9 +70,16 @@ 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(self->tp_static_builtin_index > 0); return self->tp_static_builtin_index; } @@ -83,10 +90,17 @@ static_builtin_index_set(PyTypeObject *self, size_t index) self->tp_static_builtin_index = index; } +static inline void +static_builtin_index_clear(PyTypeObject *self) +{ + self->tp_static_builtin_index = 0; +} + static_builtin_type_state * _PyStaticType_GetState(PyTypeObject *self) { - if (static_builtin_index_get(self) == 0) { + assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); + if (!static_builtin_index_is_set(self)) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -4305,11 +4319,10 @@ _PyStaticType_Dealloc(PyTypeObject *type) if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { /* Reset the type's per-interpreter state. This basically undoes what _PyStaticType_InitBuiltin() did. */ - assert(static_builtin_index_get(type) > 0); static_builtin_type_state *state = _PyStaticType_GetState(type); assert(state != NULL); state->type = NULL; - static_builtin_index_set(type, 0); + static_builtin_index_clear(type); PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->types.num_builtins_initialized > 0); @@ -6737,7 +6750,7 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; /* It should only be called once for each builtin type. */ - assert(static_builtin_index_get(self) == 0); + assert(!static_builtin_index_is_set(self)); /* For static types we store some state in an array on each interpreter. */ PyInterpreterState *interp = _PyInterpreterState_GET(); From b4bbfcb82a0f018357e936d3641809fa38f7ef3f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 11:58:07 -0600 Subject: [PATCH 20/30] Hide the 1-based indexing behind the helper functions. --- Objects/typeobject.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8e96b62656833e..4f7043865abaf5 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -80,14 +80,16 @@ static inline size_t static_builtin_index_get(PyTypeObject *self) { assert(self->tp_static_builtin_index > 0); - return self->tp_static_builtin_index; + /* 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); - self->tp_static_builtin_index = index; + /* We store a 1-based index so 0 can mean "not initialized". */ + self->tp_static_builtin_index = index + 1; } static inline void @@ -104,7 +106,7 @@ _PyStaticType_GetState(PyTypeObject *self) return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); - return &(interp->types.builtins[static_builtin_index_get(self) - 1]); + return &(interp->types.builtins[static_builtin_index_get(self)]); } // Also see _PyStaticType_InitBuiltin() and _PyStaticType_Dealloc(). @@ -6754,11 +6756,8 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) /* For static types we store some state in an array on each interpreter. */ PyInterpreterState *interp = _PyInterpreterState_GET(); - interp->types.num_builtins_initialized++; - assert(interp->types.num_builtins_initialized < _Py_MAX_STATIC_BUILTIN_TYPES); - - /* We use 1-based indexing so 0 can mean "not initialized". */ static_builtin_index_set(self, interp->types.num_builtins_initialized); + interp->types.num_builtins_initialized++; /* Now we initialize the type's per-interpreter state. */ static_builtin_type_state *state = _PyStaticType_GetState(self); From 1bd26c49ac56a3efaab3ad4ae764918b0707e482 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 12:06:34 -0600 Subject: [PATCH 21/30] Move and edit a comment. --- Objects/typeobject.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4f7043865abaf5..a2c96a79ee09ea 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4325,12 +4325,11 @@ _PyStaticType_Dealloc(PyTypeObject *type) assert(state != NULL); state->type = NULL; static_builtin_index_clear(type); + /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->types.num_builtins_initialized > 0); interp->types.num_builtins_initialized--; - - /* We leave tp_flags with _Py_TPFLAGS_STATIC_BUILTIN set. */ } } From 652fcc6ce6af16d009a9ada05e56e1248f3ed75a Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 12:25:25 -0600 Subject: [PATCH 22/30] Factor out static_builtin_state_init() and static_builtin_state_clear(). --- Objects/typeobject.c | 59 ++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a2c96a79ee09ea..d3370b67a0814b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -98,6 +98,7 @@ static_builtin_index_clear(PyTypeObject *self) self->tp_static_builtin_index = 0; } +/* For static types we store some state in an array on each interpreter. */ static_builtin_type_state * _PyStaticType_GetState(PyTypeObject *self) { @@ -109,6 +110,38 @@ _PyStaticType_GetState(PyTypeObject *self) return &(interp->types.builtins[static_builtin_index_get(self)]); } +static void +static_builtin_state_init(PyTypeObject *self) +{ + /* It should only be called once for each builtin type. */ + assert(!static_builtin_index_is_set(self)); + + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_index_set(self, interp->types.num_builtins_initialized); + interp->types.num_builtins_initialized++; + + /* Now we initialize the type's per-interpreter state. */ + static_builtin_type_state *state = _PyStaticType_GetState(self); + assert(state != NULL); + 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. */ + static_builtin_type_state *state = _PyStaticType_GetState(self); + assert(state != NULL); + state->type = NULL; + static_builtin_index_clear(self); + /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ + + PyInterpreterState *interp = _PyInterpreterState_GET(); + assert(interp->types.num_builtins_initialized > 0); + interp->types.num_builtins_initialized--; +} + // Also see _PyStaticType_InitBuiltin() and _PyStaticType_Dealloc(). /* end static builtin helpers */ @@ -4297,7 +4330,6 @@ clear_static_tp_subclasses(PyTypeObject *type) Py_CLEAR(type->tp_subclasses); } - void _PyStaticType_Dealloc(PyTypeObject *type) { @@ -4319,17 +4351,7 @@ _PyStaticType_Dealloc(PyTypeObject *type) type->tp_flags &= ~Py_TPFLAGS_READY; if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - /* Reset the type's per-interpreter state. - This basically undoes what _PyStaticType_InitBuiltin() did. */ - static_builtin_type_state *state = _PyStaticType_GetState(type); - assert(state != NULL); - state->type = NULL; - static_builtin_index_clear(type); - /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ - - PyInterpreterState *interp = _PyInterpreterState_GET(); - assert(interp->types.num_builtins_initialized > 0); - interp->types.num_builtins_initialized--; + static_builtin_state_clear(type); } } @@ -6750,18 +6772,7 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) { self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN; - /* It should only be called once for each builtin type. */ - assert(!static_builtin_index_is_set(self)); - - /* For static types we store some state in an array on each interpreter. */ - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_index_set(self, interp->types.num_builtins_initialized); - interp->types.num_builtins_initialized++; - - /* Now we initialize the type's per-interpreter state. */ - static_builtin_type_state *state = _PyStaticType_GetState(self); - assert(state != NULL); - state->type = self; + static_builtin_state_init(self); return PyType_Ready(self); } From d558a466094a121b9f950d7521ee666465112a7c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 12:26:51 -0600 Subject: [PATCH 23/30] Un-initialize the type if PyType_Ready() fails. --- Objects/typeobject.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d3370b67a0814b..d17800e1f57964 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6774,7 +6774,11 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) static_builtin_state_init(self); - return PyType_Ready(self); + int res = PyType_Ready(self); + if (res < 0) { + static_builtin_state_clear(self); + } + return res; } From 39a8fc7d1d1840498a08fc98f2c4aa6e458d9ded Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 12:31:26 -0600 Subject: [PATCH 24/30] Drop an empty line. --- Objects/typeobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d17800e1f57964..a1aa05fdb11757 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6766,7 +6766,6 @@ PyType_Ready(PyTypeObject *type) return 0; } - int _PyStaticType_InitBuiltin(PyTypeObject *self) { From 6019eba05e2319e1b3fd41946fe448fa0a172984 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 12:32:53 -0600 Subject: [PATCH 25/30] Move a comment. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a1aa05fdb11757..b765dcae17245a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -135,7 +135,6 @@ static_builtin_state_clear(PyTypeObject *self) assert(state != NULL); state->type = NULL; static_builtin_index_clear(self); - /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->types.num_builtins_initialized > 0); @@ -4352,6 +4351,7 @@ _PyStaticType_Dealloc(PyTypeObject *type) if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { static_builtin_state_clear(type); + /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ } } From f2f10f01355c35d83f6f6bacae47b4f11ea62ab4 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 13:19:47 -0600 Subject: [PATCH 26/30] static_builtin_type_state -> static_builtin_state (and factor out static_builtin_state_get()) --- Include/internal/pycore_typeobject.h | 6 +++--- Objects/typeobject.c | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 545e28ac32f5fc..dc1c02ba412809 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -45,19 +45,19 @@ struct type_cache { typedef struct { PyTypeObject *type; -} static_builtin_type_state; +} static_builtin_state; struct types_state { struct type_cache type_cache; size_t num_builtins_initialized; - static_builtin_type_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES]; + static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES]; }; extern PyStatus _PyTypes_InitSlotDefs(void); extern int _PyStaticType_InitBuiltin(PyTypeObject *type); -extern static_builtin_type_state * _PyStaticType_GetState(PyTypeObject *); +extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *); extern void _PyStaticType_Dealloc(PyTypeObject *type); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b765dcae17245a..312cfdd01e9b89 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -98,8 +98,14 @@ static_builtin_index_clear(PyTypeObject *self) self->tp_static_builtin_index = 0; } +static inline static_builtin_state * +static_builtin_state_get(PyInterpreterState *interp, size_t index) +{ + return &(interp->types.builtins[index]); +} + /* For static types we store some state in an array on each interpreter. */ -static_builtin_type_state * +static_builtin_state * _PyStaticType_GetState(PyTypeObject *self) { assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); @@ -107,7 +113,7 @@ _PyStaticType_GetState(PyTypeObject *self) return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); - return &(interp->types.builtins[static_builtin_index_get(self)]); + return static_builtin_state_get(interp, static_builtin_index_get(self)); } static void @@ -117,11 +123,12 @@ static_builtin_state_init(PyTypeObject *self) assert(!static_builtin_index_is_set(self)); PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_index_set(self, interp->types.num_builtins_initialized); + size_t index = interp->types.num_builtins_initialized; interp->types.num_builtins_initialized++; + static_builtin_index_set(self, index); /* Now we initialize the type's per-interpreter state. */ - static_builtin_type_state *state = _PyStaticType_GetState(self); + static_builtin_state *state = static_builtin_state_get(interp, index); assert(state != NULL); state->type = self; } @@ -131,12 +138,14 @@ static_builtin_state_clear(PyTypeObject *self) { /* Reset the type's per-interpreter state. This basically undoes what static_builtin_state_init() did. */ - static_builtin_type_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + + size_t index = static_builtin_index_get(self); + static_builtin_state *state = static_builtin_state_get(interp, index); assert(state != NULL); state->type = NULL; static_builtin_index_clear(self); - PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->types.num_builtins_initialized > 0); interp->types.num_builtins_initialized--; } From cea5d3438a30827dfbd53aaa6ceed6567298a0c6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 13:56:47 -0600 Subject: [PATCH 27/30] Pass the type to static_builtin_state_get(). --- Objects/typeobject.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 312cfdd01e9b89..0fda4bb05d19af 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -99,9 +99,9 @@ static_builtin_index_clear(PyTypeObject *self) } static inline static_builtin_state * -static_builtin_state_get(PyInterpreterState *interp, size_t index) +static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self) { - return &(interp->types.builtins[index]); + return &(interp->types.builtins[static_builtin_index_get(self)]); } /* For static types we store some state in an array on each interpreter. */ @@ -113,23 +113,22 @@ _PyStaticType_GetState(PyTypeObject *self) return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); - return static_builtin_state_get(interp, static_builtin_index_get(self)); + 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)); - PyInterpreterState *interp = _PyInterpreterState_GET(); - size_t index = interp->types.num_builtins_initialized; + static_builtin_index_set(self, interp->types.num_builtins_initialized); interp->types.num_builtins_initialized++; - static_builtin_index_set(self, index); - /* Now we initialize the type's per-interpreter state. */ - static_builtin_state *state = static_builtin_state_get(interp, index); - assert(state != NULL); + static_builtin_state *state = static_builtin_state_get(interp, self); state->type = self; } @@ -140,9 +139,7 @@ static_builtin_state_clear(PyTypeObject *self) This basically undoes what static_builtin_state_init() did. */ PyInterpreterState *interp = _PyInterpreterState_GET(); - size_t index = static_builtin_index_get(self); - static_builtin_state *state = static_builtin_state_get(interp, index); - assert(state != NULL); + static_builtin_state *state = static_builtin_state_get(interp, self); state->type = NULL; static_builtin_index_clear(self); From 4348e3f71cab7f07616a0b4f50b143f575ccc371 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 14:55:18 -0600 Subject: [PATCH 28/30] Handle non-builtin and non-static types in _PyStaticType_GetState(). --- Objects/typeobject.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0fda4bb05d19af..dc851474893842 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -108,7 +108,9 @@ static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self) static_builtin_state * _PyStaticType_GetState(PyTypeObject *self) { - assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); + if (!(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)) { + return NULL; + } if (!static_builtin_index_is_set(self)) { return NULL; } From 1c8b0c30e9df1347d2a54d342a7e776c94f14f28 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 16:52:47 -0600 Subject: [PATCH 29/30] Use static_builtin_index_is_set() in static_builtin_index_get(). --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index dc851474893842..c0a98c4fe110e6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -79,7 +79,7 @@ static_builtin_index_is_set(PyTypeObject *self) static inline size_t static_builtin_index_get(PyTypeObject *self) { - assert(self->tp_static_builtin_index > 0); + 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; } From ae2d4407355bcc51772e033aa4d7132815641cc6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 26 Jul 2022 16:55:04 -0600 Subject: [PATCH 30/30] Restrict _PyStaticType_GetState() to static builtin types. --- Objects/typeobject.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c0a98c4fe110e6..9eb2390118d097 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -108,12 +108,7 @@ static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self) static_builtin_state * _PyStaticType_GetState(PyTypeObject *self) { - if (!(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)) { - return NULL; - } - if (!static_builtin_index_is_set(self)) { - return NULL; - } + assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); PyInterpreterState *interp = _PyInterpreterState_GET(); return static_builtin_state_get(interp, self); }