@@ -2069,7 +2069,7 @@ dummy_func(
20692069 };
20702070
20712071 specializing op (_SPECIALIZE_LOAD_ATTR , (counter /1 , owner -- owner )) {
2072- #if ENABLE_SPECIALIZATION
2072+ #if ENABLE_SPECIALIZATION_FT
20732073 if (ADAPTIVE_COUNTER_TRIGGERS (counter )) {
20742074 PyObject * name = GETITEM (FRAME_CO_NAMES , oparg >>1 );
20752075 next_instr = this_instr ;
@@ -2078,7 +2078,7 @@ dummy_func(
20782078 }
20792079 OPCODE_DEFERRED_INC (LOAD_ATTR );
20802080 ADVANCE_ADAPTIVE_COUNTER (this_instr [1 ].counter );
2081- #endif /* ENABLE_SPECIALIZATION */
2081+ #endif /* ENABLE_SPECIALIZATION_FT */
20822082 }
20832083
20842084 op (_LOAD_ATTR , (owner -- attr , self_or_null if (oparg & 1 ))) {
@@ -2157,33 +2157,44 @@ dummy_func(
21572157 _LOAD_ATTR_INSTANCE_VALUE +
21582158 unused /5 ; // Skip over rest of cache
21592159
2160- op (_CHECK_ATTR_MODULE , (dict_version /2 , owner -- owner )) {
2160+ op (_CHECK_ATTR_MODULE_PUSH_KEYS , (dict_version /2 , owner -- owner , mod_keys : PyDictKeysObject * )) {
21612161 PyObject * owner_o = PyStackRef_AsPyObjectBorrow (owner );
21622162 DEOPT_IF (Py_TYPE (owner_o )-> tp_getattro != PyModule_Type .tp_getattro );
21632163 PyDictObject * dict = (PyDictObject * )((PyModuleObject * )owner_o )-> md_dict ;
21642164 assert (dict != NULL );
2165- DEOPT_IF (dict -> ma_keys -> dk_version != dict_version );
2165+ PyDictKeysObject * keys = FT_ATOMIC_LOAD_PTR_ACQUIRE (dict -> ma_keys );
2166+ DEOPT_IF (FT_ATOMIC_LOAD_UINT32_RELAXED (keys -> dk_version ) != dict_version );
2167+ mod_keys = keys ;
21662168 }
21672169
2168- op (_LOAD_ATTR_MODULE , (index /1 , owner -- attr , null if (oparg & 1 ))) {
2169- PyObject * owner_o = PyStackRef_AsPyObjectBorrow (owner );
2170- PyDictObject * dict = (PyDictObject * )((PyModuleObject * )owner_o )-> md_dict ;
2171- assert (dict -> ma_keys -> dk_kind == DICT_KEYS_UNICODE );
2172- assert (index < dict -> ma_keys -> dk_nentries );
2173- PyDictUnicodeEntry * ep = DK_UNICODE_ENTRIES (dict -> ma_keys ) + index ;
2174- PyObject * attr_o = ep -> me_value ;
2170+ op (_LOAD_ATTR_MODULE_FROM_KEYS , (index /1 , owner , mod_keys : PyDictKeysObject * -- attr , null if (oparg & 1 ))) {
2171+ assert (mod_keys -> dk_kind == DICT_KEYS_UNICODE );
2172+ assert (index < FT_ATOMIC_LOAD_SSIZE_RELAXED (mod_keys -> dk_nentries ));
2173+ PyDictUnicodeEntry * ep = DK_UNICODE_ENTRIES (mod_keys ) + index ;
2174+ PyObject * attr_o = FT_ATOMIC_LOAD_PTR_RELAXED (ep -> me_value );
2175+ DEAD (mod_keys );
2176+ // Clear mod_keys from stack in case we need to deopt
2177+ SAVE_STACK ();
2178+ RELOAD_STACK ();
21752179 DEOPT_IF (attr_o == NULL );
2176- STAT_INC (LOAD_ATTR , hit );
2180+ #ifdef Py_GIL_DISABLED
2181+ int increfed = _Py_TryIncrefCompareStackRef (& ep -> me_value , attr_o , & attr );
2182+ if (!increfed ) {
2183+ DEOPT_IF (true);
2184+ }
2185+ #else
21772186 Py_INCREF (attr_o );
21782187 attr = PyStackRef_FromPyObjectSteal (attr_o );
2188+ #endif
2189+ STAT_INC (LOAD_ATTR , hit );
21792190 null = PyStackRef_NULL ;
2180- DECREF_INPUTS ( );
2191+ PyStackRef_CLOSE ( owner );
21812192 }
21822193
21832194 macro (LOAD_ATTR_MODULE ) =
21842195 unused /1 +
2185- _CHECK_ATTR_MODULE +
2186- _LOAD_ATTR_MODULE +
2196+ _CHECK_ATTR_MODULE_PUSH_KEYS +
2197+ _LOAD_ATTR_MODULE_FROM_KEYS +
21872198 unused /5 ;
21882199
21892200 op (_CHECK_ATTR_WITH_HINT , (owner -- owner )) {
@@ -4961,6 +4972,21 @@ dummy_func(
49614972 null = PyStackRef_NULL ;
49624973 }
49634974
4975+ tier2 op (_LOAD_ATTR_MODULE , (index /1 , owner -- attr , null if (oparg & 1 ))) {
4976+ PyObject * owner_o = PyStackRef_AsPyObjectBorrow (owner );
4977+ PyDictObject * dict = (PyDictObject * )((PyModuleObject * )owner_o )-> md_dict ;
4978+ assert (dict -> ma_keys -> dk_kind == DICT_KEYS_UNICODE );
4979+ assert (index < dict -> ma_keys -> dk_nentries );
4980+ PyDictUnicodeEntry * ep = DK_UNICODE_ENTRIES (dict -> ma_keys ) + index ;
4981+ PyObject * attr_o = ep -> me_value ;
4982+ DEOPT_IF (attr_o == NULL );
4983+ STAT_INC (LOAD_ATTR , hit );
4984+ Py_INCREF (attr_o );
4985+ attr = PyStackRef_FromPyObjectSteal (attr_o );
4986+ null = PyStackRef_NULL ;
4987+ DECREF_INPUTS ();
4988+ }
4989+
49644990 /* Internal -- for testing executors */
49654991 op (_INTERNAL_INCREMENT_OPT_COUNTER , (opt -- )) {
49664992 _PyCounterOptimizerObject * exe = (_PyCounterOptimizerObject * )PyStackRef_AsPyObjectBorrow (opt );
0 commit comments