@@ -1007,9 +1007,11 @@ specialize_dict_access(
10071007 return 1 ;
10081008}
10091009
1010- #ifndef Py_GIL_DISABLED
1011- static int specialize_attr_loadclassattr (PyObject * owner , _Py_CODEUNIT * instr , PyObject * name ,
1012- PyObject * descr , DescriptorClassification kind , bool is_method );
1010+ static int
1011+ specialize_attr_loadclassattr (PyObject * owner , _Py_CODEUNIT * instr ,
1012+ PyObject * name , PyObject * descr ,
1013+ DescriptorClassification kind , bool is_method ,
1014+ uint32_t shared_keys_version );
10131015static int specialize_class_load_attr (PyObject * owner , _Py_CODEUNIT * instr , PyObject * name );
10141016
10151017/* Returns true if instances of obj's class are
@@ -1018,15 +1020,16 @@ static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyOb
10181020 * For other objects, we check their actual dictionary.
10191021 */
10201022static bool
1021- instance_has_key (PyObject * obj , PyObject * name )
1023+ instance_has_key (PyObject * obj , PyObject * name , uint32_t * shared_keys_version )
10221024{
10231025 PyTypeObject * cls = Py_TYPE (obj );
10241026 if ((cls -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) == 0 ) {
10251027 return false;
10261028 }
10271029 if (cls -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
10281030 PyDictKeysObject * keys = ((PyHeapTypeObject * )cls )-> ht_cached_keys ;
1029- Py_ssize_t index = _PyDictKeys_StringLookup (keys , name );
1031+ Py_ssize_t index =
1032+ _PyDictKeys_StringLookupAndVersion (keys , name , shared_keys_version );
10301033 return index >= 0 ;
10311034 }
10321035 PyDictObject * dict = _PyObject_GetManagedDict (obj );
@@ -1048,7 +1051,9 @@ specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* na
10481051{
10491052 _PyAttrCache * cache = (_PyAttrCache * )(instr + 1 );
10501053 PyTypeObject * type = Py_TYPE (owner );
1051- bool shadow = instance_has_key (owner , name );
1054+ // 0 is not a valid version
1055+ uint32_t shared_keys_version = 0 ;
1056+ bool shadow = instance_has_key (owner , name , & shared_keys_version );
10521057 PyObject * descr = NULL ;
10531058 DescriptorClassification kind = analyze_descriptor (type , name , & descr , 0 );
10541059 assert (descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN );
@@ -1066,7 +1071,9 @@ specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* na
10661071 }
10671072 int oparg = instr -> op .arg ;
10681073 if (oparg & 1 ) {
1069- if (specialize_attr_loadclassattr (owner , instr , name , descr , kind , true)) {
1074+ if (specialize_attr_loadclassattr (owner , instr , name , descr ,
1075+ kind , true,
1076+ shared_keys_version )) {
10701077 return 0 ;
10711078 }
10721079 else {
@@ -1188,7 +1195,9 @@ specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* na
11881195 goto try_instance ;
11891196 }
11901197 if ((instr -> op .arg & 1 ) == 0 ) {
1191- if (specialize_attr_loadclassattr (owner , instr , name , descr , kind , false)) {
1198+ if (specialize_attr_loadclassattr (owner , instr , name , descr ,
1199+ kind , false,
1200+ shared_keys_version )) {
11921201 return 0 ;
11931202 }
11941203 }
@@ -1209,7 +1218,6 @@ specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* na
12091218 }
12101219 return -1 ;
12111220}
1212- #endif // Py_GIL_DISABLED
12131221
12141222void
12151223_Py_Specialize_LoadAttr (_PyStackRef owner_st , _Py_CODEUNIT * instr , PyObject * name )
@@ -1239,12 +1247,7 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam
12391247 #endif
12401248 }
12411249 else {
1242- #ifdef Py_GIL_DISABLED
1243- SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_EXPECTED_ERROR );
1244- fail = true;
1245- #else
12461250 fail = specialize_instance_load_attr (owner , instr , name );
1247- #endif
12481251 }
12491252
12501253 if (fail ) {
@@ -1458,24 +1461,26 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
14581461// can cause a significant drop in cache hits. A possible test is
14591462// python.exe -m test_typing test_re test_dis test_zlib.
14601463static int
1461- specialize_attr_loadclassattr (PyObject * owner , _Py_CODEUNIT * instr , PyObject * name ,
1462- PyObject * descr , DescriptorClassification kind , bool is_method )
1464+ specialize_attr_loadclassattr (PyObject * owner , _Py_CODEUNIT * instr ,
1465+ PyObject * name , PyObject * descr ,
1466+ DescriptorClassification kind , bool is_method ,
1467+ uint32_t shared_keys_version )
14631468{
14641469 _PyLoadMethodCache * cache = (_PyLoadMethodCache * )(instr + 1 );
14651470 PyTypeObject * owner_cls = Py_TYPE (owner );
14661471
14671472 assert (descr != NULL );
14681473 assert ((is_method && kind == METHOD ) || (!is_method && kind == NON_DESCRIPTOR ));
14691474 if (owner_cls -> tp_flags & Py_TPFLAGS_INLINE_VALUES ) {
1475+ #ifndef Py_GIL_DISABLED
14701476 PyDictKeysObject * keys = ((PyHeapTypeObject * )owner_cls )-> ht_cached_keys ;
14711477 assert (_PyDictKeys_StringLookup (keys , name ) < 0 );
1472- uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState (
1473- _PyInterpreterState_GET (), keys );
1474- if (keys_version == 0 ) {
1478+ #endif
1479+ if (shared_keys_version == 0 ) {
14751480 SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_OUT_OF_VERSIONS );
14761481 return 0 ;
14771482 }
1478- write_u32 (cache -> keys_version , keys_version );
1483+ write_u32 (cache -> keys_version , shared_keys_version );
14791484 specialize (instr , is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES );
14801485 }
14811486 else {
0 commit comments