2
2
#include "Python.h"
3
3
#include "pycore_code.h"
4
4
#include "pycore_dict.h"
5
+ #include "pycore_long.h"
5
6
#include "pycore_moduleobject.h"
6
7
#include "opcode.h"
7
8
#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
@@ -46,6 +47,24 @@ print_stats(SpecializationStats *stats, const char *name)
46
47
PRINT_STAT (name , deferred );
47
48
PRINT_STAT (name , miss );
48
49
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
49
68
}
50
69
51
70
void
@@ -56,6 +75,57 @@ _Py_PrintSpecializationStats(void)
56
75
print_stats (& _specialization_stats [LOAD_GLOBAL ], "load_global" );
57
76
}
58
77
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)
59
129
#endif
60
130
61
131
static SpecializedCacheOrInstruction *
@@ -243,28 +313,34 @@ specialize_module_load_attr(
243
313
_Py_IDENTIFIER (__getattr__ );
244
314
PyDictObject * dict = (PyDictObject * )m -> md_dict ;
245
315
if (dict == NULL ) {
316
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no __dict__" );
246
317
return -1 ;
247
318
}
248
319
if (dict -> ma_keys -> dk_kind != DICT_KEYS_UNICODE ) {
320
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "non-string keys (or split)" );
249
321
return -1 ;
250
322
}
251
323
getattr = _PyUnicode_FromId (& PyId___getattr__ ); /* borrowed */
252
324
if (getattr == NULL ) {
325
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "module.__getattr__ overridden" );
253
326
PyErr_Clear ();
254
327
return -1 ;
255
328
}
256
329
Py_ssize_t index = _PyDict_GetItemHint (dict , getattr , -1 , & value );
257
330
assert (index != DKIX_ERROR );
258
331
if (index != DKIX_EMPTY ) {
332
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "module attribute not found" );
259
333
return -1 ;
260
334
}
261
335
index = _PyDict_GetItemHint (dict , name , -1 , & value );
262
336
assert (index != DKIX_ERROR );
263
337
if (index != (uint16_t )index ) {
338
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "index out of range" );
264
339
return -1 ;
265
340
}
266
341
uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState (dict );
267
342
if (keys_version == 0 ) {
343
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no more key versions" );
268
344
return -1 ;
269
345
}
270
346
cache1 -> dk_version_or_hint = keys_version ;
@@ -287,6 +363,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
287
363
}
288
364
PyTypeObject * type = Py_TYPE (owner );
289
365
if (type -> tp_getattro != PyObject_GenericGetAttr ) {
366
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "__getattribute__ overridden" );
290
367
goto fail ;
291
368
}
292
369
if (type -> tp_dict == NULL ) {
@@ -299,17 +376,19 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
299
376
// We found an attribute with a data-like descriptor.
300
377
PyTypeObject * dtype = Py_TYPE (descr );
301
378
if (dtype != & PyMemberDescr_Type ) {
379
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "not a member descriptor" );
302
380
goto fail ;
303
381
}
304
382
// It's a slot
305
383
PyMemberDescrObject * member = (PyMemberDescrObject * )descr ;
306
384
struct PyMemberDef * dmem = member -> d_member ;
307
385
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" );
309
387
goto fail ;
310
388
}
311
389
Py_ssize_t offset = dmem -> offset ;
312
390
if (offset != (uint16_t )offset ) {
391
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "offset out of range" );
313
392
goto fail ;
314
393
}
315
394
assert (offset > 0 );
@@ -320,11 +399,12 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
320
399
}
321
400
// No desciptor
322
401
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" );
324
403
goto fail ;
325
404
}
326
405
PyObject * * dictptr = (PyObject * * ) ((char * )owner + type -> tp_dictoffset );
327
406
if (* dictptr == NULL || !PyDict_CheckExact (* dictptr )) {
407
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no dict or not a dict" );
328
408
goto fail ;
329
409
}
330
410
// We found an instance with a __dict__.
@@ -342,10 +422,12 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
342
422
Py_ssize_t index = _Py_dict_lookup (dict , name , hash , & value );
343
423
assert (index != DKIX_ERROR );
344
424
if (index != (uint16_t )index ) {
425
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "index out of range" );
345
426
goto fail ;
346
427
}
347
428
uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState (dict );
348
429
if (keys_version == 0 ) {
430
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "no more key versions" );
349
431
goto fail ;
350
432
}
351
433
cache1 -> dk_version_or_hint = keys_version ;
@@ -359,6 +441,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
359
441
Py_ssize_t hint =
360
442
_PyDict_GetItemHint (dict , name , -1 , & value );
361
443
if (hint != (uint32_t )hint ) {
444
+ SPECIALIZATION_FAIL (LOAD_ATTR , Py_TYPE (owner ), name , "hint out of range" );
362
445
goto fail ;
363
446
}
364
447
cache1 -> dk_version_or_hint = (uint32_t )hint ;
0 commit comments