@@ -47,27 +47,37 @@ class object "PyObject *" "&PyBaseObject_Type"
4747static inline unsigned int
4848mcache_name_hash (PyTypeObject * type , PyObject * name )
4949{
50- unsigned int name_hash ;
50+ Py_hash_t name_hash ;
5151#if Py_GIL_DISABLED
5252 // Cache misses are relatively more expensive for the free-threaded build.
5353 // So we use the unicode string hash and unicode compare for caching
5454 // names. This allows caching of non-interned strings.
55- if (PyUnicode_CheckExact (name )) {
56- name_hash = (unsigned int )_PyObject_HashFast (name );
57- }
58- else {
59- name_hash = 0 ;
60- }
55+ assert (PyUnicode_CheckExact (name ));
56+ name_hash = _PyObject_HashFast (name );
57+ // should not fail to hash an exact unicode object
58+ assert (name_hash != -1 );
6159#else
6260 // Use the pointer value of the string for the hash and the compare. This
6361 // is faster but non-interned strings can't use the cache.
64- name_hash = ((Py_ssize_t )(name )) >> 3 ;
62+ name_hash = ((Py_hash_t )(name )) >> 3 ;
6563#endif
6664 unsigned int version = FT_ATOMIC_LOAD_UINT32_RELAXED ((type )-> tp_version_tag );
6765 return (((unsigned int )(version ) ^ (unsigned int )(name_hash )) &
6866 ((1 << MCACHE_SIZE_EXP ) - 1 ));
6967}
7068
69+ static inline struct type_cache_entry *
70+ mcache_get_entry (PyTypeObject * type , PyObject * name , struct type_cache * cache )
71+ {
72+ #ifdef Py_GIL_DISABLED
73+ if (!PyUnicode_CheckExact (name )) {
74+ return NULL ;
75+ }
76+ #endif
77+ unsigned int h = mcache_name_hash (type , name );
78+ return & cache -> hashtable [h ];
79+ }
80+
7181static inline int
7282mcache_name_eq (PyObject * entry_name , PyObject * name )
7383{
@@ -76,7 +86,7 @@ mcache_name_eq(PyObject *entry_name, PyObject *name)
7686 return 0 ;
7787 }
7888 assert (PyUnicode_CheckExact (entry_name ));
79- assert (PyUnicode_Check (name ));
89+ assert (PyUnicode_CheckExact (name ));
8090 return _PyUnicode_Equal (entry_name , name );
8191#else
8292 return entry_name == name ;
@@ -5754,12 +5764,11 @@ _PyType_LookupRefAndVersion(PyTypeObject *type, PyObject *name, unsigned int *ve
57545764unsigned int
57555765_PyType_LookupStackRefAndVersion (PyTypeObject * type , PyObject * name , _PyStackRef * out )
57565766{
5757- unsigned int h = mcache_name_hash (type , name );
57585767 struct type_cache * cache = get_type_cache ();
5759- struct type_cache_entry * entry = & cache -> hashtable [ h ] ;
5768+ struct type_cache_entry * entry = mcache_get_entry ( type , name , cache ) ;
57605769#ifdef Py_GIL_DISABLED
57615770 // synchronize-with other writing threads by doing an acquire load on the sequence
5762- while (1 ) {
5771+ while (entry != NULL ) {
57635772 uint32_t sequence = _PySeqLock_BeginRead (& entry -> sequence );
57645773 uint32_t entry_version = _Py_atomic_load_uint32_acquire (& entry -> version );
57655774 uint32_t type_version = _Py_atomic_load_uint32_acquire (& type -> tp_version_tag );
@@ -5837,6 +5846,7 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
58375846
58385847 if (has_version ) {
58395848#if Py_GIL_DISABLED
5849+ assert (entry != NULL );
58405850 update_cache_gil_disabled (entry , name , assigned_version , res );
58415851#else
58425852 PyObject * old_value = update_cache (entry , name , assigned_version , res );
0 commit comments