22#include "Python.h"
33#include "pycore_code.h"
44#include "pycore_dict.h"
5+ #include "pycore_long.h"
56#include "pycore_moduleobject.h"
67#include "opcode.h"
78#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
@@ -46,6 +47,24 @@ print_stats(SpecializationStats *stats, const char *name)
4647 PRINT_STAT (name , deferred );
4748 PRINT_STAT (name , miss );
4849 PRINT_STAT (name , deopt );
50+ #if SPECIALIZATION_STATS_DETAILED
51+ if (stats -> miss_types == NULL ) {
52+ return ;
53+ }
54+ fprintf (stderr , " %s.fails:\n" , name );
55+ PyObject * key , * count ;
56+ Py_ssize_t pos = 0 ;
57+ while (PyDict_Next (stats -> miss_types , & pos , & key , & count )) {
58+ PyObject * type = PyTuple_GetItem (key , 0 );
59+ PyObject * name = PyTuple_GetItem (key , 1 );
60+ PyObject * kind = PyTuple_GetItem (key , 2 );
61+ fprintf (stderr , " %s." , ((PyTypeObject * )type )-> tp_name );
62+ PyObject_Print (name , stderr , Py_PRINT_RAW );
63+ fprintf (stderr , " (" );
64+ PyObject_Print (kind , stderr , Py_PRINT_RAW );
65+ fprintf (stderr , "): %ld\n" , PyLong_AsLong (count ));
66+ }
67+ #endif
4968}
5069
5170void
@@ -56,6 +75,57 @@ _Py_PrintSpecializationStats(void)
5675 print_stats (& _specialization_stats [LOAD_GLOBAL ], "load_global" );
5776}
5877
78+ #if SPECIALIZATION_STATS_DETAILED
79+ void
80+ _Py_IncrementTypeCounter (int opcode , PyObject * type , PyObject * name , const char * kind )
81+ {
82+ PyObject * counter = _specialization_stats [opcode ].miss_types ;
83+ if (counter == NULL ) {
84+ _specialization_stats [opcode ].miss_types = PyDict_New ();
85+ counter = _specialization_stats [opcode ].miss_types ;
86+ if (counter == NULL ) {
87+ return ;
88+ }
89+ }
90+ PyObject * key = NULL ;
91+ PyObject * kind_object = _PyUnicode_FromASCII (kind , strlen (kind ));
92+ if (kind_object == NULL ) {
93+ PyErr_Clear ();
94+ goto done ;
95+ }
96+ key = PyTuple_Pack (3 , type , name , kind_object );
97+ if (key == NULL ) {
98+ PyErr_Clear ();
99+ goto done ;
100+ }
101+ PyObject * count = PyDict_GetItem (counter , key );
102+ if (count == NULL ) {
103+ count = _PyLong_GetZero ();
104+ if (PyDict_SetItem (counter , key , count ) < 0 ) {
105+ PyErr_Clear ();
106+ goto done ;
107+ }
108+ }
109+ count = PyNumber_Add (count , _PyLong_GetOne ());
110+ if (count == NULL ) {
111+ PyErr_Clear ();
112+ goto done ;
113+ }
114+ if (PyDict_SetItem (counter , key , count )) {
115+ PyErr_Clear ();
116+ }
117+ done :
118+ Py_XDECREF (kind_object );
119+ Py_XDECREF (key );
120+ }
121+
122+ #define SPECIALIZATION_FAIL (opcode , type , attribute , kind ) _Py_IncrementTypeCounter(opcode, (PyObject *)(type), attribute, kind)
123+
124+ #endif
125+ #endif
126+
127+ #ifndef SPECIALIZATION_FAIL
128+ #define SPECIALIZATION_FAIL (opcode , type , attribute , kind ) ((void)0)
59129#endif
60130
61131static SpecializedCacheOrInstruction *
@@ -243,28 +313,34 @@ specialize_module_load_attr(
243313 _Py_IDENTIFIER (__getattr__ );
244314 PyDictObject * dict = (PyDictObject * )m -> md_dict ;
245315 if (dict == NULL ) {
316+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no __dict__" );
246317 return -1 ;
247318 }
248319 if (dict -> ma_keys -> dk_kind != DICT_KEYS_UNICODE ) {
320+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "non-string keys (or split)" );
249321 return -1 ;
250322 }
251323 getattr = _PyUnicode_FromId (& PyId___getattr__ ); /* borrowed */
252324 if (getattr == NULL ) {
325+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "module.__getattr__ overridden" );
253326 PyErr_Clear ();
254327 return -1 ;
255328 }
256329 Py_ssize_t index = _PyDict_GetItemHint (dict , getattr , -1 , & value );
257330 assert (index != DKIX_ERROR );
258331 if (index != DKIX_EMPTY ) {
332+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "module attribute not found" );
259333 return -1 ;
260334 }
261335 index = _PyDict_GetItemHint (dict , name , -1 , & value );
262336 assert (index != DKIX_ERROR );
263337 if (index != (uint16_t )index ) {
338+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "index out of range" );
264339 return -1 ;
265340 }
266341 uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState (dict );
267342 if (keys_version == 0 ) {
343+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no more key versions" );
268344 return -1 ;
269345 }
270346 cache1 -> dk_version_or_hint = keys_version ;
@@ -287,6 +363,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
287363 }
288364 PyTypeObject * type = Py_TYPE (owner );
289365 if (type -> tp_getattro != PyObject_GenericGetAttr ) {
366+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "__getattribute__ overridden" );
290367 goto fail ;
291368 }
292369 if (type -> tp_dict == NULL ) {
@@ -299,17 +376,19 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
299376 // We found an attribute with a data-like descriptor.
300377 PyTypeObject * dtype = Py_TYPE (descr );
301378 if (dtype != & PyMemberDescr_Type ) {
379+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "not a member descriptor" );
302380 goto fail ;
303381 }
304382 // It's a slot
305383 PyMemberDescrObject * member = (PyMemberDescrObject * )descr ;
306384 struct PyMemberDef * dmem = member -> d_member ;
307385 if (dmem -> type != T_OBJECT_EX ) {
308- // It's a slot of a different type. We don't handle those.
386+ SPECIALIZATION_FAIL ( LOAD_ATTR , Py_TYPE ( owner ), name , "non-object slot" );
309387 goto fail ;
310388 }
311389 Py_ssize_t offset = dmem -> offset ;
312390 if (offset != (uint16_t )offset ) {
391+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "offset out of range" );
313392 goto fail ;
314393 }
315394 assert (offset > 0 );
@@ -320,11 +399,12 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
320399 }
321400 // No desciptor
322401 if (type -> tp_dictoffset <= 0 ) {
323- // No dictionary, or computed offset dictionary
402+ SPECIALIZATION_FAIL ( LOAD_ATTR , Py_TYPE ( owner ), name , "no dict or negative offset" );
324403 goto fail ;
325404 }
326405 PyObject * * dictptr = (PyObject * * ) ((char * )owner + type -> tp_dictoffset );
327406 if (* dictptr == NULL || !PyDict_CheckExact (* dictptr )) {
407+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no dict or not a dict" );
328408 goto fail ;
329409 }
330410 // We found an instance with a __dict__.
@@ -342,10 +422,12 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
342422 Py_ssize_t index = _Py_dict_lookup (dict , name , hash , & value );
343423 assert (index != DKIX_ERROR );
344424 if (index != (uint16_t )index ) {
425+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "index out of range" );
345426 goto fail ;
346427 }
347428 uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState (dict );
348429 if (keys_version == 0 ) {
430+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no more key versions" );
349431 goto fail ;
350432 }
351433 cache1 -> dk_version_or_hint = keys_version ;
@@ -359,6 +441,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
359441 Py_ssize_t hint =
360442 _PyDict_GetItemHint (dict , name , -1 , & value );
361443 if (hint != (uint32_t )hint ) {
444+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "hint out of range" );
362445 goto fail ;
363446 }
364447 cache1 -> dk_version_or_hint = (uint32_t )hint ;
0 commit comments