@@ -73,29 +73,29 @@ static inline PyTypeObject * subclass_from_ref(PyObject *ref);
7373static inline int
7474static_builtin_index_is_set (PyTypeObject * self )
7575{
76- return self -> tp_static_builtin_index > 0 ;
76+ return self -> tp_subclasses != NULL ;
7777}
7878
7979static inline size_t
8080static_builtin_index_get (PyTypeObject * self )
8181{
8282 assert (static_builtin_index_is_set (self ));
8383 /* We store a 1-based index so 0 can mean "not initialized". */
84- return self -> tp_static_builtin_index - 1 ;
84+ return ( size_t ) self -> tp_subclasses - 1 ;
8585}
8686
8787static inline void
8888static_builtin_index_set (PyTypeObject * self , size_t index )
8989{
9090 assert (index < _Py_MAX_STATIC_BUILTIN_TYPES );
9191 /* We store a 1-based index so 0 can mean "not initialized". */
92- self -> tp_static_builtin_index = index + 1 ;
92+ self -> tp_subclasses = ( PyObject * )( index + 1 ) ;
9393}
9494
9595static inline void
9696static_builtin_index_clear (PyTypeObject * self )
9797{
98- self -> tp_static_builtin_index = 0 ;
98+ self -> tp_subclasses = NULL ;
9999}
100100
101101static inline static_builtin_state *
@@ -127,6 +127,7 @@ static_builtin_state_init(PyTypeObject *self)
127127
128128 static_builtin_state * state = static_builtin_state_get (interp , self );
129129 state -> type = self ;
130+ /* state->tp_subclasses is left NULL until init_subclasses() sets it. */
130131 /* state->tp_weaklist is left NULL until insert_head() or insert_after()
131132 (in weakrefobject.c) sets it. */
132133}
@@ -373,6 +374,8 @@ _PyTypes_Fini(PyInterpreterState *interp)
373374}
374375
375376
377+ static PyObject * lookup_subclasses (PyTypeObject * );
378+
376379void
377380PyType_Modified (PyTypeObject * type )
378381{
@@ -395,7 +398,7 @@ PyType_Modified(PyTypeObject *type)
395398 return ;
396399 }
397400
398- PyObject * subclasses = type -> tp_subclasses ;
401+ PyObject * subclasses = lookup_subclasses ( type ) ;
399402 if (subclasses != NULL ) {
400403 assert (PyDict_CheckExact (subclasses ));
401404
@@ -783,7 +786,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
783786 Py_XDECREF (old_mro );
784787
785788 // Avoid creating an empty list if there is no subclass
786- if (type -> tp_subclasses != NULL ) {
789+ if (_PyType_HasSubclasses ( type ) ) {
787790 /* Obtain a copy of subclasses list to iterate over.
788791
789792 Otherwise type->tp_subclasses might be altered
@@ -4345,10 +4348,13 @@ type_dealloc_common(PyTypeObject *type)
43454348}
43464349
43474350
4351+ static void clear_subclasses (PyTypeObject * self );
4352+
43484353static void
43494354clear_static_tp_subclasses (PyTypeObject * type )
43504355{
4351- if (type -> tp_subclasses == NULL ) {
4356+ PyObject * subclasses = lookup_subclasses (type );
4357+ if (subclasses == NULL ) {
43524358 return ;
43534359 }
43544360
@@ -4372,9 +4378,19 @@ clear_static_tp_subclasses(PyTypeObject *type)
43724378 going to leak. This mostly only affects embedding scenarios.
43734379 */
43744380
4375- // For now we just clear tp_subclasses.
4381+ // For now we just do a sanity check and then clear tp_subclasses.
4382+ Py_ssize_t i = 0 ;
4383+ PyObject * key , * ref ; // borrowed ref
4384+ while (PyDict_Next (subclasses , & i , & key , & ref )) {
4385+ PyTypeObject * subclass = subclass_from_ref (ref ); // borrowed
4386+ if (subclass == NULL ) {
4387+ continue ;
4388+ }
4389+ // All static builtin subtypes should have been finalized already.
4390+ assert (!(subclass -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ));
4391+ }
43764392
4377- Py_CLEAR (type -> tp_subclasses );
4393+ clear_subclasses (type );
43784394}
43794395
43804396void
@@ -4424,7 +4440,7 @@ type_dealloc(PyTypeObject *type)
44244440 Py_XDECREF (type -> tp_bases );
44254441 Py_XDECREF (type -> tp_mro );
44264442 Py_XDECREF (type -> tp_cache );
4427- Py_XDECREF (type -> tp_subclasses );
4443+ clear_subclasses (type );
44284444
44294445 /* A type's tp_doc is heap allocated, unlike the tp_doc slots
44304446 * of most other objects. It's okay to cast it to char *.
@@ -4444,6 +4460,30 @@ type_dealloc(PyTypeObject *type)
44444460}
44454461
44464462
4463+ static PyObject *
4464+ lookup_subclasses (PyTypeObject * self )
4465+ {
4466+ if (self -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ) {
4467+ static_builtin_state * state = _PyStaticType_GetState (self );
4468+ assert (state != NULL );
4469+ return state -> tp_subclasses ;
4470+ }
4471+ return (PyObject * )self -> tp_subclasses ;
4472+ }
4473+
4474+ int
4475+ _PyType_HasSubclasses (PyTypeObject * self )
4476+ {
4477+ if (self -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN &&
4478+ _PyStaticType_GetState (self ) == NULL ) {
4479+ return 0 ;
4480+ }
4481+ if (lookup_subclasses (self ) == NULL ) {
4482+ return 0 ;
4483+ }
4484+ return 1 ;
4485+ }
4486+
44474487PyObject *
44484488_PyType_GetSubclasses (PyTypeObject * self )
44494489{
@@ -4452,7 +4492,7 @@ _PyType_GetSubclasses(PyTypeObject *self)
44524492 return NULL ;
44534493 }
44544494
4455- PyObject * subclasses = self -> tp_subclasses ; // borrowed ref
4495+ PyObject * subclasses = lookup_subclasses ( self ) ; // borrowed ref
44564496 if (subclasses == NULL ) {
44574497 return list ;
44584498 }
@@ -6830,6 +6870,36 @@ _PyStaticType_InitBuiltin(PyTypeObject *self)
68306870}
68316871
68326872
6873+ static PyObject *
6874+ init_subclasses (PyTypeObject * self )
6875+ {
6876+ PyObject * subclasses = PyDict_New ();
6877+ if (subclasses == NULL ) {
6878+ return NULL ;
6879+ }
6880+ if (self -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ) {
6881+ static_builtin_state * state = _PyStaticType_GetState (self );
6882+ state -> tp_subclasses = subclasses ;
6883+ return subclasses ;
6884+ }
6885+ self -> tp_subclasses = (void * )subclasses ;
6886+ return subclasses ;
6887+ }
6888+
6889+ static void
6890+ clear_subclasses (PyTypeObject * self )
6891+ {
6892+ /* Delete the dictionary to save memory. _PyStaticType_Dealloc()
6893+ callers also test if tp_subclasses is NULL to check if a static type
6894+ has no subclass. */
6895+ if (self -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ) {
6896+ static_builtin_state * state = _PyStaticType_GetState (self );
6897+ Py_CLEAR (state -> tp_subclasses );
6898+ return ;
6899+ }
6900+ Py_CLEAR (self -> tp_subclasses );
6901+ }
6902+
68336903static int
68346904add_subclass (PyTypeObject * base , PyTypeObject * type )
68356905{
@@ -6846,9 +6916,9 @@ add_subclass(PyTypeObject *base, PyTypeObject *type)
68466916 // Only get tp_subclasses after creating the key and value.
68476917 // PyWeakref_NewRef() can trigger a garbage collection which can execute
68486918 // arbitrary Python code and so modify base->tp_subclasses.
6849- PyObject * subclasses = base -> tp_subclasses ;
6919+ PyObject * subclasses = lookup_subclasses ( base ) ;
68506920 if (subclasses == NULL ) {
6851- base -> tp_subclasses = subclasses = PyDict_New ( );
6921+ subclasses = init_subclasses ( base );
68526922 if (subclasses == NULL ) {
68536923 Py_DECREF (key );
68546924 Py_DECREF (ref );
@@ -6905,10 +6975,13 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base)
69056975 We fall back to manually traversing the values. */
69066976 Py_ssize_t i = 0 ;
69076977 PyObject * ref ; // borrowed ref
6908- while (PyDict_Next ((PyObject * )base -> tp_subclasses , & i , & key , & ref )) {
6909- PyTypeObject * subclass = subclass_from_ref (ref ); // borrowed
6910- if (subclass == type ) {
6911- return Py_NewRef (key );
6978+ PyObject * subclasses = lookup_subclasses (base );
6979+ if (subclasses != NULL ) {
6980+ while (PyDict_Next (subclasses , & i , & key , & ref )) {
6981+ PyTypeObject * subclass = subclass_from_ref (ref ); // borrowed
6982+ if (subclass == type ) {
6983+ return Py_NewRef (key );
6984+ }
69126985 }
69136986 }
69146987 /* It wasn't found. */
@@ -6918,7 +6991,7 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base)
69186991static void
69196992remove_subclass (PyTypeObject * base , PyTypeObject * type )
69206993{
6921- PyObject * subclasses = base -> tp_subclasses ; // borrowed ref
6994+ PyObject * subclasses = lookup_subclasses ( base ) ; // borrowed ref
69226995 if (subclasses == NULL ) {
69236996 return ;
69246997 }
@@ -6934,10 +7007,7 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type)
69347007 Py_XDECREF (key );
69357008
69367009 if (PyDict_Size (subclasses ) == 0 ) {
6937- // Delete the dictionary to save memory. _PyStaticType_Dealloc()
6938- // callers also test if tp_subclasses is NULL to check if a static type
6939- // has no subclass.
6940- Py_CLEAR (base -> tp_subclasses );
7010+ clear_subclasses (base );
69417011 }
69427012}
69437013
@@ -9022,7 +9092,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
90229092 // It is safe to use a borrowed reference because update_subclasses() is
90239093 // only used with update_slots_callback() which doesn't modify
90249094 // tp_subclasses.
9025- PyObject * subclasses = type -> tp_subclasses ; // borrowed ref
9095+ PyObject * subclasses = lookup_subclasses ( type ) ; // borrowed ref
90269096 if (subclasses == NULL ) {
90279097 return 0 ;
90289098 }
0 commit comments