@@ -73,29 +73,29 @@ static inline PyTypeObject * subclass_from_ref(PyObject *ref);
73
73
static inline int
74
74
static_builtin_index_is_set (PyTypeObject * self )
75
75
{
76
- return self -> tp_static_builtin_index > 0 ;
76
+ return self -> tp_subclasses != NULL ;
77
77
}
78
78
79
79
static inline size_t
80
80
static_builtin_index_get (PyTypeObject * self )
81
81
{
82
82
assert (static_builtin_index_is_set (self ));
83
83
/* 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 ;
85
85
}
86
86
87
87
static inline void
88
88
static_builtin_index_set (PyTypeObject * self , size_t index )
89
89
{
90
90
assert (index < _Py_MAX_STATIC_BUILTIN_TYPES );
91
91
/* 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 ) ;
93
93
}
94
94
95
95
static inline void
96
96
static_builtin_index_clear (PyTypeObject * self )
97
97
{
98
- self -> tp_static_builtin_index = 0 ;
98
+ self -> tp_subclasses = NULL ;
99
99
}
100
100
101
101
static inline static_builtin_state *
@@ -127,6 +127,7 @@ static_builtin_state_init(PyTypeObject *self)
127
127
128
128
static_builtin_state * state = static_builtin_state_get (interp , self );
129
129
state -> type = self ;
130
+ /* state->tp_subclasses is left NULL until init_subclasses() sets it. */
130
131
/* state->tp_weaklist is left NULL until insert_head() or insert_after()
131
132
(in weakrefobject.c) sets it. */
132
133
}
@@ -373,6 +374,8 @@ _PyTypes_Fini(PyInterpreterState *interp)
373
374
}
374
375
375
376
377
+ static PyObject * lookup_subclasses (PyTypeObject * );
378
+
376
379
void
377
380
PyType_Modified (PyTypeObject * type )
378
381
{
@@ -395,7 +398,7 @@ PyType_Modified(PyTypeObject *type)
395
398
return ;
396
399
}
397
400
398
- PyObject * subclasses = type -> tp_subclasses ;
401
+ PyObject * subclasses = lookup_subclasses ( type ) ;
399
402
if (subclasses != NULL ) {
400
403
assert (PyDict_CheckExact (subclasses ));
401
404
@@ -783,7 +786,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
783
786
Py_XDECREF (old_mro );
784
787
785
788
// Avoid creating an empty list if there is no subclass
786
- if (type -> tp_subclasses != NULL ) {
789
+ if (_PyType_HasSubclasses ( type ) ) {
787
790
/* Obtain a copy of subclasses list to iterate over.
788
791
789
792
Otherwise type->tp_subclasses might be altered
@@ -4345,10 +4348,13 @@ type_dealloc_common(PyTypeObject *type)
4345
4348
}
4346
4349
4347
4350
4351
+ static void clear_subclasses (PyTypeObject * self );
4352
+
4348
4353
static void
4349
4354
clear_static_tp_subclasses (PyTypeObject * type )
4350
4355
{
4351
- if (type -> tp_subclasses == NULL ) {
4356
+ PyObject * subclasses = lookup_subclasses (type );
4357
+ if (subclasses == NULL ) {
4352
4358
return ;
4353
4359
}
4354
4360
@@ -4372,9 +4378,19 @@ clear_static_tp_subclasses(PyTypeObject *type)
4372
4378
going to leak. This mostly only affects embedding scenarios.
4373
4379
*/
4374
4380
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
+ }
4376
4392
4377
- Py_CLEAR (type -> tp_subclasses );
4393
+ clear_subclasses (type );
4378
4394
}
4379
4395
4380
4396
void
@@ -4424,7 +4440,7 @@ type_dealloc(PyTypeObject *type)
4424
4440
Py_XDECREF (type -> tp_bases );
4425
4441
Py_XDECREF (type -> tp_mro );
4426
4442
Py_XDECREF (type -> tp_cache );
4427
- Py_XDECREF (type -> tp_subclasses );
4443
+ clear_subclasses (type );
4428
4444
4429
4445
/* A type's tp_doc is heap allocated, unlike the tp_doc slots
4430
4446
* of most other objects. It's okay to cast it to char *.
@@ -4444,6 +4460,30 @@ type_dealloc(PyTypeObject *type)
4444
4460
}
4445
4461
4446
4462
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
+
4447
4487
PyObject *
4448
4488
_PyType_GetSubclasses (PyTypeObject * self )
4449
4489
{
@@ -4452,7 +4492,7 @@ _PyType_GetSubclasses(PyTypeObject *self)
4452
4492
return NULL ;
4453
4493
}
4454
4494
4455
- PyObject * subclasses = self -> tp_subclasses ; // borrowed ref
4495
+ PyObject * subclasses = lookup_subclasses ( self ) ; // borrowed ref
4456
4496
if (subclasses == NULL ) {
4457
4497
return list ;
4458
4498
}
@@ -6830,6 +6870,36 @@ _PyStaticType_InitBuiltin(PyTypeObject *self)
6830
6870
}
6831
6871
6832
6872
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
+
6833
6903
static int
6834
6904
add_subclass (PyTypeObject * base , PyTypeObject * type )
6835
6905
{
@@ -6846,9 +6916,9 @@ add_subclass(PyTypeObject *base, PyTypeObject *type)
6846
6916
// Only get tp_subclasses after creating the key and value.
6847
6917
// PyWeakref_NewRef() can trigger a garbage collection which can execute
6848
6918
// arbitrary Python code and so modify base->tp_subclasses.
6849
- PyObject * subclasses = base -> tp_subclasses ;
6919
+ PyObject * subclasses = lookup_subclasses ( base ) ;
6850
6920
if (subclasses == NULL ) {
6851
- base -> tp_subclasses = subclasses = PyDict_New ( );
6921
+ subclasses = init_subclasses ( base );
6852
6922
if (subclasses == NULL ) {
6853
6923
Py_DECREF (key );
6854
6924
Py_DECREF (ref );
@@ -6905,10 +6975,13 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base)
6905
6975
We fall back to manually traversing the values. */
6906
6976
Py_ssize_t i = 0 ;
6907
6977
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
+ }
6912
6985
}
6913
6986
}
6914
6987
/* It wasn't found. */
@@ -6918,7 +6991,7 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base)
6918
6991
static void
6919
6992
remove_subclass (PyTypeObject * base , PyTypeObject * type )
6920
6993
{
6921
- PyObject * subclasses = base -> tp_subclasses ; // borrowed ref
6994
+ PyObject * subclasses = lookup_subclasses ( base ) ; // borrowed ref
6922
6995
if (subclasses == NULL ) {
6923
6996
return ;
6924
6997
}
@@ -6934,10 +7007,7 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type)
6934
7007
Py_XDECREF (key );
6935
7008
6936
7009
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 );
6941
7011
}
6942
7012
}
6943
7013
@@ -9022,7 +9092,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
9022
9092
// It is safe to use a borrowed reference because update_subclasses() is
9023
9093
// only used with update_slots_callback() which doesn't modify
9024
9094
// tp_subclasses.
9025
- PyObject * subclasses = type -> tp_subclasses ; // borrowed ref
9095
+ PyObject * subclasses = lookup_subclasses ( type ) ; // borrowed ref
9026
9096
if (subclasses == NULL ) {
9027
9097
return 0 ;
9028
9098
}
0 commit comments