@@ -52,8 +52,8 @@ class object "PyObject *" "&PyBaseObject_Type"
5252 MCACHE_HASH(FT_ATOMIC_LOAD_UINT_RELAXED((type)->tp_version_tag), \
5353 ((Py_ssize_t)(name)) >> 3)
5454#define MCACHE_CACHEABLE_NAME (name ) \
55- PyUnicode_CheckExact(name) && \
56- (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
55+ ( PyUnicode_CheckExact(name) && \
56+ (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE) )
5757
5858#define NEXT_VERSION_TAG (interp ) \
5959 (interp)->types.next_version_tag
@@ -6134,6 +6134,21 @@ _PyType_LookupRefAndVersion(PyTypeObject *type, PyObject *name, unsigned int *ve
61346134 return PyStackRef_AsPyObjectSteal (out );
61356135}
61366136
6137+ static int
6138+ should_assign_version_tag (PyTypeObject * type , PyObject * name , unsigned int version_tag )
6139+ {
6140+ if (version_tag != 0 ) {
6141+ return 0 ;
6142+ }
6143+ if (FT_ATOMIC_LOAD_UINT16_RELAXED (type -> tp_versions_used ) >= MAX_VERSIONS_PER_CLASS ) {
6144+ return 0 ;
6145+ }
6146+ if (!MCACHE_CACHEABLE_NAME (name )) {
6147+ return 0 ;
6148+ }
6149+ return 1 ;
6150+ }
6151+
61376152unsigned int
61386153_PyType_LookupStackRefAndVersion (PyTypeObject * type , PyObject * name , _PyStackRef * out )
61396154{
@@ -6187,36 +6202,37 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
61876202
61886203 int res ;
61896204 PyInterpreterState * interp = _PyInterpreterState_GET ();
6190- int has_version = 0 ;
6191- unsigned int assigned_version = 0 ;
61926205
6193- BEGIN_TYPE_LOCK ();
6194- // We must assign the version before doing the lookup. If
6195- // find_name_in_mro() blocks and releases the critical section
6196- // then the type version can change.
6197- if (MCACHE_CACHEABLE_NAME (name )) {
6198- has_version = assign_version_tag (interp , type );
6199- assigned_version = type -> tp_version_tag ;
6200- }
6201- res = find_name_in_mro (type , name , out );
6202- END_TYPE_LOCK ();
6206+ unsigned int version_tag = FT_ATOMIC_LOAD_UINT (type -> tp_version_tag );
6207+ if (should_assign_version_tag (type , name , version_tag )) {
6208+ BEGIN_TYPE_LOCK ();
6209+ assign_version_tag (interp , type );
6210+ version_tag = type -> tp_version_tag ;
6211+ res = find_name_in_mro (type , name , out );
6212+ END_TYPE_LOCK ();
6213+ }
6214+ else {
6215+ res = find_name_in_mro (type , name , out );
6216+ }
62036217
62046218 /* Only put NULL results into cache if there was no error. */
62056219 if (res < 0 ) {
62066220 * out = PyStackRef_NULL ;
62076221 return 0 ;
62086222 }
62096223
6210- if (has_version ) {
6211- PyObject * res_obj = PyStackRef_AsPyObjectBorrow (* out );
6224+ if (version_tag == 0 || !MCACHE_CACHEABLE_NAME (name )) {
6225+ return 0 ;
6226+ }
6227+
6228+ PyObject * res_obj = PyStackRef_AsPyObjectBorrow (* out );
62126229#if Py_GIL_DISABLED
6213- update_cache_gil_disabled (entry , name , assigned_version , res_obj );
6230+ update_cache_gil_disabled (entry , name , version_tag , res_obj );
62146231#else
6215- PyObject * old_value = update_cache (entry , name , assigned_version , res_obj );
6216- Py_DECREF (old_value );
6232+ PyObject * old_value = update_cache (entry , name , version_tag , res_obj );
6233+ Py_DECREF (old_value );
62176234#endif
6218- }
6219- return has_version ? assigned_version : 0 ;
6235+ return version_tag ;
62206236}
62216237
62226238/* Internal API to look for a name through the MRO.
0 commit comments