13
13
#include "pycore_moduleobject.h" // _PyModule_GetDef()
14
14
#include "pycore_object.h" // _PyType_HasFeature()
15
15
#include "pycore_object_alloc.h" // _PyObject_MallocWithType()
16
+ #include "pycore_pyatomic_ft_wrappers.h"
16
17
#include "pycore_pyerrors.h" // _PyErr_Occurred()
17
18
#include "pycore_pystate.h" // _PyThreadState_GET()
18
19
#include "pycore_symtable.h" // _Py_Mangle()
@@ -344,6 +345,39 @@ _PyStaticType_GetBuiltins(void)
344
345
345
346
/* end static builtin helpers */
346
347
348
+ static void
349
+ type_set_flags (PyTypeObject * tp , unsigned long flags )
350
+ {
351
+ if (tp -> tp_flags & Py_TPFLAGS_READY ) {
352
+ // It's possible the type object has been exposed to other threads
353
+ // if it's been marked ready. In that case, the type lock should be
354
+ // held when flags are modified.
355
+ ASSERT_TYPE_LOCK_HELD ();
356
+ }
357
+ // Since PyType_HasFeature() reads the flags without holding the type
358
+ // lock, we need an atomic store here.
359
+ FT_ATOMIC_STORE_ULONG_RELAXED (tp -> tp_flags , flags );
360
+ }
361
+
362
+ static void
363
+ type_set_flags_with_mask (PyTypeObject * tp , unsigned long mask , unsigned long flags )
364
+ {
365
+ ASSERT_TYPE_LOCK_HELD ();
366
+ unsigned long new_flags = (tp -> tp_flags & ~mask ) | flags ;
367
+ type_set_flags (tp , new_flags );
368
+ }
369
+
370
+ static void
371
+ type_add_flags (PyTypeObject * tp , unsigned long flag )
372
+ {
373
+ type_set_flags (tp , tp -> tp_flags | flag );
374
+ }
375
+
376
+ static void
377
+ type_clear_flags (PyTypeObject * tp , unsigned long flag )
378
+ {
379
+ type_set_flags (tp , tp -> tp_flags & ~flag );
380
+ }
347
381
348
382
static inline void
349
383
start_readying (PyTypeObject * type )
@@ -357,7 +391,7 @@ start_readying(PyTypeObject *type)
357
391
return ;
358
392
}
359
393
assert ((type -> tp_flags & Py_TPFLAGS_READYING ) == 0 );
360
- type -> tp_flags |= Py_TPFLAGS_READYING ;
394
+ type_add_flags ( type , Py_TPFLAGS_READYING ) ;
361
395
}
362
396
363
397
static inline void
@@ -372,7 +406,7 @@ stop_readying(PyTypeObject *type)
372
406
return ;
373
407
}
374
408
assert (type -> tp_flags & Py_TPFLAGS_READYING );
375
- type -> tp_flags &= ~ Py_TPFLAGS_READYING ;
409
+ type_clear_flags ( type , Py_TPFLAGS_READYING ) ;
376
410
}
377
411
378
412
static inline int
@@ -1548,11 +1582,14 @@ type_set_abstractmethods(PyObject *tp, PyObject *value, void *Py_UNUSED(closure)
1548
1582
return -1 ;
1549
1583
}
1550
1584
1551
- PyType_Modified (type );
1585
+ BEGIN_TYPE_LOCK ();
1586
+ type_modified_unlocked (type );
1552
1587
if (abstract )
1553
- type -> tp_flags |= Py_TPFLAGS_IS_ABSTRACT ;
1588
+ type_add_flags ( type , Py_TPFLAGS_IS_ABSTRACT ) ;
1554
1589
else
1555
- type -> tp_flags &= ~Py_TPFLAGS_IS_ABSTRACT ;
1590
+ type_clear_flags (type , Py_TPFLAGS_IS_ABSTRACT );
1591
+ END_TYPE_LOCK ();
1592
+
1556
1593
return 0 ;
1557
1594
}
1558
1595
@@ -3335,7 +3372,7 @@ mro_internal_unlocked(PyTypeObject *type, int initial, PyObject **p_old_mro)
3335
3372
3336
3373
// XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE?
3337
3374
if (!(type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN )) {
3338
- PyType_Modified (type );
3375
+ type_modified_unlocked (type );
3339
3376
}
3340
3377
else {
3341
3378
/* For static builtin types, this is only called during init
@@ -3941,8 +3978,8 @@ type_new_alloc(type_new_ctx *ctx)
3941
3978
// Initialize tp_flags.
3942
3979
// All heap types need GC, since we can create a reference cycle by storing
3943
3980
// an instance on one of its parents.
3944
- type -> tp_flags = ( Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
3945
- Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC );
3981
+ type_set_flags ( type , Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
3982
+ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC );
3946
3983
3947
3984
// Initialize essential fields
3948
3985
type -> tp_as_async = & et -> as_async ;
@@ -4175,12 +4212,12 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
4175
4212
4176
4213
if (ctx -> add_weak ) {
4177
4214
assert ((type -> tp_flags & Py_TPFLAGS_MANAGED_WEAKREF ) == 0 );
4178
- type -> tp_flags |= Py_TPFLAGS_MANAGED_WEAKREF ;
4215
+ type_add_flags ( type , Py_TPFLAGS_MANAGED_WEAKREF ) ;
4179
4216
type -> tp_weaklistoffset = MANAGED_WEAKREF_OFFSET ;
4180
4217
}
4181
4218
if (ctx -> add_dict ) {
4182
4219
assert ((type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) == 0 );
4183
- type -> tp_flags |= Py_TPFLAGS_MANAGED_DICT ;
4220
+ type_add_flags ( type , Py_TPFLAGS_MANAGED_DICT ) ;
4184
4221
type -> tp_dictoffset = -1 ;
4185
4222
}
4186
4223
@@ -4978,7 +5015,7 @@ PyType_FromMetaclass(
4978
5015
4979
5016
type = & res -> ht_type ;
4980
5017
/* The flags must be initialized early, before the GC traverses us */
4981
- type -> tp_flags = spec -> flags | Py_TPFLAGS_HEAPTYPE ;
5018
+ type_set_flags ( type , spec -> flags | Py_TPFLAGS_HEAPTYPE ) ;
4982
5019
4983
5020
res -> ht_module = Py_XNewRef (module );
4984
5021
@@ -5739,18 +5776,11 @@ _PyType_CacheGetItemForSpecialization(PyHeapTypeObject *ht, PyObject *descriptor
5739
5776
return can_cache ;
5740
5777
}
5741
5778
5742
- static void
5743
- set_flags (PyTypeObject * self , unsigned long mask , unsigned long flags )
5744
- {
5745
- ASSERT_TYPE_LOCK_HELD ();
5746
- self -> tp_flags = (self -> tp_flags & ~mask ) | flags ;
5747
- }
5748
-
5749
5779
void
5750
5780
_PyType_SetFlags (PyTypeObject * self , unsigned long mask , unsigned long flags )
5751
5781
{
5752
5782
BEGIN_TYPE_LOCK ();
5753
- set_flags (self , mask , flags );
5783
+ type_set_flags_with_mask (self , mask , flags );
5754
5784
END_TYPE_LOCK ();
5755
5785
}
5756
5786
@@ -5781,7 +5811,7 @@ set_flags_recursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
5781
5811
return ;
5782
5812
}
5783
5813
5784
- set_flags (self , mask , flags );
5814
+ type_set_flags_with_mask (self , mask , flags );
5785
5815
5786
5816
PyObject * children = _PyType_GetSubclasses (self );
5787
5817
if (children == NULL ) {
@@ -6116,8 +6146,10 @@ fini_static_type(PyInterpreterState *interp, PyTypeObject *type,
6116
6146
clear_static_type_objects (interp , type , isbuiltin , final );
6117
6147
6118
6148
if (final ) {
6119
- type -> tp_flags &= ~Py_TPFLAGS_READY ;
6120
- _PyType_SetVersion (type , 0 );
6149
+ BEGIN_TYPE_LOCK ();
6150
+ type_clear_flags (type , Py_TPFLAGS_READY );
6151
+ set_version_unlocked (type , 0 );
6152
+ END_TYPE_LOCK ();
6121
6153
}
6122
6154
6123
6155
_PyStaticType_ClearWeakRefs (interp , type );
@@ -7866,13 +7898,13 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
7866
7898
if (!(type -> tp_flags & Py_TPFLAGS_HAVE_GC ) &&
7867
7899
(base -> tp_flags & Py_TPFLAGS_HAVE_GC ) &&
7868
7900
(!type -> tp_traverse && !type -> tp_clear )) {
7869
- type -> tp_flags |= Py_TPFLAGS_HAVE_GC ;
7901
+ type_add_flags ( type , Py_TPFLAGS_HAVE_GC ) ;
7870
7902
if (type -> tp_traverse == NULL )
7871
7903
type -> tp_traverse = base -> tp_traverse ;
7872
7904
if (type -> tp_clear == NULL )
7873
7905
type -> tp_clear = base -> tp_clear ;
7874
7906
}
7875
- type -> tp_flags |= ( base -> tp_flags & Py_TPFLAGS_PREHEADER );
7907
+ type_add_flags ( type , base -> tp_flags & Py_TPFLAGS_PREHEADER );
7876
7908
7877
7909
if (type -> tp_basicsize == 0 )
7878
7910
type -> tp_basicsize = base -> tp_basicsize ;
@@ -7890,38 +7922,40 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
7890
7922
7891
7923
/* Setup fast subclass flags */
7892
7924
PyObject * mro = lookup_tp_mro (base );
7925
+ unsigned long flags = 0 ;
7893
7926
if (is_subtype_with_mro (mro , base , (PyTypeObject * )PyExc_BaseException )) {
7894
- type -> tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS ;
7927
+ flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS ;
7895
7928
}
7896
7929
else if (is_subtype_with_mro (mro , base , & PyType_Type )) {
7897
- type -> tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS ;
7930
+ flags |= Py_TPFLAGS_TYPE_SUBCLASS ;
7898
7931
}
7899
7932
else if (is_subtype_with_mro (mro , base , & PyLong_Type )) {
7900
- type -> tp_flags |= Py_TPFLAGS_LONG_SUBCLASS ;
7933
+ flags |= Py_TPFLAGS_LONG_SUBCLASS ;
7901
7934
}
7902
7935
else if (is_subtype_with_mro (mro , base , & PyBytes_Type )) {
7903
- type -> tp_flags |= Py_TPFLAGS_BYTES_SUBCLASS ;
7936
+ flags |= Py_TPFLAGS_BYTES_SUBCLASS ;
7904
7937
}
7905
7938
else if (is_subtype_with_mro (mro , base , & PyUnicode_Type )) {
7906
- type -> tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS ;
7939
+ flags |= Py_TPFLAGS_UNICODE_SUBCLASS ;
7907
7940
}
7908
7941
else if (is_subtype_with_mro (mro , base , & PyTuple_Type )) {
7909
- type -> tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS ;
7942
+ flags |= Py_TPFLAGS_TUPLE_SUBCLASS ;
7910
7943
}
7911
7944
else if (is_subtype_with_mro (mro , base , & PyList_Type )) {
7912
- type -> tp_flags |= Py_TPFLAGS_LIST_SUBCLASS ;
7945
+ flags |= Py_TPFLAGS_LIST_SUBCLASS ;
7913
7946
}
7914
7947
else if (is_subtype_with_mro (mro , base , & PyDict_Type )) {
7915
- type -> tp_flags |= Py_TPFLAGS_DICT_SUBCLASS ;
7948
+ flags |= Py_TPFLAGS_DICT_SUBCLASS ;
7916
7949
}
7917
7950
7918
7951
/* Setup some inheritable flags */
7919
7952
if (PyType_HasFeature (base , _Py_TPFLAGS_MATCH_SELF )) {
7920
- type -> tp_flags |= _Py_TPFLAGS_MATCH_SELF ;
7953
+ flags |= _Py_TPFLAGS_MATCH_SELF ;
7921
7954
}
7922
7955
if (PyType_HasFeature (base , Py_TPFLAGS_ITEMS_AT_END )) {
7923
- type -> tp_flags |= Py_TPFLAGS_ITEMS_AT_END ;
7956
+ flags |= Py_TPFLAGS_ITEMS_AT_END ;
7924
7957
}
7958
+ type_add_flags (type , flags );
7925
7959
}
7926
7960
7927
7961
static int
@@ -8069,7 +8103,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
8069
8103
if (!type -> tp_call &&
8070
8104
_PyType_HasFeature (base , Py_TPFLAGS_HAVE_VECTORCALL ))
8071
8105
{
8072
- type -> tp_flags |= Py_TPFLAGS_HAVE_VECTORCALL ;
8106
+ type_add_flags ( type , Py_TPFLAGS_HAVE_VECTORCALL ) ;
8073
8107
}
8074
8108
COPYSLOT (tp_call );
8075
8109
}
@@ -8103,7 +8137,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
8103
8137
_PyType_HasFeature (type , Py_TPFLAGS_IMMUTABLETYPE ) &&
8104
8138
_PyType_HasFeature (base , Py_TPFLAGS_METHOD_DESCRIPTOR ))
8105
8139
{
8106
- type -> tp_flags |= Py_TPFLAGS_METHOD_DESCRIPTOR ;
8140
+ type_add_flags ( type , Py_TPFLAGS_METHOD_DESCRIPTOR ) ;
8107
8141
}
8108
8142
COPYSLOT (tp_descr_set );
8109
8143
COPYSLOT (tp_dictoffset );
@@ -8418,7 +8452,7 @@ type_ready_inherit_as_structs(PyTypeObject *type, PyTypeObject *base)
8418
8452
static void
8419
8453
inherit_patma_flags (PyTypeObject * type , PyTypeObject * base ) {
8420
8454
if ((type -> tp_flags & COLLECTION_FLAGS ) == 0 ) {
8421
- type -> tp_flags |= base -> tp_flags & COLLECTION_FLAGS ;
8455
+ type_add_flags ( type , base -> tp_flags & COLLECTION_FLAGS ) ;
8422
8456
}
8423
8457
}
8424
8458
@@ -8533,7 +8567,7 @@ type_ready_set_new(PyTypeObject *type, int initial)
8533
8567
&& base == & PyBaseObject_Type
8534
8568
&& !(type -> tp_flags & Py_TPFLAGS_HEAPTYPE ))
8535
8569
{
8536
- type -> tp_flags |= Py_TPFLAGS_DISALLOW_INSTANTIATION ;
8570
+ type_add_flags ( type , Py_TPFLAGS_DISALLOW_INSTANTIATION ) ;
8537
8571
}
8538
8572
8539
8573
if (!(type -> tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION )) {
@@ -8580,7 +8614,7 @@ type_ready_managed_dict(PyTypeObject *type)
8580
8614
}
8581
8615
}
8582
8616
if (type -> tp_itemsize == 0 ) {
8583
- type -> tp_flags |= Py_TPFLAGS_INLINE_VALUES ;
8617
+ type_add_flags ( type , Py_TPFLAGS_INLINE_VALUES ) ;
8584
8618
}
8585
8619
return 0 ;
8586
8620
}
@@ -8686,7 +8720,7 @@ type_ready(PyTypeObject *type, int initial)
8686
8720
}
8687
8721
8688
8722
/* All done -- set the ready flag */
8689
- type -> tp_flags |= Py_TPFLAGS_READY ;
8723
+ type_add_flags ( type , Py_TPFLAGS_READY ) ;
8690
8724
stop_readying (type );
8691
8725
8692
8726
assert (_PyType_CheckConsistency (type ));
@@ -8708,7 +8742,7 @@ PyType_Ready(PyTypeObject *type)
8708
8742
8709
8743
/* Historically, all static types were immutable. See bpo-43908 */
8710
8744
if (!(type -> tp_flags & Py_TPFLAGS_HEAPTYPE )) {
8711
- type -> tp_flags |= Py_TPFLAGS_IMMUTABLETYPE ;
8745
+ type_add_flags ( type , Py_TPFLAGS_IMMUTABLETYPE ) ;
8712
8746
/* Static types must be immortal */
8713
8747
_Py_SetImmortalUntracked ((PyObject * )type );
8714
8748
}
@@ -8738,8 +8772,8 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self,
8738
8772
if ((self -> tp_flags & Py_TPFLAGS_READY ) == 0 ) {
8739
8773
assert (initial );
8740
8774
8741
- self -> tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN ;
8742
- self -> tp_flags |= Py_TPFLAGS_IMMUTABLETYPE ;
8775
+ type_add_flags ( self , _Py_TPFLAGS_STATIC_BUILTIN ) ;
8776
+ type_add_flags ( self , Py_TPFLAGS_IMMUTABLETYPE ) ;
8743
8777
8744
8778
assert (NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG );
8745
8779
if (self -> tp_version_tag == 0 ) {
@@ -11126,7 +11160,7 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
11126
11160
generic = p -> function ;
11127
11161
if (p -> function == slot_tp_call ) {
11128
11162
/* A generic __call__ is incompatible with vectorcall */
11129
- type -> tp_flags &= ~ Py_TPFLAGS_HAVE_VECTORCALL ;
11163
+ type_clear_flags ( type , Py_TPFLAGS_HAVE_VECTORCALL ) ;
11130
11164
}
11131
11165
}
11132
11166
Py_DECREF (descr );
@@ -11216,7 +11250,7 @@ update_all_slots(PyTypeObject* type)
11216
11250
ASSERT_TYPE_LOCK_HELD ();
11217
11251
11218
11252
/* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
11219
- PyType_Modified (type );
11253
+ type_modified_unlocked (type );
11220
11254
11221
11255
for (p = slotdefs ; p -> name ; p ++ ) {
11222
11256
/* update_slot returns int but can't actually fail */
@@ -11492,8 +11526,10 @@ PyType_Freeze(PyTypeObject *type)
11492
11526
return -1 ;
11493
11527
}
11494
11528
11495
- type -> tp_flags |= Py_TPFLAGS_IMMUTABLETYPE ;
11496
- PyType_Modified (type );
11529
+ BEGIN_TYPE_LOCK ();
11530
+ type_add_flags (type , Py_TPFLAGS_IMMUTABLETYPE );
11531
+ type_modified_unlocked (type );
11532
+ END_TYPE_LOCK ();
11497
11533
11498
11534
return 0 ;
11499
11535
}
0 commit comments