@@ -1039,14 +1039,6 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
10391039 }
10401040}
10411041
1042- typedef enum {
1043- MANAGED_VALUES = 1 ,
1044- MANAGED_DICT = 2 ,
1045- OFFSET_DICT = 3 ,
1046- NO_DICT = 4 ,
1047- LAZY_DICT = 5 ,
1048- } ObjectDictKind ;
1049-
10501042// Please collect stats carefully before and after modifying. A subtle change
10511043// can cause a significant drop in cache hits. A possible test is
10521044// python.exe -m test_typing test_re test_dis test_zlib.
@@ -1058,71 +1050,45 @@ PyObject *descr, DescriptorClassification kind)
10581050 PyTypeObject * owner_cls = Py_TYPE (owner );
10591051
10601052 assert (kind == METHOD && descr != NULL );
1061- ObjectDictKind dictkind ;
1062- PyDictKeysObject * keys ;
10631053 if (owner_cls -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) {
10641054 PyDictOrValues dorv = * _PyObject_DictOrValuesPointer (owner );
1065- keys = ((PyHeapTypeObject * )owner_cls )-> ht_cached_keys ;
1066- if (_PyDictOrValues_IsValues (dorv )) {
1067- dictkind = MANAGED_VALUES ;
1068- }
1069- else {
1070- dictkind = MANAGED_DICT ;
1071- }
1072- }
1073- else {
1074- Py_ssize_t dictoffset = owner_cls -> tp_dictoffset ;
1075- if (dictoffset < 0 || dictoffset > INT16_MAX ) {
1076- SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_OUT_OF_RANGE );
1077- goto fail ;
1078- }
1079- if (dictoffset == 0 ) {
1080- dictkind = NO_DICT ;
1081- keys = NULL ;
1082- }
1083- else {
1084- PyObject * dict = * (PyObject * * ) ((char * )owner + dictoffset );
1085- if (dict == NULL ) {
1086- // This object will have a dict if user access __dict__
1087- dictkind = LAZY_DICT ;
1088- keys = NULL ;
1089- }
1090- else {
1091- keys = ((PyDictObject * )dict )-> ma_keys ;
1092- dictkind = OFFSET_DICT ;
1093- }
1055+ PyDictKeysObject * keys = ((PyHeapTypeObject * )owner_cls )-> ht_cached_keys ;
1056+ if (!_PyDictOrValues_IsValues (dorv )) {
1057+ SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_ATTR_HAS_MANAGED_DICT );
1058+ return 0 ;
10941059 }
1095- }
1096- if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT ) {
10971060 Py_ssize_t index = _PyDictKeys_StringLookup (keys , name );
10981061 if (index != DKIX_EMPTY ) {
10991062 SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_ATTR_SHADOWED );
1100- goto fail ;
1063+ return 0 ;
11011064 }
11021065 uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState (keys );
11031066 if (keys_version == 0 ) {
11041067 SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_OUT_OF_VERSIONS );
1105- goto fail ;
1068+ return 0 ;
11061069 }
11071070 write_u32 (cache -> keys_version , keys_version );
1071+ _py_set_opcode (instr , LOAD_ATTR_METHOD_WITH_VALUES );
11081072 }
1109- switch (dictkind ) {
1110- case NO_DICT :
1073+ else {
1074+ Py_ssize_t dictoffset = owner_cls -> tp_dictoffset ;
1075+ if (dictoffset < 0 || dictoffset > INT16_MAX ) {
1076+ SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_OUT_OF_RANGE );
1077+ return 0 ;
1078+ }
1079+ if (dictoffset == 0 ) {
11111080 _py_set_opcode (instr , LOAD_ATTR_METHOD_NO_DICT );
1112- break ;
1113- case MANAGED_VALUES :
1114- _py_set_opcode (instr , LOAD_ATTR_METHOD_WITH_VALUES );
1115- break ;
1116- case MANAGED_DICT :
1117- SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_ATTR_HAS_MANAGED_DICT );
1118- goto fail ;
1119- case OFFSET_DICT :
1120- SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_ATTR_NOT_MANAGED_DICT );
1121- goto fail ;
1122- case LAZY_DICT :
1123- assert (owner_cls -> tp_dictoffset > 0 && owner_cls -> tp_dictoffset <= INT16_MAX );
1081+ }
1082+ else {
1083+ PyObject * dict = * (PyObject * * ) ((char * )owner + dictoffset );
1084+ if (dict ) {
1085+ SPECIALIZATION_FAIL (LOAD_ATTR , SPEC_FAIL_ATTR_NOT_MANAGED_DICT );
1086+ return 0 ;
1087+ }
1088+ assert (owner_cls -> tp_dictoffset > 0 );
1089+ assert (owner_cls -> tp_dictoffset <= INT16_MAX );
11241090 _py_set_opcode (instr , LOAD_ATTR_METHOD_LAZY_DICT );
1125- break ;
1091+ }
11261092 }
11271093 /* `descr` is borrowed. This is safe for methods (even inherited ones from
11281094 * super classes!) as long as tp_version_tag is validated for two main reasons:
@@ -1141,8 +1107,6 @@ PyObject *descr, DescriptorClassification kind)
11411107 write_u32 (cache -> type_version , owner_cls -> tp_version_tag );
11421108 write_obj (cache -> descr , descr );
11431109 return 1 ;
1144- fail :
1145- return 0 ;
11461110}
11471111
11481112void
0 commit comments