@@ -1156,14 +1156,6 @@ type_modified_unlocked(PyTypeObject *type)
11561156 }
11571157 }
11581158
1159- set_version_unlocked (type , 0 ); /* 0 is not a valid version tag */
1160- if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
1161- // This field *must* be invalidated if the type is modified (see the
1162- // comment on struct _specialization_cache):
1163- FT_ATOMIC_STORE_PTR_RELAXED (
1164- ((PyHeapTypeObject * )type )-> _spec_cache .getitem , NULL );
1165- }
1166-
11671159 // Notify registered type watchers, if any
11681160 if (type -> tp_watched ) {
11691161 PyInterpreterState * interp = _PyInterpreterState_GET ();
@@ -1185,6 +1177,14 @@ type_modified_unlocked(PyTypeObject *type)
11851177 bits >>= 1 ;
11861178 }
11871179 }
1180+
1181+ set_version_unlocked (type , 0 ); /* 0 is not a valid version tag */
1182+ if (PyType_HasFeature (type , Py_TPFLAGS_HEAPTYPE )) {
1183+ // This field *must* be invalidated if the type is modified (see the
1184+ // comment on struct _specialization_cache):
1185+ FT_ATOMIC_STORE_PTR_RELAXED (
1186+ ((PyHeapTypeObject * )type )-> _spec_cache .getitem , NULL );
1187+ }
11881188}
11891189
11901190void
@@ -1238,21 +1238,14 @@ type_mro_modified(PyTypeObject *type, PyObject *bases)
12381238 Called from mro_internal, which will subsequently be called on
12391239 each subclass when their mro is recursively updated.
12401240 */
1241+ Py_ssize_t i , n ;
1242+
12411243 ASSERT_TYPE_LOCK_HELD ();
1242- if (!Py_IS_TYPE (type , & PyType_Type )) {
1243- unsigned int meta_version = Py_TYPE (type )-> tp_version_tag ;
1244- // This can be re-entrant.
1245- bool is_custom = has_custom_mro (type );
1246- if (meta_version != Py_TYPE (type )-> tp_version_tag ) {
1247- // metaclass changed during call of has_custom_mro()
1248- goto clear ;
1249- }
1250- if (is_custom ) {
1251- goto clear ;
1252- }
1244+ if (!Py_IS_TYPE (type , & PyType_Type ) && has_custom_mro (type )) {
1245+ goto clear ;
12531246 }
1254- Py_ssize_t n = PyTuple_GET_SIZE (bases );
1255- for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
1247+ n = PyTuple_GET_SIZE (bases );
1248+ for (i = 0 ; i < n ; i ++ ) {
12561249 PyObject * b = PyTuple_GET_ITEM (bases , i );
12571250 PyTypeObject * cls = _PyType_CAST (b );
12581251
@@ -5771,22 +5764,12 @@ update_cache(struct type_cache_entry *entry, PyObject *name, unsigned int versio
57715764 return old_name ;
57725765}
57735766
5767+ #if Py_GIL_DISABLED
5768+
57745769static void
5775- maybe_update_cache ( PyTypeObject * type , struct type_cache_entry * entry ,
5776- PyObject * name , unsigned int version_tag , PyObject * value )
5770+ update_cache_gil_disabled ( struct type_cache_entry * entry , PyObject * name ,
5771+ unsigned int version_tag , PyObject * value )
57775772{
5778- if (version_tag == 0 ) {
5779- return ; // 0 is not a valid version
5780- }
5781- // Calling find_name_in_mro() might cause the type version to change.
5782- // For example, if a __hash__ or __eq__ method mutates the types.
5783- // This case is expected to be rare but we check for it here and avoid
5784- // replacing a valid cache entry with a known to be stale one.
5785- if (FT_ATOMIC_LOAD_UINT_RELAXED (type -> tp_version_tag ) != version_tag ) {
5786- return ; // version changed during lookup
5787- }
5788- PyObject * old_value ;
5789- #ifdef Py_GIL_DISABLED
57905773 _PySeqLock_LockWrite (& entry -> sequence );
57915774
57925775 // update the entry
@@ -5798,16 +5781,16 @@ maybe_update_cache(PyTypeObject *type, struct type_cache_entry *entry,
57985781 return ;
57995782 }
58005783
5801- old_value = update_cache (entry , name , version_tag , value );
5784+ PyObject * old_value = update_cache (entry , name , version_tag , value );
58025785
58035786 // Then update sequence to the next valid value
58045787 _PySeqLock_UnlockWrite (& entry -> sequence );
5805- #else
5806- old_value = update_cache (entry , name , version_tag , value );
5807- #endif
5788+
58085789 Py_DECREF (old_value );
58095790}
58105791
5792+ #endif
5793+
58115794void
58125795_PyTypes_AfterFork (void )
58135796{
@@ -5825,22 +5808,23 @@ _PyTypes_AfterFork(void)
58255808#endif
58265809}
58275810
5828- // Try to assign a new type version tag, return it if successful. Return 0
5829- // if no version was assigned.
5830- static unsigned int
5831- type_assign_version (PyTypeObject * type )
5811+ /* Internal API to look for a name through the MRO.
5812+ This returns a strong reference, and doesn't set an exception!
5813+ If nonzero, version is set to the value of type->tp_version at the time of
5814+ the lookup.
5815+ */
5816+ PyObject *
5817+ _PyType_LookupRefAndVersion (PyTypeObject * type , PyObject * name , unsigned int * version )
58325818{
5833- unsigned int version = type -> tp_version_tag ;
5834- if (version == 0 ) {
5835- PyInterpreterState * interp = _PyInterpreterState_GET ();
5836- if (assign_version_tag (interp , type )) {
5837- version = type -> tp_version_tag ;
5838- }
5839- else {
5840- version = 0 ;
5841- }
5819+ _PyStackRef out ;
5820+ unsigned int ver = _PyType_LookupStackRefAndVersion (type , name , & out );
5821+ if (version ) {
5822+ * version = ver ;
58425823 }
5843- return version ;
5824+ if (PyStackRef_IsNull (out )) {
5825+ return NULL ;
5826+ }
5827+ return PyStackRef_AsPyObjectSteal (out );
58445828}
58455829
58465830unsigned int
@@ -5896,12 +5880,15 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
58965880
58975881 PyObject * res ;
58985882 int error ;
5899- unsigned int assigned_version = 0 ; // 0 is not a valid version
5883+ PyInterpreterState * interp = _PyInterpreterState_GET ();
5884+ int has_version = 0 ;
5885+ unsigned int assigned_version = 0 ;
59005886 BEGIN_TYPE_LOCK ();
5887+ res = find_name_in_mro (type , name , & error );
59015888 if (MCACHE_CACHEABLE_NAME (name )) {
5902- assigned_version = type_assign_version (type );
5889+ has_version = assign_version_tag (interp , type );
5890+ assigned_version = type -> tp_version_tag ;
59035891 }
5904- res = find_name_in_mro (type , name , & error );
59055892 END_TYPE_LOCK ();
59065893
59075894 /* Only put NULL results into cache if there was no error. */
@@ -5920,28 +5907,17 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
59205907 * out = PyStackRef_NULL ;
59215908 return 0 ;
59225909 }
5923- maybe_update_cache (type , entry , name , assigned_version , res );
5924- * out = res ? PyStackRef_FromPyObjectSteal (res ) : PyStackRef_NULL ;
5925- return assigned_version ;
5926- }
59275910
5928- /* Internal API to look for a name through the MRO.
5929- This returns a strong reference, and doesn't set an exception!
5930- If nonzero, version is set to the value of type->tp_version at the time of
5931- the lookup.
5932- */
5933- PyObject *
5934- _PyType_LookupRefAndVersion (PyTypeObject * type , PyObject * name , unsigned int * version )
5935- {
5936- _PyStackRef out ;
5937- unsigned int ver = _PyType_LookupStackRefAndVersion (type , name , & out );
5938- if (version ) {
5939- * version = ver ;
5940- }
5941- if (PyStackRef_IsNull (out )) {
5942- return NULL ;
5911+ if (has_version ) {
5912+ #if Py_GIL_DISABLED
5913+ update_cache_gil_disabled (entry , name , assigned_version , res );
5914+ #else
5915+ PyObject * old_value = update_cache (entry , name , assigned_version , res );
5916+ Py_DECREF (old_value );
5917+ #endif
59435918 }
5944- return PyStackRef_AsPyObjectSteal (out );
5919+ * out = res ? PyStackRef_FromPyObjectSteal (res ) : PyStackRef_NULL ;
5920+ return has_version ? assigned_version : 0 ;
59455921}
59465922
59475923/* Internal API to look for a name through the MRO.
0 commit comments