@@ -37,11 +37,17 @@ class object "PyObject *" "&PyBaseObject_Type"
3737 (((unsigned int)(version) ^ (unsigned int)(name_hash)) \
3838 & ((1 << MCACHE_SIZE_EXP) - 1))
3939
40- #define MCACHE_HASH_METHOD (type , name ) \
41- MCACHE_HASH((type)->tp_version_tag, ((Py_ssize_t)(name)) >> 3)
40+ static inline unsigned int
41+ MCACHE_HASH_METHOD (PyTypeObject * type , PyObject * name )
42+ {
43+ unsigned int version = _Py_atomic_load_uint32_relaxed (& type -> tp_version_tag );
44+ return MCACHE_HASH (version , ((Py_ssize_t )(name )) >> 3 );
45+ }
46+
4247#define MCACHE_CACHEABLE_NAME (name ) \
4348 PyUnicode_CheckExact(name) && \
4449 PyUnicode_IS_READY(name) && \
50+ PyUnicode_CHECK_INTERNED(name) && \
4551 (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
4652
4753#define next_version_tag (_PyRuntime.types.next_version_tag)
@@ -289,66 +295,42 @@ _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_d
289295static struct type_cache *
290296get_type_cache (void )
291297{
292- PyInterpreterState * interp = _PyInterpreterState_GET ();
293- return & interp -> types .type_cache ;
294- }
295-
296-
297- static void
298- type_cache_clear (struct type_cache * cache , PyObject * value )
299- {
300- for (Py_ssize_t i = 0 ; i < (1 << MCACHE_SIZE_EXP ); i ++ ) {
301- struct type_cache_entry * entry = & cache -> hashtable [i ];
302- entry -> version = 0 ;
303- Py_XSETREF (entry -> name , _Py_XNewRef (value ));
304- entry -> value = NULL ;
305- }
298+ PyThreadState * tstate = _PyThreadState_GET ();
299+ #ifdef Py_NOGIL
300+ return & ((PyThreadStateImpl * )tstate )-> type_cache ;
301+ #else
302+ return & tstate -> interp -> types .type_cache ;
303+ #endif
306304}
307305
308306
309307void
310308_PyType_InitCache (PyInterpreterState * interp )
311309{
312- struct type_cache * cache = & interp -> types .type_cache ;
313- for (Py_ssize_t i = 0 ; i < (1 << MCACHE_SIZE_EXP ); i ++ ) {
314- struct type_cache_entry * entry = & cache -> hashtable [i ];
315- assert (entry -> name == NULL );
316-
317- entry -> version = 0 ;
318- // Set to None so _PyType_Lookup() can use Py_SETREF(),
319- // rather than using slower Py_XSETREF().
320- entry -> name = Py_None ;
321- entry -> value = NULL ;
322- }
323310}
324311
325312
326313static unsigned int
327- _PyType_ClearCache (PyInterpreterState * interp )
314+ _PyType_ClearCache (PyThreadStateImpl * tstate )
328315{
329- struct type_cache * cache = & interp -> types .type_cache ;
330- // Set to None, rather than NULL, so _PyType_Lookup() can
331- // use Py_SETREF() rather than using slower Py_XSETREF().
332- type_cache_clear (cache , Py_None );
333-
316+ memset (& tstate -> type_cache , 0 , sizeof (tstate -> type_cache ));
334317 return next_version_tag - 1 ;
335318}
336319
337320
338321unsigned int
339322PyType_ClearCache (void )
340323{
341- PyInterpreterState * interp = _PyInterpreterState_GET ();
342- return _PyType_ClearCache (interp );
324+ // TODO: clear all threads type caches or merge type caches
325+ PyThreadState * tstate = _PyThreadState_GET ();
326+ return _PyType_ClearCache ((PyThreadStateImpl * )tstate );
343327}
344328
345329
346330void
347331_PyTypes_Fini (PyInterpreterState * interp )
348332{
349- struct type_cache * cache = & interp -> types .type_cache ;
350- type_cache_clear (cache , NULL );
351-
333+ _PyType_ClearCache (& interp -> _initial_thread );
352334 assert (interp -> types .num_builtins_initialized == 0 );
353335 // All the static builtin types should have been finalized already.
354336 for (size_t i = 0 ; i < _Py_MAX_STATIC_BUILTIN_TYPES ; i ++ ) {
@@ -436,8 +418,8 @@ PyType_Unwatch(int watcher_id, PyObject* obj)
436418 return 0 ;
437419}
438420
439- void
440- PyType_Modified (PyTypeObject * type )
421+ static void
422+ _PyType_ModifiedEx (PyTypeObject * type )
441423{
442424 /* Invalidate any cached data for the specified type and all
443425 subclasses. This function is called after the base
@@ -469,7 +451,7 @@ PyType_Modified(PyTypeObject *type)
469451 if (subclass == NULL ) {
470452 continue ;
471453 }
472- PyType_Modified (subclass );
454+ _PyType_ModifiedEx (subclass );
473455 Py_DECREF (subclass );
474456 }
475457 }
@@ -496,6 +478,14 @@ PyType_Modified(PyTypeObject *type)
496478 type -> tp_version_tag = 0 ; /* 0 is not a valid version tag */
497479}
498480
481+ void
482+ PyType_Modified (PyTypeObject * type )
483+ {
484+ _PyMutex_lock (& _PyRuntime .mutex );
485+ _PyType_ModifiedEx (type );
486+ _PyMutex_unlock (& _PyRuntime .mutex );
487+ }
488+
499489static void
500490type_mro_modified (PyTypeObject * type , PyObject * bases ) {
501491 /*
@@ -549,6 +539,23 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
549539 type -> tp_version_tag = 0 ; /* 0 is not a valid version tag */
550540}
551541
542+ static unsigned int
543+ advance_version_tag (void )
544+ {
545+ retry : ;
546+ unsigned int version_tag = _Py_atomic_load_uint_relaxed (& next_version_tag );
547+ if (version_tag == 0 ) {
548+ /* We have run out of version numbers */
549+ return 0 ;
550+ }
551+ if (!_Py_atomic_compare_exchange_uint (& next_version_tag ,
552+ version_tag ,
553+ version_tag + 1 )) {
554+ goto retry ;
555+ }
556+ return version_tag ;
557+ }
558+
552559static int
553560assign_version_tag (PyTypeObject * type )
554561{
@@ -564,11 +571,13 @@ assign_version_tag(PyTypeObject *type)
564571 return 0 ;
565572 }
566573
567- if (next_version_tag == 0 ) {
574+ unsigned int version_tag = advance_version_tag ();
575+ if (version_tag == 0 ) {
568576 /* We have run out of version numbers */
569577 return 0 ;
570578 }
571- type -> tp_version_tag = next_version_tag ++ ;
579+
580+ _Py_atomic_store_uint32_relaxed (& type -> tp_version_tag , version_tag );
572581 assert (type -> tp_version_tag != 0 );
573582
574583 PyObject * bases = type -> tp_bases ;
@@ -578,7 +587,8 @@ assign_version_tag(PyTypeObject *type)
578587 if (!assign_version_tag (_PyType_CAST (b )))
579588 return 0 ;
580589 }
581- type -> tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG ;
590+ _Py_atomic_store_ulong_relaxed (
591+ & type -> tp_flags , type -> tp_flags | Py_TPFLAGS_VALID_VERSION_TAG );
582592 return 1 ;
583593}
584594
@@ -4198,9 +4208,10 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
41984208 entry -> version = type -> tp_version_tag ;
41994209 entry -> value = res ; /* borrowed */
42004210 assert (_PyASCIIObject_CAST (name )-> hash != -1 );
4201- OBJECT_STAT_INC_COND (type_cache_collisions , entry -> name != Py_None && entry -> name != name );
4211+ OBJECT_STAT_INC_COND (type_cache_collisions , entry -> name != NULL && entry -> name != name );
42024212 assert (_PyType_HasFeature (type , Py_TPFLAGS_VALID_VERSION_TAG ));
4203- Py_SETREF (entry -> name , Py_NewRef (name ));
4213+ assert (_PyObject_IS_IMMORTAL (name ));
4214+ entry -> name = name ;
42044215 }
42054216 return res ;
42064217}
@@ -4374,7 +4385,9 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
43744385 PyType_Modified (type );
43754386
43764387 if (is_dunder_name (name )) {
4388+ _PyMutex_lock (& _PyRuntime .mutex );
43774389 res = update_slot (type , name );
4390+ _PyMutex_unlock (& _PyRuntime .mutex );
43784391 }
43794392 assert (_PyType_CheckConsistency (type ));
43804393 }
@@ -6992,6 +7005,15 @@ _PyStaticType_InitBuiltin(PyTypeObject *self)
69927005 return res ;
69937006}
69947007
7008+ static PyObject *
7009+ init_once (void * dst , PyObject * obj )
7010+ {
7011+ if (!_Py_atomic_compare_exchange_ptr (dst , NULL , obj )) {
7012+ Py_DECREF (obj );
7013+ obj = _Py_atomic_load_ptr (dst );
7014+ }
7015+ return obj ;
7016+ }
69957017
69967018static PyObject *
69977019init_subclasses (PyTypeObject * self )
@@ -7002,11 +7024,9 @@ init_subclasses(PyTypeObject *self)
70027024 }
70037025 if (self -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN ) {
70047026 static_builtin_state * state = _PyStaticType_GetState (self );
7005- state -> tp_subclasses = subclasses ;
7006- return subclasses ;
7027+ return init_once (& state -> tp_subclasses , subclasses );
70077028 }
7008- self -> tp_subclasses = (void * )subclasses ;
7009- return subclasses ;
7029+ return init_once (& self -> tp_subclasses , subclasses );
70107030}
70117031
70127032static void
@@ -9074,13 +9094,16 @@ update_all_slots(PyTypeObject* type)
90749094{
90759095 pytype_slotdef * p ;
90769096
9097+ _PyMutex_lock (& _PyRuntime .mutex );
9098+
90779099 /* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
9078- PyType_Modified (type );
9100+ _PyType_ModifiedEx (type );
90799101
90809102 for (p = slotdefs ; p -> name ; p ++ ) {
90819103 /* update_slot returns int but can't actually fail */
90829104 update_slot (type , p -> name_strobj );
90839105 }
9106+ _PyMutex_unlock (& _PyRuntime .mutex );
90849107}
90859108
90869109
0 commit comments