@@ -51,8 +51,8 @@ class object "PyObject *" "&PyBaseObject_Type"
5151 MCACHE_HASH(FT_ATOMIC_LOAD_UINT32_RELAXED((type)->tp_version_tag), \
5252 ((Py_ssize_t)(name)) >> 3)
5353#define MCACHE_CACHEABLE_NAME (name ) \
54- PyUnicode_CheckExact(name) && \
55- (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
54+ ( PyUnicode_CheckExact(name) && \
55+ (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE) )
5656
5757#define NEXT_VERSION_TAG (interp ) \
5858 (interp)->types.next_version_tag
@@ -5860,6 +5860,14 @@ _PyType_LookupRefAndVersion(PyTypeObject *type, PyObject *name, unsigned int *ve
58605860 return PyStackRef_AsPyObjectSteal (out );
58615861}
58625862
5863+ static int
5864+ should_assign_version_tag (PyTypeObject * type , PyObject * name , unsigned int version_tag )
5865+ {
5866+ return (version_tag == 0
5867+ && FT_ATOMIC_LOAD_UINT16_RELAXED (type -> tp_versions_used ) < MAX_VERSIONS_PER_CLASS
5868+ && MCACHE_CACHEABLE_NAME (name ));
5869+ }
5870+
58635871unsigned int
58645872_PyType_LookupStackRefAndVersion (PyTypeObject * type , PyObject * name , _PyStackRef * out )
58655873{
@@ -5908,41 +5916,39 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
59085916 /* We may end up clearing live exceptions below, so make sure it's ours. */
59095917 assert (!PyErr_Occurred ());
59105918
5911- // We need to atomically do the lookup and capture the version before
5912- // anyone else can modify our mro or mutate the type.
5913-
59145919 int res ;
59155920 PyInterpreterState * interp = _PyInterpreterState_GET ();
5916- int has_version = 0 ;
5917- unsigned int assigned_version = 0 ;
59185921
5919- BEGIN_TYPE_LOCK ();
5920- // We must assign the version before doing the lookup. If
5921- // find_name_in_mro() blocks and releases the critical section
5922- // then the type version can change.
5923- if (MCACHE_CACHEABLE_NAME (name )) {
5924- has_version = assign_version_tag (interp , type );
5925- assigned_version = type -> tp_version_tag ;
5926- }
5927- res = find_name_in_mro (type , name , out );
5928- END_TYPE_LOCK ();
5922+ unsigned int version_tag = FT_ATOMIC_LOAD_UINT (type -> tp_version_tag );
5923+ if (should_assign_version_tag (type , name , version_tag )) {
5924+ BEGIN_TYPE_LOCK ();
5925+ assign_version_tag (interp , type );
5926+ version_tag = type -> tp_version_tag ;
5927+ res = find_name_in_mro (type , name , out );
5928+ END_TYPE_LOCK ();
5929+ }
5930+ else {
5931+ res = find_name_in_mro (type , name , out );
5932+ }
59295933
59305934 /* Only put NULL results into cache if there was no error. */
59315935 if (res < 0 ) {
59325936 * out = PyStackRef_NULL ;
59335937 return 0 ;
59345938 }
59355939
5936- if (has_version ) {
5937- PyObject * res_obj = PyStackRef_AsPyObjectBorrow (* out );
5940+ if (version_tag == 0 || !MCACHE_CACHEABLE_NAME (name )) {
5941+ return 0 ;
5942+ }
5943+
5944+ PyObject * res_obj = PyStackRef_AsPyObjectBorrow (* out );
59385945#if Py_GIL_DISABLED
5939- update_cache_gil_disabled (entry , name , assigned_version , res_obj );
5946+ update_cache_gil_disabled (entry , name , version_tag , res_obj );
59405947#else
5941- PyObject * old_value = update_cache (entry , name , assigned_version , res_obj );
5942- Py_DECREF (old_value );
5948+ PyObject * old_value = update_cache (entry , name , version_tag , res_obj );
5949+ Py_DECREF (old_value );
59435950#endif
5944- }
5945- return has_version ? assigned_version : 0 ;
5951+ return version_tag ;
59465952}
59475953
59485954/* Internal API to look for a name through the MRO.
0 commit comments