Branch data Line data Source code
1 : : #include "Python.h"
2 : : #include "pycore_code.h"
3 : : #include "pycore_dict.h"
4 : : #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState()
5 : : #include "pycore_global_strings.h" // _Py_ID()
6 : : #include "pycore_long.h"
7 : : #include "pycore_moduleobject.h"
8 : : #include "pycore_object.h"
9 : : #include "pycore_opcode.h" // _PyOpcode_Caches
10 : : #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
11 : : #include "pycore_descrobject.h"
12 : :
13 : : #include <stdlib.h> // rand()
14 : :
15 : : /* For guidance on adding or extending families of instructions see
16 : : * ./adaptive.md
17 : : */
18 : :
19 : : #ifdef Py_STATS
20 : : PyStats _py_stats_struct = { 0 };
21 : : PyStats *_py_stats = NULL;
22 : :
23 : : #define ADD_STAT_TO_DICT(res, field) \
24 : : do { \
25 : : PyObject *val = PyLong_FromUnsignedLongLong(stats->field); \
26 : : if (val == NULL) { \
27 : : Py_DECREF(res); \
28 : : return NULL; \
29 : : } \
30 : : if (PyDict_SetItemString(res, #field, val) == -1) { \
31 : : Py_DECREF(res); \
32 : : Py_DECREF(val); \
33 : : return NULL; \
34 : : } \
35 : : Py_DECREF(val); \
36 : : } while(0);
37 : :
38 : : static PyObject*
39 : : stats_to_dict(SpecializationStats *stats)
40 : : {
41 : : PyObject *res = PyDict_New();
42 : : if (res == NULL) {
43 : : return NULL;
44 : : }
45 : : ADD_STAT_TO_DICT(res, success);
46 : : ADD_STAT_TO_DICT(res, failure);
47 : : ADD_STAT_TO_DICT(res, hit);
48 : : ADD_STAT_TO_DICT(res, deferred);
49 : : ADD_STAT_TO_DICT(res, miss);
50 : : ADD_STAT_TO_DICT(res, deopt);
51 : : PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS);
52 : : if (failure_kinds == NULL) {
53 : : Py_DECREF(res);
54 : : return NULL;
55 : : }
56 : : for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) {
57 : : PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]);
58 : : if (stat == NULL) {
59 : : Py_DECREF(res);
60 : : Py_DECREF(failure_kinds);
61 : : return NULL;
62 : : }
63 : : PyTuple_SET_ITEM(failure_kinds, i, stat);
64 : : }
65 : : if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) {
66 : : Py_DECREF(res);
67 : : Py_DECREF(failure_kinds);
68 : : return NULL;
69 : : }
70 : : Py_DECREF(failure_kinds);
71 : : return res;
72 : : }
73 : : #undef ADD_STAT_TO_DICT
74 : :
75 : : static int
76 : : add_stat_dict(
77 : : PyObject *res,
78 : : int opcode,
79 : : const char *name) {
80 : :
81 : : SpecializationStats *stats = &_py_stats_struct.opcode_stats[opcode].specialization;
82 : : PyObject *d = stats_to_dict(stats);
83 : : if (d == NULL) {
84 : : return -1;
85 : : }
86 : : int err = PyDict_SetItemString(res, name, d);
87 : : Py_DECREF(d);
88 : : return err;
89 : : }
90 : :
91 : : #ifdef Py_STATS
92 : : PyObject*
93 : : _Py_GetSpecializationStats(void) {
94 : : PyObject *stats = PyDict_New();
95 : : if (stats == NULL) {
96 : : return NULL;
97 : : }
98 : : int err = 0;
99 : : err += add_stat_dict(stats, LOAD_ATTR, "load_attr");
100 : : err += add_stat_dict(stats, LOAD_GLOBAL, "load_global");
101 : : err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr");
102 : : err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr");
103 : : err += add_stat_dict(stats, STORE_ATTR, "store_attr");
104 : : err += add_stat_dict(stats, CALL, "call");
105 : : err += add_stat_dict(stats, BINARY_OP, "binary_op");
106 : : err += add_stat_dict(stats, COMPARE_OP, "compare_op");
107 : : err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence");
108 : : err += add_stat_dict(stats, FOR_ITER, "for_iter");
109 : : if (err < 0) {
110 : : Py_DECREF(stats);
111 : : return NULL;
112 : : }
113 : : return stats;
114 : : }
115 : : #endif
116 : :
117 : :
118 : : #define PRINT_STAT(i, field) \
119 : : if (stats[i].field) { \
120 : : fprintf(out, " opcode[%d]." #field " : %" PRIu64 "\n", i, stats[i].field); \
121 : : }
122 : :
123 : : static void
124 : : print_spec_stats(FILE *out, OpcodeStats *stats)
125 : : {
126 : : /* Mark some opcodes as specializable for stats,
127 : : * even though we don't specialize them yet. */
128 : : fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE);
129 : : fprintf(out, "opcode[%d].specializable : 1\n", COMPARE_OP);
130 : : fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE);
131 : : fprintf(out, "opcode[%d].specializable : 1\n", SEND);
132 : : for (int i = 0; i < 256; i++) {
133 : : if (_PyOpcode_Caches[i]) {
134 : : fprintf(out, "opcode[%d].specializable : 1\n", i);
135 : : }
136 : : PRINT_STAT(i, specialization.success);
137 : : PRINT_STAT(i, specialization.failure);
138 : : PRINT_STAT(i, specialization.hit);
139 : : PRINT_STAT(i, specialization.deferred);
140 : : PRINT_STAT(i, specialization.miss);
141 : : PRINT_STAT(i, specialization.deopt);
142 : : PRINT_STAT(i, execution_count);
143 : : for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) {
144 : : uint64_t val = stats[i].specialization.failure_kinds[j];
145 : : if (val) {
146 : : fprintf(out, " opcode[%d].specialization.failure_kinds[%d] : %"
147 : : PRIu64 "\n", i, j, val);
148 : : }
149 : : }
150 : : for(int j = 0; j < 256; j++) {
151 : : if (stats[i].pair_count[j]) {
152 : : fprintf(out, "opcode[%d].pair_count[%d] : %" PRIu64 "\n",
153 : : i, j, stats[i].pair_count[j]);
154 : : }
155 : : }
156 : : }
157 : : }
158 : : #undef PRINT_STAT
159 : :
160 : :
161 : : static void
162 : : print_call_stats(FILE *out, CallStats *stats)
163 : : {
164 : : fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls);
165 : : fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls);
166 : : fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed);
167 : : fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created);
168 : : for (int i = 0; i < EVAL_CALL_KINDS; i++) {
169 : : fprintf(out, "Calls via PyEval_EvalFrame[%d] : %" PRIu64 "\n", i, stats->eval_calls[i]);
170 : : }
171 : : }
172 : :
173 : : static void
174 : : print_object_stats(FILE *out, ObjectStats *stats)
175 : : {
176 : : fprintf(out, "Object allocations from freelist: %" PRIu64 "\n", stats->from_freelist);
177 : : fprintf(out, "Object frees to freelist: %" PRIu64 "\n", stats->to_freelist);
178 : : fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations);
179 : : fprintf(out, "Object allocations to 512 bytes: %" PRIu64 "\n", stats->allocations512);
180 : : fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k);
181 : : fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big);
182 : : fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees);
183 : : fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values);
184 : : fprintf(out, "Object interpreter increfs: %" PRIu64 "\n", stats->interpreter_increfs);
185 : : fprintf(out, "Object interpreter decrefs: %" PRIu64 "\n", stats->interpreter_decrefs);
186 : : fprintf(out, "Object increfs: %" PRIu64 "\n", stats->increfs);
187 : : fprintf(out, "Object decrefs: %" PRIu64 "\n", stats->decrefs);
188 : : fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request);
189 : : fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
190 : : fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
191 : : fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
192 : : fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits);
193 : : fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses);
194 : : fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
195 : : fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits);
196 : : fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses);
197 : : }
198 : :
199 : : static void
200 : : print_stats(FILE *out, PyStats *stats) {
201 : : print_spec_stats(out, stats->opcode_stats);
202 : : print_call_stats(out, &stats->call_stats);
203 : : print_object_stats(out, &stats->object_stats);
204 : : }
205 : :
206 : : void
207 : : _Py_StatsClear(void)
208 : : {
209 : : _py_stats_struct = (PyStats) { 0 };
210 : : }
211 : :
212 : : void
213 : : _Py_PrintSpecializationStats(int to_file)
214 : : {
215 : : FILE *out = stderr;
216 : : if (to_file) {
217 : : /* Write to a file instead of stderr. */
218 : : # ifdef MS_WINDOWS
219 : : const char *dirname = "c:\\temp\\py_stats\\";
220 : : # else
221 : : const char *dirname = "/tmp/py_stats/";
222 : : # endif
223 : : /* Use random 160 bit number as file name,
224 : : * to avoid both accidental collisions and
225 : : * symlink attacks. */
226 : : unsigned char rand[20];
227 : : char hex_name[41];
228 : : _PyOS_URandomNonblock(rand, 20);
229 : : for (int i = 0; i < 20; i++) {
230 : : hex_name[2*i] = "0123456789abcdef"[rand[i]&15];
231 : : hex_name[2*i+1] = "0123456789abcdef"[(rand[i]>>4)&15];
232 : : }
233 : : hex_name[40] = '\0';
234 : : char buf[64];
235 : : assert(strlen(dirname) + 40 + strlen(".txt") < 64);
236 : : sprintf(buf, "%s%s.txt", dirname, hex_name);
237 : : FILE *fout = fopen(buf, "w");
238 : : if (fout) {
239 : : out = fout;
240 : : }
241 : : }
242 : : else {
243 : : fprintf(out, "Specialization stats:\n");
244 : : }
245 : : print_stats(out, &_py_stats_struct);
246 : : if (out != stderr) {
247 : : fclose(out);
248 : : }
249 : : }
250 : :
251 : : #ifdef Py_STATS
252 : :
253 : : #define SPECIALIZATION_FAIL(opcode, kind) \
254 : : do { \
255 : : if (_py_stats) { \
256 : : _py_stats->opcode_stats[opcode].specialization.failure_kinds[kind]++; \
257 : : } \
258 : : } while (0)
259 : :
260 : : #endif
261 : : #endif
262 : :
263 : : #ifndef SPECIALIZATION_FAIL
264 : : #define SPECIALIZATION_FAIL(opcode, kind) ((void)0)
265 : : #endif
266 : :
267 : : static int compare_masks[] = {
268 : : [Py_LT] = COMPARISON_LESS_THAN,
269 : : [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS,
270 : : [Py_EQ] = COMPARISON_EQUALS,
271 : : [Py_NE] = COMPARISON_NOT_EQUALS,
272 : : [Py_GT] = COMPARISON_GREATER_THAN,
273 : : [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS,
274 : : };
275 : :
276 : : // Initialize warmup counters and insert superinstructions. This cannot fail.
277 : : void
278 : 32254 : _PyCode_Quicken(PyCodeObject *code)
279 : : {
280 : : #if ENABLE_SPECIALIZATION
281 : 32254 : int opcode = 0;
282 : 32254 : _Py_CODEUNIT *instructions = _PyCode_CODE(code);
283 [ + + ]: 1358558 : for (int i = 0; i < Py_SIZE(code); i++) {
284 : 1326304 : int previous_opcode = opcode;
285 : 1326304 : opcode = _PyOpcode_Deopt[instructions[i].op.code];
286 : 1326304 : int caches = _PyOpcode_Caches[opcode];
287 [ + + ]: 1326304 : if (caches) {
288 : 332738 : instructions[i + 1].cache = adaptive_counter_warmup();
289 : 332738 : i += caches;
290 : 332738 : continue;
291 : : }
292 [ + + + + : 993566 : switch (previous_opcode << 8 | opcode) {
+ + + ]
293 : 11586 : case LOAD_CONST << 8 | LOAD_FAST:
294 : 11586 : instructions[i - 1].op.code = LOAD_CONST__LOAD_FAST;
295 : 11586 : break;
296 : 16486 : case LOAD_FAST << 8 | LOAD_CONST:
297 : 16486 : instructions[i - 1].op.code = LOAD_FAST__LOAD_CONST;
298 : 16486 : break;
299 : 33022 : case LOAD_FAST << 8 | LOAD_FAST:
300 : 33022 : instructions[i - 1].op.code = LOAD_FAST__LOAD_FAST;
301 : 33022 : break;
302 : 25228 : case STORE_FAST << 8 | LOAD_FAST:
303 : 25228 : instructions[i - 1].op.code = STORE_FAST__LOAD_FAST;
304 : 25228 : break;
305 : 5281 : case STORE_FAST << 8 | STORE_FAST:
306 : 5281 : instructions[i - 1].op.code = STORE_FAST__STORE_FAST;
307 : 5281 : break;
308 : 2674 : case COMPARE_OP << 8 | POP_JUMP_IF_TRUE:
309 : : case COMPARE_OP << 8 | POP_JUMP_IF_FALSE:
310 : : {
311 : 2674 : int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.arg;
312 : : assert((oparg >> 4) <= Py_GE);
313 : 2674 : int mask = compare_masks[oparg >> 4];
314 [ + + ]: 2674 : if (opcode == POP_JUMP_IF_FALSE) {
315 : 2295 : mask = mask ^ 0xf;
316 : : }
317 : 2674 : instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.code = COMPARE_AND_BRANCH;
318 : 2674 : instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.arg = (oparg & 0xf0) | mask;
319 : 2674 : break;
320 : : }
321 : : }
322 : 1326304 : }
323 : : #endif /* ENABLE_SPECIALIZATION */
324 : 32254 : }
325 : :
326 : : #define SIMPLE_FUNCTION 0
327 : :
328 : : /* Common */
329 : :
330 : : #define SPEC_FAIL_OTHER 0
331 : : #define SPEC_FAIL_NO_DICT 1
332 : : #define SPEC_FAIL_OVERRIDDEN 2
333 : : #define SPEC_FAIL_OUT_OF_VERSIONS 3
334 : : #define SPEC_FAIL_OUT_OF_RANGE 4
335 : : #define SPEC_FAIL_EXPECTED_ERROR 5
336 : : #define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 6
337 : : #define SPEC_FAIL_CODE_COMPLEX_PARAMETERS 7
338 : : #define SPEC_FAIL_CODE_NOT_OPTIMIZED 8
339 : :
340 : :
341 : : #define SPEC_FAIL_LOAD_GLOBAL_NON_DICT 17
342 : : #define SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT 18
343 : :
344 : : /* Attributes */
345 : :
346 : : #define SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR 9
347 : : #define SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR 10
348 : : #define SPEC_FAIL_ATTR_NOT_DESCRIPTOR 11
349 : : #define SPEC_FAIL_ATTR_METHOD 12
350 : : #define SPEC_FAIL_ATTR_MUTABLE_CLASS 13
351 : : #define SPEC_FAIL_ATTR_PROPERTY 14
352 : : #define SPEC_FAIL_ATTR_NON_OBJECT_SLOT 15
353 : : #define SPEC_FAIL_ATTR_READ_ONLY 16
354 : : #define SPEC_FAIL_ATTR_AUDITED_SLOT 17
355 : : #define SPEC_FAIL_ATTR_NOT_MANAGED_DICT 18
356 : : #define SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT 19
357 : : #define SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND 20
358 : :
359 : : #define SPEC_FAIL_ATTR_SHADOWED 21
360 : : #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
361 : : #define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23
362 : : #define SPEC_FAIL_ATTR_OBJECT_SLOT 24
363 : : #define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25
364 : : #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26
365 : : #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27
366 : : #define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28
367 : : #define SPEC_FAIL_ATTR_NOT_IN_KEYS 29
368 : : #define SPEC_FAIL_ATTR_NOT_IN_DICT 30
369 : : #define SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE 31
370 : : #define SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR 32
371 : : #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ 33
372 : :
373 : : /* Binary subscr and store subscr */
374 : :
375 : : #define SPEC_FAIL_SUBSCR_ARRAY_INT 9
376 : : #define SPEC_FAIL_SUBSCR_ARRAY_SLICE 10
377 : : #define SPEC_FAIL_SUBSCR_LIST_SLICE 11
378 : : #define SPEC_FAIL_SUBSCR_TUPLE_SLICE 12
379 : : #define SPEC_FAIL_SUBSCR_STRING_INT 13
380 : : #define SPEC_FAIL_SUBSCR_STRING_SLICE 14
381 : : #define SPEC_FAIL_SUBSCR_BUFFER_INT 15
382 : : #define SPEC_FAIL_SUBSCR_BUFFER_SLICE 16
383 : : #define SPEC_FAIL_SUBSCR_SEQUENCE_INT 17
384 : :
385 : : /* Store subscr */
386 : : #define SPEC_FAIL_SUBSCR_BYTEARRAY_INT 18
387 : : #define SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE 19
388 : : #define SPEC_FAIL_SUBSCR_PY_SIMPLE 20
389 : : #define SPEC_FAIL_SUBSCR_PY_OTHER 21
390 : : #define SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE 22
391 : : #define SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE 23
392 : :
393 : : /* Binary op */
394 : :
395 : : #define SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES 9
396 : : #define SPEC_FAIL_BINARY_OP_ADD_OTHER 10
397 : : #define SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES 11
398 : : #define SPEC_FAIL_BINARY_OP_AND_INT 12
399 : : #define SPEC_FAIL_BINARY_OP_AND_OTHER 13
400 : : #define SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE 14
401 : : #define SPEC_FAIL_BINARY_OP_LSHIFT 15
402 : : #define SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY 16
403 : : #define SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES 17
404 : : #define SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER 18
405 : : #define SPEC_FAIL_BINARY_OP_OR 19
406 : : #define SPEC_FAIL_BINARY_OP_POWER 20
407 : : #define SPEC_FAIL_BINARY_OP_REMAINDER 21
408 : : #define SPEC_FAIL_BINARY_OP_RSHIFT 22
409 : : #define SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES 23
410 : : #define SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER 24
411 : : #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES 25
412 : : #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT 26
413 : : #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER 27
414 : : #define SPEC_FAIL_BINARY_OP_XOR 28
415 : :
416 : : /* Calls */
417 : :
418 : : #define SPEC_FAIL_CALL_INSTANCE_METHOD 11
419 : : #define SPEC_FAIL_CALL_CMETHOD 12
420 : : #define SPEC_FAIL_CALL_CFUNC_VARARGS 13
421 : : #define SPEC_FAIL_CALL_CFUNC_VARARGS_KEYWORDS 14
422 : : #define SPEC_FAIL_CALL_CFUNC_NOARGS 15
423 : : #define SPEC_FAIL_CALL_CFUNC_METHOD_FASTCALL_KEYWORDS 16
424 : : #define SPEC_FAIL_CALL_METH_DESCR_VARARGS 17
425 : : #define SPEC_FAIL_CALL_METH_DESCR_VARARGS_KEYWORDS 18
426 : : #define SPEC_FAIL_CALL_METH_DESCR_METHOD_FASTCALL_KEYWORDS 19
427 : : #define SPEC_FAIL_CALL_BAD_CALL_FLAGS 20
428 : : #define SPEC_FAIL_CALL_PYTHON_CLASS 21
429 : : #define SPEC_FAIL_CALL_PEP_523 22
430 : : #define SPEC_FAIL_CALL_BOUND_METHOD 23
431 : : #define SPEC_FAIL_CALL_STR 24
432 : : #define SPEC_FAIL_CALL_CLASS_NO_VECTORCALL 25
433 : : #define SPEC_FAIL_CALL_CLASS_MUTABLE 26
434 : : #define SPEC_FAIL_CALL_KWNAMES 27
435 : : #define SPEC_FAIL_CALL_METHOD_WRAPPER 28
436 : : #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29
437 : :
438 : : /* COMPARE_OP */
439 : : #define SPEC_FAIL_COMPARE_DIFFERENT_TYPES 12
440 : : #define SPEC_FAIL_COMPARE_STRING 13
441 : : #define SPEC_FAIL_COMPARE_NOT_FOLLOWED_BY_COND_JUMP 14
442 : : #define SPEC_FAIL_COMPARE_BIG_INT 15
443 : : #define SPEC_FAIL_COMPARE_BYTES 16
444 : : #define SPEC_FAIL_COMPARE_TUPLE 17
445 : : #define SPEC_FAIL_COMPARE_LIST 18
446 : : #define SPEC_FAIL_COMPARE_SET 19
447 : : #define SPEC_FAIL_COMPARE_BOOL 20
448 : : #define SPEC_FAIL_COMPARE_BASEOBJECT 21
449 : : #define SPEC_FAIL_COMPARE_FLOAT_LONG 22
450 : : #define SPEC_FAIL_COMPARE_LONG_FLOAT 23
451 : : #define SPEC_FAIL_COMPARE_EXTENDED_ARG 24
452 : :
453 : : /* FOR_ITER */
454 : : #define SPEC_FAIL_FOR_ITER_GENERATOR 10
455 : : #define SPEC_FAIL_FOR_ITER_COROUTINE 11
456 : : #define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12
457 : : #define SPEC_FAIL_FOR_ITER_LIST 13
458 : : #define SPEC_FAIL_FOR_ITER_TUPLE 14
459 : : #define SPEC_FAIL_FOR_ITER_SET 15
460 : : #define SPEC_FAIL_FOR_ITER_STRING 16
461 : : #define SPEC_FAIL_FOR_ITER_BYTES 17
462 : : #define SPEC_FAIL_FOR_ITER_RANGE 18
463 : : #define SPEC_FAIL_FOR_ITER_ITERTOOLS 19
464 : : #define SPEC_FAIL_FOR_ITER_DICT_KEYS 20
465 : : #define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21
466 : : #define SPEC_FAIL_FOR_ITER_DICT_VALUES 22
467 : : #define SPEC_FAIL_FOR_ITER_ENUMERATE 23
468 : : #define SPEC_FAIL_FOR_ITER_MAP 24
469 : : #define SPEC_FAIL_FOR_ITER_ZIP 25
470 : : #define SPEC_FAIL_FOR_ITER_SEQ_ITER 26
471 : : #define SPEC_FAIL_FOR_ITER_REVERSED_LIST 27
472 : : #define SPEC_FAIL_FOR_ITER_CALLABLE 28
473 : : #define SPEC_FAIL_FOR_ITER_ASCII_STRING 29
474 : :
475 : : // UNPACK_SEQUENCE
476 : :
477 : : #define SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR 9
478 : : #define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 10
479 : :
480 : : static int function_kind(PyCodeObject *code);
481 : : static bool function_check_args(PyObject *o, int expected_argcount, int opcode);
482 : : static uint32_t function_get_version(PyObject *o, int opcode);
483 : :
484 : : static int
485 : 2964 : specialize_module_load_attr(
486 : : PyObject *owner, _Py_CODEUNIT *instr, PyObject *name
487 : : ) {
488 : 2964 : _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
489 : 2964 : PyModuleObject *m = (PyModuleObject *)owner;
490 : : assert((owner->ob_type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
491 : 2964 : PyDictObject *dict = (PyDictObject *)m->md_dict;
492 [ - + ]: 2964 : if (dict == NULL) {
493 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NO_DICT);
494 : 0 : return -1;
495 : : }
496 [ - + ]: 2964 : if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
497 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT);
498 : 0 : return -1;
499 : : }
500 : 2964 : Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__));
501 : : assert(index != DKIX_ERROR);
502 [ + + ]: 2964 : if (index != DKIX_EMPTY) {
503 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND);
504 : 6 : return -1;
505 : : }
506 : 2958 : index = _PyDict_LookupIndex(dict, name);
507 : : assert (index != DKIX_ERROR);
508 [ + + ]: 2958 : if (index != (uint16_t)index) {
509 : : SPECIALIZATION_FAIL(LOAD_ATTR,
510 : : index == DKIX_EMPTY ?
511 : : SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND :
512 : : SPEC_FAIL_OUT_OF_RANGE);
513 : 222 : return -1;
514 : : }
515 : 2736 : uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(
516 : : _PyInterpreterState_GET(), dict->ma_keys);
517 [ - + ]: 2736 : if (keys_version == 0) {
518 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
519 : 0 : return -1;
520 : : }
521 : 2736 : write_u32(cache->version, keys_version);
522 : 2736 : cache->index = (uint16_t)index;
523 : 2736 : instr->op.code = LOAD_ATTR_MODULE;
524 : 2736 : return 0;
525 : : }
526 : :
527 : :
528 : :
529 : : /* Attribute specialization */
530 : :
531 : : typedef enum {
532 : : OVERRIDING, /* Is an overriding descriptor, and will remain so. */
533 : : METHOD, /* Attribute has Py_TPFLAGS_METHOD_DESCRIPTOR set */
534 : : PROPERTY, /* Is a property */
535 : : OBJECT_SLOT, /* Is an object slot descriptor */
536 : : OTHER_SLOT, /* Is a slot descriptor of another type */
537 : : NON_OVERRIDING, /* Is another non-overriding descriptor, and is an instance of an immutable class*/
538 : : BUILTIN_CLASSMETHOD, /* Builtin methods with METH_CLASS */
539 : : PYTHON_CLASSMETHOD, /* Python classmethod(func) object */
540 : : NON_DESCRIPTOR, /* Is not a descriptor, and is an instance of an immutable class */
541 : : MUTABLE, /* Instance of a mutable class; might, or might not, be a descriptor */
542 : : ABSENT, /* Attribute is not present on the class */
543 : : DUNDER_CLASS, /* __class__ attribute */
544 : : GETSET_OVERRIDDEN, /* __getattribute__ or __setattr__ has been overridden */
545 : : GETATTRIBUTE_IS_PYTHON_FUNCTION /* Descriptor requires calling a Python __getattribute__ */
546 : : } DescriptorClassification;
547 : :
548 : :
549 : : static DescriptorClassification
550 : 22308 : analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store)
551 : : {
552 : 22308 : bool has_getattr = false;
553 [ + + ]: 22308 : if (store) {
554 [ + + ]: 8757 : if (type->tp_setattro != PyObject_GenericSetAttr) {
555 : 205 : *descr = NULL;
556 : 205 : return GETSET_OVERRIDDEN;
557 : : }
558 : : }
559 : : else {
560 : 13551 : getattrofunc getattro_slot = type->tp_getattro;
561 [ + + ]: 13551 : if (getattro_slot == PyObject_GenericGetAttr) {
562 : : /* Normal attribute lookup; */
563 : 13017 : has_getattr = false;
564 : : }
565 [ + + - + ]: 534 : else if (getattro_slot == _Py_slot_tp_getattr_hook ||
566 : 61 : getattro_slot == _Py_slot_tp_getattro) {
567 : : /* One or both of __getattribute__ or __getattr__ may have been
568 : : overridden See typeobject.c for why these functions are special. */
569 : 61 : PyObject *getattribute = _PyType_Lookup(type,
570 : : &_Py_ID(__getattribute__));
571 : 61 : PyInterpreterState *interp = _PyInterpreterState_GET();
572 [ + - ]: 122 : bool has_custom_getattribute = getattribute != NULL &&
573 [ - + ]: 61 : getattribute != interp->callable_cache.object__getattribute__;
574 : 61 : has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL;
575 [ - + ]: 61 : if (has_custom_getattribute) {
576 [ # # ]: 0 : if (getattro_slot == _Py_slot_tp_getattro &&
577 [ # # # # ]: 0 : !has_getattr &&
578 : 0 : Py_IS_TYPE(getattribute, &PyFunction_Type)) {
579 : 0 : *descr = getattribute;
580 : 0 : return GETATTRIBUTE_IS_PYTHON_FUNCTION;
581 : : }
582 : : /* Potentially both __getattr__ and __getattribute__ are set.
583 : : Too complicated */
584 : 0 : *descr = NULL;
585 : 0 : return GETSET_OVERRIDDEN;
586 : : }
587 : : /* Potentially has __getattr__ but no custom __getattribute__.
588 : : Fall through to usual descriptor analysis.
589 : : Usual attribute lookup should only be allowed at runtime
590 : : if we can guarantee that there is no way an exception can be
591 : : raised. This means some specializations, e.g. specializing
592 : : for property() isn't safe.
593 : : */
594 : : }
595 : : else {
596 : 473 : *descr = NULL;
597 : 473 : return GETSET_OVERRIDDEN;
598 : : }
599 : : }
600 : 21630 : PyObject *descriptor = _PyType_Lookup(type, name);
601 : 21630 : *descr = descriptor;
602 [ + + ]: 21630 : if (descriptor == NULL) {
603 : 15038 : return ABSENT;
604 : : }
605 : 6592 : PyTypeObject *desc_cls = Py_TYPE(descriptor);
606 [ + + ]: 6592 : if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) {
607 : 11 : return MUTABLE;
608 : : }
609 [ + + ]: 6581 : if (desc_cls->tp_descr_set) {
610 [ + + ]: 1546 : if (desc_cls == &PyMemberDescr_Type) {
611 : 948 : PyMemberDescrObject *member = (PyMemberDescrObject *)descriptor;
612 : 948 : struct PyMemberDef *dmem = member->d_member;
613 [ + + ]: 948 : if (dmem->type == T_OBJECT_EX) {
614 : 141 : return OBJECT_SLOT;
615 : : }
616 : 807 : return OTHER_SLOT;
617 : : }
618 [ + + ]: 598 : if (desc_cls == &PyProperty_Type) {
619 : : /* We can't detect at runtime whether an attribute exists
620 : : with property. So that means we may have to call
621 : : __getattr__. */
622 [ - + ]: 170 : return has_getattr ? GETSET_OVERRIDDEN : PROPERTY;
623 : : }
624 [ + + ]: 428 : if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) {
625 [ + - ]: 27 : if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) {
626 : 27 : return DUNDER_CLASS;
627 : : }
628 : : }
629 [ + + ]: 401 : if (store) {
630 : 59 : return OVERRIDING;
631 : : }
632 : : }
633 [ + + ]: 5377 : if (desc_cls->tp_descr_get) {
634 [ + + ]: 4877 : if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) {
635 : 3773 : return METHOD;
636 : : }
637 [ + + ]: 1104 : if (Py_IS_TYPE(descriptor, &PyClassMethodDescr_Type)) {
638 : 135 : return BUILTIN_CLASSMETHOD;
639 : : }
640 [ + + ]: 969 : if (Py_IS_TYPE(descriptor, &PyClassMethod_Type)) {
641 : 439 : return PYTHON_CLASSMETHOD;
642 : : }
643 : 530 : return NON_OVERRIDING;
644 : : }
645 : 500 : return NON_DESCRIPTOR;
646 : : }
647 : :
648 : : static int
649 : 15038 : specialize_dict_access(
650 : : PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type,
651 : : DescriptorClassification kind, PyObject *name,
652 : : int base_op, int values_op, int hint_op)
653 : : {
654 : : assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT ||
655 : : kind == BUILTIN_CLASSMETHOD || kind == PYTHON_CLASSMETHOD);
656 : : // No descriptor, or non overriding.
657 [ + + ]: 15038 : if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
658 : : SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
659 : 344 : return 0;
660 : : }
661 : 14694 : _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
662 : 14694 : PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
663 [ + + ]: 14694 : if (_PyDictOrValues_IsValues(dorv)) {
664 : : // Virtual dictionary
665 : 4007 : PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
666 : : assert(PyUnicode_CheckExact(name));
667 : 4007 : Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
668 : : assert (index != DKIX_ERROR);
669 [ + + ]: 4007 : if (index != (uint16_t)index) {
670 : : SPECIALIZATION_FAIL(base_op,
671 : : index == DKIX_EMPTY ?
672 : : SPEC_FAIL_ATTR_NOT_IN_KEYS :
673 : : SPEC_FAIL_OUT_OF_RANGE);
674 : 83 : return 0;
675 : : }
676 : 3924 : write_u32(cache->version, type->tp_version_tag);
677 : 3924 : cache->index = (uint16_t)index;
678 : 3924 : instr->op.code = values_op;
679 : : }
680 : : else {
681 : 10687 : PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
682 [ + + - + ]: 10687 : if (dict == NULL || !PyDict_CheckExact(dict)) {
683 : : SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
684 : 91 : return 0;
685 : : }
686 : : // We found an instance with a __dict__.
687 : : Py_ssize_t index =
688 : 10596 : _PyDict_LookupIndex(dict, name);
689 [ - + ]: 10596 : if (index != (uint16_t)index) {
690 : : SPECIALIZATION_FAIL(base_op,
691 : : index == DKIX_EMPTY ?
692 : : SPEC_FAIL_ATTR_NOT_IN_DICT :
693 : : SPEC_FAIL_OUT_OF_RANGE);
694 : 0 : return 0;
695 : : }
696 : 10596 : cache->index = (uint16_t)index;
697 : 10596 : write_u32(cache->version, type->tp_version_tag);
698 : 10596 : instr->op.code = hint_op;
699 : : }
700 : 14520 : return 1;
701 : : }
702 : :
703 : : static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name,
704 : : PyObject* descr, DescriptorClassification kind);
705 : : static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name);
706 : :
707 : : void
708 : 17862 : _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
709 : : {
710 : : assert(ENABLE_SPECIALIZATION);
711 : : assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
712 : 17862 : _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
713 : 17862 : PyTypeObject *type = Py_TYPE(owner);
714 [ - + ]: 17862 : if (!_PyType_IsReady(type)) {
715 : : // We *might* not really need this check, but we inherited it from
716 : : // PyObject_GenericGetAttr and friends... and this way we still do the
717 : : // right thing if someone forgets to call PyType_Ready(type):
718 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
719 : 0 : goto fail;
720 : : }
721 [ + + ]: 17862 : if (PyModule_CheckExact(owner)) {
722 [ + + ]: 2964 : if (specialize_module_load_attr(owner, instr, name))
723 : : {
724 : 228 : goto fail;
725 : : }
726 : 2736 : goto success;
727 : : }
728 [ + + ]: 14898 : if (PyType_Check(owner)) {
729 [ + + ]: 2317 : if (specialize_class_load_attr(owner, instr, name)) {
730 : 2146 : goto fail;
731 : : }
732 : 171 : goto success;
733 : : }
734 : 12581 : PyObject *descr = NULL;
735 : 12581 : DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0);
736 : : assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
737 [ - + + + : 12581 : switch(kind) {
+ + + + -
- + + + +
- ]
738 : 0 : case OVERRIDING:
739 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
740 : 0 : goto fail;
741 : 3771 : case METHOD:
742 : : {
743 : 3771 : int oparg = instr->op.arg;
744 [ + + ]: 3771 : if (oparg & 1) {
745 [ + + ]: 3335 : if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) {
746 : 2744 : goto success;
747 : : }
748 : : }
749 : : else {
750 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
751 : : }
752 : 1027 : goto fail;
753 : : }
754 : 145 : case PROPERTY:
755 : : {
756 : 145 : _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
757 : : assert(Py_TYPE(descr) == &PyProperty_Type);
758 : 145 : PyObject *fget = ((_PyPropertyObject *)descr)->prop_get;
759 [ - + ]: 145 : if (fget == NULL) {
760 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
761 : 0 : goto fail;
762 : : }
763 [ - + ]: 145 : if (!Py_IS_TYPE(fget, &PyFunction_Type)) {
764 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
765 : 0 : goto fail;
766 : : }
767 [ - + ]: 145 : if (!function_check_args(fget, 1, LOAD_ATTR)) {
768 : 0 : goto fail;
769 : : }
770 : 145 : uint32_t version = function_get_version(fget, LOAD_ATTR);
771 [ - + ]: 145 : if (version == 0) {
772 : 0 : goto fail;
773 : : }
774 : 145 : write_u32(lm_cache->keys_version, version);
775 : : assert(type->tp_version_tag != 0);
776 : 145 : write_u32(lm_cache->type_version, type->tp_version_tag);
777 : : /* borrowed */
778 : 145 : write_obj(lm_cache->descr, fget);
779 : 145 : instr->op.code = LOAD_ATTR_PROPERTY;
780 : 145 : goto success;
781 : : }
782 : 79 : case OBJECT_SLOT:
783 : : {
784 : 79 : PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
785 : 79 : struct PyMemberDef *dmem = member->d_member;
786 : 79 : Py_ssize_t offset = dmem->offset;
787 [ - + ]: 79 : if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
788 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
789 : 0 : goto fail;
790 : : }
791 [ - + ]: 79 : if (dmem->flags & PY_AUDIT_READ) {
792 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT);
793 : 0 : goto fail;
794 : : }
795 [ - + ]: 79 : if (offset != (uint16_t)offset) {
796 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
797 : 0 : goto fail;
798 : : }
799 : : assert(dmem->type == T_OBJECT_EX);
800 : : assert(offset > 0);
801 : 79 : cache->index = (uint16_t)offset;
802 : 79 : write_u32(cache->version, type->tp_version_tag);
803 : 79 : instr->op.code = LOAD_ATTR_SLOT;
804 : 79 : goto success;
805 : : }
806 : 27 : case DUNDER_CLASS:
807 : : {
808 : 27 : Py_ssize_t offset = offsetof(PyObject, ob_type);
809 : : assert(offset == (uint16_t)offset);
810 : 27 : cache->index = (uint16_t)offset;
811 : 27 : write_u32(cache->version, type->tp_version_tag);
812 : 27 : instr->op.code = LOAD_ATTR_SLOT;
813 : 27 : goto success;
814 : : }
815 : 754 : case OTHER_SLOT:
816 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
817 : 754 : goto fail;
818 : 9 : case MUTABLE:
819 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
820 : 9 : goto fail;
821 : 415 : case GETSET_OVERRIDDEN:
822 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN);
823 : 415 : goto fail;
824 : 0 : case GETATTRIBUTE_IS_PYTHON_FUNCTION:
825 : : {
826 : : assert(type->tp_getattro == _Py_slot_tp_getattro);
827 : : assert(Py_IS_TYPE(descr, &PyFunction_Type));
828 : 0 : _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
829 [ # # ]: 0 : if (!function_check_args(descr, 2, LOAD_ATTR)) {
830 : 0 : goto fail;
831 : : }
832 : 0 : uint32_t version = function_get_version(descr, LOAD_ATTR);
833 [ # # ]: 0 : if (version == 0) {
834 : 0 : goto fail;
835 : : }
836 : 0 : write_u32(lm_cache->keys_version, version);
837 : : /* borrowed */
838 : 0 : write_obj(lm_cache->descr, descr);
839 : 0 : write_u32(lm_cache->type_version, type->tp_version_tag);
840 : 0 : instr->op.code = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN;
841 : 0 : goto success;
842 : : }
843 : 0 : case BUILTIN_CLASSMETHOD:
844 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ);
845 : 0 : goto fail;
846 : 20 : case PYTHON_CLASSMETHOD:
847 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_METHOD_OBJ);
848 : 20 : goto fail;
849 : 344 : case NON_OVERRIDING:
850 : : SPECIALIZATION_FAIL(LOAD_ATTR,
851 : : (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ?
852 : : SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR :
853 : : SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
854 : 344 : goto fail;
855 : 201 : case NON_DESCRIPTOR:
856 : : SPECIALIZATION_FAIL(LOAD_ATTR,
857 : : (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ?
858 : : SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE :
859 : : SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
860 : 201 : goto fail;
861 : 6816 : case ABSENT:
862 [ + + ]: 6816 : if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR,
863 : : LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
864 : : {
865 : 6577 : goto success;
866 : : }
867 : : }
868 : 239 : fail:
869 : : STAT_INC(LOAD_ATTR, failure);
870 : : assert(!PyErr_Occurred());
871 : 5383 : instr->op.code = LOAD_ATTR;
872 : 5383 : cache->counter = adaptive_counter_backoff(cache->counter);
873 : 5383 : return;
874 : 12479 : success:
875 : : STAT_INC(LOAD_ATTR, success);
876 : : assert(!PyErr_Occurred());
877 : 12479 : cache->counter = adaptive_counter_cooldown();
878 : : }
879 : :
880 : : void
881 : 9307 : _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
882 : : {
883 : : assert(ENABLE_SPECIALIZATION);
884 : : assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR);
885 : 9307 : _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
886 : 9307 : PyTypeObject *type = Py_TYPE(owner);
887 [ - + ]: 9307 : if (!_PyType_IsReady(type)) {
888 : : // We *might* not really need this check, but we inherited it from
889 : : // PyObject_GenericSetAttr and friends... and this way we still do the
890 : : // right thing if someone forgets to call PyType_Ready(type):
891 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OTHER);
892 : 0 : goto fail;
893 : : }
894 [ + + ]: 9307 : if (PyModule_CheckExact(owner)) {
895 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
896 : 550 : goto fail;
897 : : }
898 : : PyObject *descr;
899 : 8757 : DescriptorClassification kind = analyze_descriptor(type, name, &descr, 1);
900 [ + - + + : 8757 : switch(kind) {
+ + + - -
- + + - ]
901 : 59 : case OVERRIDING:
902 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
903 : 59 : goto fail;
904 : 0 : case METHOD:
905 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_METHOD);
906 : 0 : goto fail;
907 : 25 : case PROPERTY:
908 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_PROPERTY);
909 : 25 : goto fail;
910 : 62 : case OBJECT_SLOT:
911 : : {
912 : 62 : PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
913 : 62 : struct PyMemberDef *dmem = member->d_member;
914 : 62 : Py_ssize_t offset = dmem->offset;
915 [ - + ]: 62 : if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
916 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_EXPECTED_ERROR);
917 : 0 : goto fail;
918 : : }
919 [ - + ]: 62 : if (dmem->flags & READONLY) {
920 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_READ_ONLY);
921 : 0 : goto fail;
922 : : }
923 [ - + ]: 62 : if (offset != (uint16_t)offset) {
924 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OUT_OF_RANGE);
925 : 0 : goto fail;
926 : : }
927 : : assert(dmem->type == T_OBJECT_EX);
928 : : assert(offset > 0);
929 : 62 : cache->index = (uint16_t)offset;
930 : 62 : write_u32(cache->version, type->tp_version_tag);
931 : 62 : instr->op.code = STORE_ATTR_SLOT;
932 : 62 : goto success;
933 : : }
934 : 53 : case DUNDER_CLASS:
935 : : case OTHER_SLOT:
936 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
937 : 53 : goto fail;
938 : 1 : case MUTABLE:
939 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
940 : 1 : goto fail;
941 : 205 : case GETATTRIBUTE_IS_PYTHON_FUNCTION:
942 : : case GETSET_OVERRIDDEN:
943 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
944 : 205 : goto fail;
945 : 0 : case BUILTIN_CLASSMETHOD:
946 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ);
947 : 0 : goto fail;
948 : 0 : case PYTHON_CLASSMETHOD:
949 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_METHOD_OBJ);
950 : 0 : goto fail;
951 : 0 : case NON_OVERRIDING:
952 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR);
953 : 0 : goto fail;
954 : 130 : case NON_DESCRIPTOR:
955 : : SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE);
956 : 130 : goto fail;
957 : 8222 : case ABSENT:
958 [ + + ]: 8222 : if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR,
959 : : STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT))
960 : : {
961 : 7943 : goto success;
962 : : }
963 : : }
964 : 279 : fail:
965 : : STAT_INC(STORE_ATTR, failure);
966 : : assert(!PyErr_Occurred());
967 : 1302 : instr->op.code = STORE_ATTR;
968 : 1302 : cache->counter = adaptive_counter_backoff(cache->counter);
969 : 1302 : return;
970 : 8005 : success:
971 : : STAT_INC(STORE_ATTR, success);
972 : : assert(!PyErr_Occurred());
973 : 8005 : cache->counter = adaptive_counter_cooldown();
974 : : }
975 : :
976 : :
977 : : #ifdef Py_STATS
978 : : static int
979 : : load_attr_fail_kind(DescriptorClassification kind)
980 : : {
981 : : switch (kind) {
982 : : case OVERRIDING:
983 : : return SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR;
984 : : case METHOD:
985 : : return SPEC_FAIL_ATTR_METHOD;
986 : : case PROPERTY:
987 : : return SPEC_FAIL_ATTR_PROPERTY;
988 : : case OBJECT_SLOT:
989 : : return SPEC_FAIL_ATTR_OBJECT_SLOT;
990 : : case OTHER_SLOT:
991 : : return SPEC_FAIL_ATTR_NON_OBJECT_SLOT;
992 : : case DUNDER_CLASS:
993 : : return SPEC_FAIL_OTHER;
994 : : case MUTABLE:
995 : : return SPEC_FAIL_ATTR_MUTABLE_CLASS;
996 : : case GETSET_OVERRIDDEN:
997 : : case GETATTRIBUTE_IS_PYTHON_FUNCTION:
998 : : return SPEC_FAIL_OVERRIDDEN;
999 : : case BUILTIN_CLASSMETHOD:
1000 : : return SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD;
1001 : : case PYTHON_CLASSMETHOD:
1002 : : return SPEC_FAIL_ATTR_CLASS_METHOD_OBJ;
1003 : : case NON_OVERRIDING:
1004 : : return SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR;
1005 : : case NON_DESCRIPTOR:
1006 : : return SPEC_FAIL_ATTR_NOT_DESCRIPTOR;
1007 : : case ABSENT:
1008 : : return SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE;
1009 : : }
1010 : : Py_UNREACHABLE();
1011 : : }
1012 : : #endif
1013 : :
1014 : : static int
1015 : 2317 : specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
1016 : : PyObject *name)
1017 : : {
1018 : 2317 : _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
1019 [ + + + + ]: 2317 : if (!PyType_CheckExact(owner) || _PyType_Lookup(Py_TYPE(owner), name)) {
1020 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE);
1021 : 1347 : return -1;
1022 : : }
1023 : 970 : PyObject *descr = NULL;
1024 : 970 : DescriptorClassification kind = 0;
1025 : 970 : kind = analyze_descriptor((PyTypeObject *)owner, name, &descr, 0);
1026 [ + + ]: 970 : switch (kind) {
1027 : 171 : case METHOD:
1028 : : case NON_DESCRIPTOR:
1029 : 171 : write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag);
1030 : 171 : write_obj(cache->descr, descr);
1031 : 171 : instr->op.code = LOAD_ATTR_CLASS;
1032 : 171 : return 0;
1033 : : #ifdef Py_STATS
1034 : : case ABSENT:
1035 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
1036 : : return -1;
1037 : : #endif
1038 : 799 : default:
1039 : : SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind));
1040 : 799 : return -1;
1041 : : }
1042 : : }
1043 : :
1044 : : // Please collect stats carefully before and after modifying. A subtle change
1045 : : // can cause a significant drop in cache hits. A possible test is
1046 : : // python.exe -m test_typing test_re test_dis test_zlib.
1047 : : static int
1048 : 3335 : specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
1049 : : PyObject *descr, DescriptorClassification kind)
1050 : : {
1051 : 3335 : _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
1052 : 3335 : PyTypeObject *owner_cls = Py_TYPE(owner);
1053 : :
1054 : : assert(kind == METHOD && descr != NULL);
1055 [ + + ]: 3335 : if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
1056 : 1002 : PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
1057 : 1002 : PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
1058 [ + + ]: 1002 : if (!_PyDictOrValues_IsValues(dorv)) {
1059 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT);
1060 : 112 : return 0;
1061 : : }
1062 : 890 : Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
1063 [ - + ]: 890 : if (index != DKIX_EMPTY) {
1064 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
1065 : 0 : return 0;
1066 : : }
1067 : 890 : uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(
1068 : : _PyInterpreterState_GET(), keys);
1069 [ - + ]: 890 : if (keys_version == 0) {
1070 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
1071 : 0 : return 0;
1072 : : }
1073 : 890 : write_u32(cache->keys_version, keys_version);
1074 : 890 : instr->op.code = LOAD_ATTR_METHOD_WITH_VALUES;
1075 : : }
1076 : : else {
1077 : 2333 : Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
1078 [ + - - + ]: 2333 : if (dictoffset < 0 || dictoffset > INT16_MAX) {
1079 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
1080 : 0 : return 0;
1081 : : }
1082 [ + + ]: 2333 : if (dictoffset == 0) {
1083 : 1822 : instr->op.code = LOAD_ATTR_METHOD_NO_DICT;
1084 : : }
1085 : : else {
1086 : 511 : PyObject *dict = *(PyObject **) ((char *)owner + dictoffset);
1087 [ + + ]: 511 : if (dict) {
1088 : : SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
1089 : 479 : return 0;
1090 : : }
1091 : : assert(owner_cls->tp_dictoffset > 0);
1092 : : assert(owner_cls->tp_dictoffset <= INT16_MAX);
1093 : 32 : instr->op.code = LOAD_ATTR_METHOD_LAZY_DICT;
1094 : : }
1095 : : }
1096 : : /* `descr` is borrowed. This is safe for methods (even inherited ones from
1097 : : * super classes!) as long as tp_version_tag is validated for two main reasons:
1098 : : *
1099 : : * 1. The class will always hold a reference to the method so it will
1100 : : * usually not be GC-ed. Should it be deleted in Python, e.g.
1101 : : * `del obj.meth`, tp_version_tag will be invalidated, because of reason 2.
1102 : : *
1103 : : * 2. The pre-existing type method cache (MCACHE) uses the same principles
1104 : : * of caching a borrowed descriptor. The MCACHE infrastructure does all the
1105 : : * heavy lifting for us. E.g. it invalidates tp_version_tag on any MRO
1106 : : * modification, on any type object change along said MRO, etc. (see
1107 : : * PyType_Modified usages in typeobject.c). The MCACHE has been
1108 : : * working since Python 2.6 and it's battle-tested.
1109 : : */
1110 : 2744 : write_u32(cache->type_version, owner_cls->tp_version_tag);
1111 : 2744 : write_obj(cache->descr, descr);
1112 : 2744 : return 1;
1113 : : }
1114 : :
1115 : : void
1116 : 11080 : _Py_Specialize_LoadGlobal(
1117 : : PyObject *globals, PyObject *builtins,
1118 : : _Py_CODEUNIT *instr, PyObject *name)
1119 : : {
1120 : : assert(ENABLE_SPECIALIZATION);
1121 : : assert(_PyOpcode_Caches[LOAD_GLOBAL] == INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
1122 : : /* Use inline cache */
1123 : 11080 : _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)(instr + 1);
1124 : : assert(PyUnicode_CheckExact(name));
1125 [ - + ]: 11080 : if (!PyDict_CheckExact(globals)) {
1126 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT);
1127 : 0 : goto fail;
1128 : : }
1129 : 11080 : PyDictKeysObject * globals_keys = ((PyDictObject *)globals)->ma_keys;
1130 [ - + ]: 11080 : if (!DK_IS_UNICODE(globals_keys)) {
1131 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
1132 : 0 : goto fail;
1133 : : }
1134 : 11080 : Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name);
1135 [ - + ]: 11080 : if (index == DKIX_ERROR) {
1136 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
1137 : 0 : goto fail;
1138 : : }
1139 : 11080 : PyInterpreterState *interp = _PyInterpreterState_GET();
1140 [ + + ]: 11080 : if (index != DKIX_EMPTY) {
1141 [ - + ]: 7093 : if (index != (uint16_t)index) {
1142 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
1143 : 0 : goto fail;
1144 : : }
1145 : 7093 : uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(
1146 : : interp, globals_keys);
1147 [ - + ]: 7093 : if (keys_version == 0) {
1148 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
1149 : 0 : goto fail;
1150 : : }
1151 [ - + ]: 7093 : if (keys_version != (uint16_t)keys_version) {
1152 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
1153 : 0 : goto fail;
1154 : : }
1155 : 7093 : cache->index = (uint16_t)index;
1156 : 7093 : cache->module_keys_version = (uint16_t)keys_version;
1157 : 7093 : instr->op.code = LOAD_GLOBAL_MODULE;
1158 : 7093 : goto success;
1159 : : }
1160 [ - + ]: 3987 : if (!PyDict_CheckExact(builtins)) {
1161 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT);
1162 : 0 : goto fail;
1163 : : }
1164 : 3987 : PyDictKeysObject * builtin_keys = ((PyDictObject *)builtins)->ma_keys;
1165 [ - + ]: 3987 : if (!DK_IS_UNICODE(builtin_keys)) {
1166 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
1167 : 0 : goto fail;
1168 : : }
1169 : 3987 : index = _PyDictKeys_StringLookup(builtin_keys, name);
1170 [ - + ]: 3987 : if (index == DKIX_ERROR) {
1171 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
1172 : 0 : goto fail;
1173 : : }
1174 [ - + ]: 3987 : if (index != (uint16_t)index) {
1175 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
1176 : 0 : goto fail;
1177 : : }
1178 : 3987 : uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState(
1179 : : interp, globals_keys);
1180 [ - + ]: 3987 : if (globals_version == 0) {
1181 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
1182 : 0 : goto fail;
1183 : : }
1184 [ - + ]: 3987 : if (globals_version != (uint16_t)globals_version) {
1185 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
1186 : 0 : goto fail;
1187 : : }
1188 : 3987 : uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState(
1189 : : interp, builtin_keys);
1190 [ - + ]: 3987 : if (builtins_version == 0) {
1191 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
1192 : 0 : goto fail;
1193 : : }
1194 [ - + ]: 3987 : if (builtins_version > UINT16_MAX) {
1195 : : SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
1196 : 0 : goto fail;
1197 : : }
1198 : 3987 : cache->index = (uint16_t)index;
1199 : 3987 : cache->module_keys_version = (uint16_t)globals_version;
1200 : 3987 : cache->builtin_keys_version = (uint16_t)builtins_version;
1201 : 3987 : instr->op.code = LOAD_GLOBAL_BUILTIN;
1202 : 3987 : goto success;
1203 : 0 : fail:
1204 : : STAT_INC(LOAD_GLOBAL, failure);
1205 : : assert(!PyErr_Occurred());
1206 : 0 : instr->op.code = LOAD_GLOBAL;
1207 : 0 : cache->counter = adaptive_counter_backoff(cache->counter);
1208 : 0 : return;
1209 : 11080 : success:
1210 : : STAT_INC(LOAD_GLOBAL, success);
1211 : : assert(!PyErr_Occurred());
1212 : 11080 : cache->counter = adaptive_counter_cooldown();
1213 : : }
1214 : :
1215 : : #ifdef Py_STATS
1216 : : static int
1217 : : binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub)
1218 : : {
1219 : : if (container_type == &PyUnicode_Type) {
1220 : : if (PyLong_CheckExact(sub)) {
1221 : : return SPEC_FAIL_SUBSCR_STRING_INT;
1222 : : }
1223 : : if (PySlice_Check(sub)) {
1224 : : return SPEC_FAIL_SUBSCR_STRING_SLICE;
1225 : : }
1226 : : return SPEC_FAIL_OTHER;
1227 : : }
1228 : : else if (strcmp(container_type->tp_name, "array.array") == 0) {
1229 : : if (PyLong_CheckExact(sub)) {
1230 : : return SPEC_FAIL_SUBSCR_ARRAY_INT;
1231 : : }
1232 : : if (PySlice_Check(sub)) {
1233 : : return SPEC_FAIL_SUBSCR_ARRAY_SLICE;
1234 : : }
1235 : : return SPEC_FAIL_OTHER;
1236 : : }
1237 : : else if (container_type->tp_as_buffer) {
1238 : : if (PyLong_CheckExact(sub)) {
1239 : : return SPEC_FAIL_SUBSCR_BUFFER_INT;
1240 : : }
1241 : : if (PySlice_Check(sub)) {
1242 : : return SPEC_FAIL_SUBSCR_BUFFER_SLICE;
1243 : : }
1244 : : return SPEC_FAIL_OTHER;
1245 : : }
1246 : : else if (container_type->tp_as_sequence) {
1247 : : if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) {
1248 : : return SPEC_FAIL_SUBSCR_SEQUENCE_INT;
1249 : : }
1250 : : }
1251 : : return SPEC_FAIL_OTHER;
1252 : : }
1253 : : #endif
1254 : :
1255 : : static int
1256 : 8041 : function_kind(PyCodeObject *code) {
1257 : 8041 : int flags = code->co_flags;
1258 [ + + + + ]: 8041 : if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) {
1259 : 2393 : return SPEC_FAIL_CODE_COMPLEX_PARAMETERS;
1260 : : }
1261 [ - + ]: 5648 : if ((flags & CO_OPTIMIZED) == 0) {
1262 : 0 : return SPEC_FAIL_CODE_NOT_OPTIMIZED;
1263 : : }
1264 : 5648 : return SIMPLE_FUNCTION;
1265 : : }
1266 : :
1267 : : /* Returning false indicates a failure. */
1268 : : static bool
1269 : 145 : function_check_args(PyObject *o, int expected_argcount, int opcode)
1270 : : {
1271 : : assert(Py_IS_TYPE(o, &PyFunction_Type));
1272 : 145 : PyFunctionObject *func = (PyFunctionObject *)o;
1273 : 145 : PyCodeObject *fcode = (PyCodeObject *)func->func_code;
1274 : 145 : int kind = function_kind(fcode);
1275 [ - + ]: 145 : if (kind != SIMPLE_FUNCTION) {
1276 : : SPECIALIZATION_FAIL(opcode, kind);
1277 : 0 : return false;
1278 : : }
1279 [ - + ]: 145 : if (fcode->co_argcount != expected_argcount) {
1280 : : SPECIALIZATION_FAIL(opcode, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
1281 : 0 : return false;
1282 : : }
1283 : 145 : return true;
1284 : : }
1285 : :
1286 : : /* Returning 0 indicates a failure. */
1287 : : static uint32_t
1288 : 145 : function_get_version(PyObject *o, int opcode)
1289 : : {
1290 : : assert(Py_IS_TYPE(o, &PyFunction_Type));
1291 : 145 : PyFunctionObject *func = (PyFunctionObject *)o;
1292 : 145 : uint32_t version = _PyFunction_GetVersionForCurrentState(func);
1293 [ - + ]: 145 : if (version == 0) {
1294 : : SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS);
1295 : 0 : return 0;
1296 : : }
1297 : 145 : return version;
1298 : : }
1299 : :
1300 : : void
1301 : 1443 : _Py_Specialize_BinarySubscr(
1302 : : PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
1303 : : {
1304 : : assert(ENABLE_SPECIALIZATION);
1305 : : assert(_PyOpcode_Caches[BINARY_SUBSCR] ==
1306 : : INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
1307 : 1443 : _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)(instr + 1);
1308 : 1443 : PyTypeObject *container_type = Py_TYPE(container);
1309 [ + + ]: 1443 : if (container_type == &PyList_Type) {
1310 [ + + ]: 150 : if (PyLong_CheckExact(sub)) {
1311 [ + + + + ]: 133 : if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) {
1312 : 93 : instr->op.code = BINARY_SUBSCR_LIST_INT;
1313 : 93 : goto success;
1314 : : }
1315 : : SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
1316 : 40 : goto fail;
1317 : : }
1318 : : SPECIALIZATION_FAIL(BINARY_SUBSCR,
1319 : : PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_LIST_SLICE : SPEC_FAIL_OTHER);
1320 : 17 : goto fail;
1321 : : }
1322 [ + + ]: 1293 : if (container_type == &PyTuple_Type) {
1323 [ + + ]: 290 : if (PyLong_CheckExact(sub)) {
1324 [ + + + + ]: 288 : if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) {
1325 : 260 : instr->op.code = BINARY_SUBSCR_TUPLE_INT;
1326 : 260 : goto success;
1327 : : }
1328 : : SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
1329 : 28 : goto fail;
1330 : : }
1331 : : SPECIALIZATION_FAIL(BINARY_SUBSCR,
1332 : : PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_TUPLE_SLICE : SPEC_FAIL_OTHER);
1333 : 2 : goto fail;
1334 : : }
1335 [ + + ]: 1003 : if (container_type == &PyDict_Type) {
1336 : 292 : instr->op.code = BINARY_SUBSCR_DICT;
1337 : 292 : goto success;
1338 : : }
1339 : 711 : PyTypeObject *cls = Py_TYPE(container);
1340 : 711 : PyObject *descriptor = _PyType_Lookup(cls, &_Py_ID(__getitem__));
1341 [ + - + + ]: 711 : if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) {
1342 [ - + ]: 54 : if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
1343 : : SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE);
1344 : 0 : goto fail;
1345 : : }
1346 : 54 : PyFunctionObject *func = (PyFunctionObject *)descriptor;
1347 : 54 : PyCodeObject *fcode = (PyCodeObject *)func->func_code;
1348 : 54 : int kind = function_kind(fcode);
1349 [ + + ]: 54 : if (kind != SIMPLE_FUNCTION) {
1350 : : SPECIALIZATION_FAIL(BINARY_SUBSCR, kind);
1351 : 2 : goto fail;
1352 : : }
1353 [ - + ]: 52 : if (fcode->co_argcount != 2) {
1354 : : SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
1355 : 0 : goto fail;
1356 : : }
1357 : : assert(cls->tp_version_tag != 0);
1358 : 52 : write_u32(cache->type_version, cls->tp_version_tag);
1359 : 52 : int version = _PyFunction_GetVersionForCurrentState(func);
1360 [ + - - + ]: 52 : if (version == 0 || version != (uint16_t)version) {
1361 : : SPECIALIZATION_FAIL(BINARY_SUBSCR, version == 0 ?
1362 : : SPEC_FAIL_OUT_OF_VERSIONS : SPEC_FAIL_OUT_OF_RANGE);
1363 : 0 : goto fail;
1364 : : }
1365 : 52 : cache->func_version = version;
1366 : 52 : ((PyHeapTypeObject *)container_type)->_spec_cache.getitem = descriptor;
1367 : 52 : instr->op.code = BINARY_SUBSCR_GETITEM;
1368 : 52 : goto success;
1369 : : }
1370 : : SPECIALIZATION_FAIL(BINARY_SUBSCR,
1371 : : binary_subscr_fail_kind(container_type, sub));
1372 : 657 : fail:
1373 : : STAT_INC(BINARY_SUBSCR, failure);
1374 : : assert(!PyErr_Occurred());
1375 : 746 : instr->op.code = BINARY_SUBSCR;
1376 : 746 : cache->counter = adaptive_counter_backoff(cache->counter);
1377 : 746 : return;
1378 : 697 : success:
1379 : : STAT_INC(BINARY_SUBSCR, success);
1380 : : assert(!PyErr_Occurred());
1381 : 697 : cache->counter = adaptive_counter_cooldown();
1382 : : }
1383 : :
1384 : : void
1385 : 565 : _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
1386 : : {
1387 : : assert(ENABLE_SPECIALIZATION);
1388 : 565 : _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
1389 : 565 : PyTypeObject *container_type = Py_TYPE(container);
1390 [ + + ]: 565 : if (container_type == &PyList_Type) {
1391 [ + - ]: 62 : if (PyLong_CheckExact(sub)) {
1392 [ + + + + ]: 62 : if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
1393 [ + - ]: 45 : && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container))
1394 : : {
1395 : 45 : instr->op.code = STORE_SUBSCR_LIST_INT;
1396 : 45 : goto success;
1397 : : }
1398 : : else {
1399 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
1400 : 17 : goto fail;
1401 : : }
1402 : : }
1403 [ # # ]: 0 : else if (PySlice_Check(sub)) {
1404 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_LIST_SLICE);
1405 : 0 : goto fail;
1406 : : }
1407 : : else {
1408 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
1409 : 0 : goto fail;
1410 : : }
1411 : : }
1412 [ + + ]: 503 : if (container_type == &PyDict_Type) {
1413 : 368 : instr->op.code = STORE_SUBSCR_DICT;
1414 : 368 : goto success;
1415 : : }
1416 : : #ifdef Py_STATS
1417 : : PyMappingMethods *as_mapping = container_type->tp_as_mapping;
1418 : : if (as_mapping && (as_mapping->mp_ass_subscript
1419 : : == PyDict_Type.tp_as_mapping->mp_ass_subscript)) {
1420 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE);
1421 : : goto fail;
1422 : : }
1423 : : if (PyObject_CheckBuffer(container)) {
1424 : : if (PyLong_CheckExact(sub) && (((size_t)Py_SIZE(sub)) > 1)) {
1425 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
1426 : : }
1427 : : else if (strcmp(container_type->tp_name, "array.array") == 0) {
1428 : : if (PyLong_CheckExact(sub)) {
1429 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_INT);
1430 : : }
1431 : : else if (PySlice_Check(sub)) {
1432 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_SLICE);
1433 : : }
1434 : : else {
1435 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
1436 : : }
1437 : : }
1438 : : else if (PyByteArray_CheckExact(container)) {
1439 : : if (PyLong_CheckExact(sub)) {
1440 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_INT);
1441 : : }
1442 : : else if (PySlice_Check(sub)) {
1443 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE);
1444 : : }
1445 : : else {
1446 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
1447 : : }
1448 : : }
1449 : : else {
1450 : : if (PyLong_CheckExact(sub)) {
1451 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_INT);
1452 : : }
1453 : : else if (PySlice_Check(sub)) {
1454 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_SLICE);
1455 : : }
1456 : : else {
1457 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
1458 : : }
1459 : : }
1460 : : goto fail;
1461 : : }
1462 : : PyObject *descriptor = _PyType_Lookup(container_type, &_Py_ID(__setitem__));
1463 : : if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) {
1464 : : PyFunctionObject *func = (PyFunctionObject *)descriptor;
1465 : : PyCodeObject *code = (PyCodeObject *)func->func_code;
1466 : : int kind = function_kind(code);
1467 : : if (kind == SIMPLE_FUNCTION) {
1468 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_SIMPLE);
1469 : : }
1470 : : else {
1471 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_OTHER);
1472 : : }
1473 : : goto fail;
1474 : : }
1475 : : #endif
1476 : : SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
1477 : 135 : fail:
1478 : : STAT_INC(STORE_SUBSCR, failure);
1479 : : assert(!PyErr_Occurred());
1480 : 152 : instr->op.code = STORE_SUBSCR;
1481 : 152 : cache->counter = adaptive_counter_backoff(cache->counter);
1482 : 152 : return;
1483 : 413 : success:
1484 : : STAT_INC(STORE_SUBSCR, success);
1485 : : assert(!PyErr_Occurred());
1486 : 413 : cache->counter = adaptive_counter_cooldown();
1487 : : }
1488 : :
1489 : : static int
1490 : 2789 : specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
1491 : : PyObject *kwnames)
1492 : : {
1493 : 2789 : PyTypeObject *tp = _PyType_CAST(callable);
1494 [ + + ]: 2789 : if (tp->tp_new == PyBaseObject_Type.tp_new) {
1495 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PYTHON_CLASS);
1496 : 961 : return -1;
1497 : : }
1498 [ + + ]: 1828 : if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
1499 : 1650 : int oparg = instr->op.arg;
1500 [ + + + - : 1650 : if (nargs == 1 && kwnames == NULL && oparg == 1) {
+ + ]
1501 [ + + ]: 968 : if (tp == &PyUnicode_Type) {
1502 : 79 : instr->op.code = CALL_NO_KW_STR_1;
1503 : 79 : return 0;
1504 : : }
1505 [ + + ]: 889 : else if (tp == &PyType_Type) {
1506 : 101 : instr->op.code = CALL_NO_KW_TYPE_1;
1507 : 101 : return 0;
1508 : : }
1509 [ + + ]: 788 : else if (tp == &PyTuple_Type) {
1510 : 76 : instr->op.code = CALL_NO_KW_TUPLE_1;
1511 : 76 : return 0;
1512 : : }
1513 : : }
1514 [ + + ]: 1394 : if (tp->tp_vectorcall != NULL) {
1515 : 414 : instr->op.code = CALL_BUILTIN_CLASS;
1516 : 414 : return 0;
1517 : : }
1518 : : SPECIALIZATION_FAIL(CALL, tp == &PyUnicode_Type ?
1519 : : SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL);
1520 : 980 : return -1;
1521 : : }
1522 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_CLASS_MUTABLE);
1523 : 178 : return -1;
1524 : : }
1525 : :
1526 : : #ifdef Py_STATS
1527 : : static int
1528 : : builtin_call_fail_kind(int ml_flags)
1529 : : {
1530 : : switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
1531 : : METH_KEYWORDS | METH_METHOD)) {
1532 : : case METH_VARARGS:
1533 : : return SPEC_FAIL_CALL_CFUNC_VARARGS;
1534 : : case METH_VARARGS | METH_KEYWORDS:
1535 : : return SPEC_FAIL_CALL_CFUNC_VARARGS_KEYWORDS;
1536 : : case METH_NOARGS:
1537 : : return SPEC_FAIL_CALL_CFUNC_NOARGS;
1538 : : case METH_METHOD | METH_FASTCALL | METH_KEYWORDS:
1539 : : return SPEC_FAIL_CALL_CFUNC_METHOD_FASTCALL_KEYWORDS;
1540 : : /* These cases should be optimized, but return "other" just in case */
1541 : : case METH_O:
1542 : : case METH_FASTCALL:
1543 : : case METH_FASTCALL | METH_KEYWORDS:
1544 : : return SPEC_FAIL_OTHER;
1545 : : default:
1546 : : return SPEC_FAIL_CALL_BAD_CALL_FLAGS;
1547 : : }
1548 : : }
1549 : :
1550 : : static int
1551 : : meth_descr_call_fail_kind(int ml_flags)
1552 : : {
1553 : : switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
1554 : : METH_KEYWORDS | METH_METHOD)) {
1555 : : case METH_VARARGS:
1556 : : return SPEC_FAIL_CALL_METH_DESCR_VARARGS;
1557 : : case METH_VARARGS | METH_KEYWORDS:
1558 : : return SPEC_FAIL_CALL_METH_DESCR_VARARGS_KEYWORDS;
1559 : : case METH_METHOD | METH_FASTCALL | METH_KEYWORDS:
1560 : : return SPEC_FAIL_CALL_METH_DESCR_METHOD_FASTCALL_KEYWORDS;
1561 : : /* These cases should be optimized, but return "other" just in case */
1562 : : case METH_NOARGS:
1563 : : case METH_O:
1564 : : case METH_FASTCALL:
1565 : : case METH_FASTCALL | METH_KEYWORDS:
1566 : : return SPEC_FAIL_OTHER;
1567 : : default:
1568 : : return SPEC_FAIL_CALL_BAD_CALL_FLAGS;
1569 : : }
1570 : : }
1571 : : #endif
1572 : :
1573 : : static int
1574 : 5989 : specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
1575 : : int nargs, PyObject *kwnames)
1576 : : {
1577 [ + + ]: 5989 : if (kwnames) {
1578 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
1579 : 14 : return -1;
1580 : : }
1581 : :
1582 [ + + + + : 5975 : switch (descr->d_method->ml_flags &
+ ]
1583 : : (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
1584 : : METH_KEYWORDS | METH_METHOD)) {
1585 : 173 : case METH_NOARGS: {
1586 [ - + ]: 173 : if (nargs != 1) {
1587 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
1588 : 0 : return -1;
1589 : : }
1590 : 173 : instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS;
1591 : 173 : return 0;
1592 : : }
1593 : 3664 : case METH_O: {
1594 [ - + ]: 3664 : if (nargs != 2) {
1595 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
1596 : 0 : return -1;
1597 : : }
1598 : 3664 : PyInterpreterState *interp = _PyInterpreterState_GET();
1599 : 3664 : PyObject *list_append = interp->callable_cache.list_append;
1600 : 3664 : _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_CALL + 1];
1601 : 3664 : bool pop = (next.op.code == POP_TOP);
1602 : 3664 : int oparg = instr->op.arg;
1603 [ + + + - : 3664 : if ((PyObject *)descr == list_append && oparg == 1 && pop) {
+ - ]
1604 : 337 : instr->op.code = CALL_NO_KW_LIST_APPEND;
1605 : 337 : return 0;
1606 : : }
1607 : 3327 : instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_O;
1608 : 3327 : return 0;
1609 : : }
1610 : 460 : case METH_FASTCALL: {
1611 : 460 : instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_FAST;
1612 : 460 : return 0;
1613 : : }
1614 : 98 : case METH_FASTCALL | METH_KEYWORDS: {
1615 : 98 : instr->op.code = CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS;
1616 : 98 : return 0;
1617 : : }
1618 : : }
1619 : : SPECIALIZATION_FAIL(CALL, meth_descr_call_fail_kind(descr->d_method->ml_flags));
1620 : 1580 : return -1;
1621 : : }
1622 : :
1623 : : static int
1624 : 7842 : specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
1625 : : PyObject *kwnames, bool bound_method)
1626 : : {
1627 : 7842 : _PyCallCache *cache = (_PyCallCache *)(instr + 1);
1628 : 7842 : PyCodeObject *code = (PyCodeObject *)func->func_code;
1629 : 7842 : int kind = function_kind(code);
1630 : : /* Don't specialize if PEP 523 is active */
1631 [ - + ]: 7842 : if (_PyInterpreterState_GET()->eval_frame) {
1632 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523);
1633 : 0 : return -1;
1634 : : }
1635 [ + + ]: 7842 : if (kwnames) {
1636 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
1637 : 575 : return -1;
1638 : : }
1639 [ + + ]: 7267 : if (kind != SIMPLE_FUNCTION) {
1640 : : SPECIALIZATION_FAIL(CALL, kind);
1641 : 1968 : return -1;
1642 : : }
1643 : 5299 : int argcount = code->co_argcount;
1644 [ + + ]: 5299 : int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults);
1645 : : assert(defcount <= argcount);
1646 : 5299 : int min_args = argcount-defcount;
1647 [ + - - + ]: 5299 : if (nargs > argcount || nargs < min_args) {
1648 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
1649 : 0 : return -1;
1650 : : }
1651 : : assert(nargs <= argcount && nargs >= min_args);
1652 : : assert(min_args >= 0 && defcount >= 0);
1653 : : assert(defcount == 0 || func->func_defaults != NULL);
1654 [ - + ]: 5299 : if (min_args > 0xffff) {
1655 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE);
1656 : 0 : return -1;
1657 : : }
1658 : 5299 : int version = _PyFunction_GetVersionForCurrentState(func);
1659 [ - + ]: 5299 : if (version == 0) {
1660 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS);
1661 : 0 : return -1;
1662 : : }
1663 : 5299 : write_u32(cache->func_version, version);
1664 : 5299 : cache->min_args = min_args;
1665 [ + + ]: 5299 : if (argcount == nargs) {
1666 [ + + ]: 5056 : instr->op.code = bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS;
1667 : : }
1668 [ + + ]: 243 : else if (bound_method) {
1669 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD);
1670 : 38 : return -1;
1671 : : }
1672 : : else {
1673 : 205 : instr->op.code = CALL_PY_WITH_DEFAULTS;
1674 : : }
1675 : 5261 : return 0;
1676 : : }
1677 : :
1678 : : static int
1679 : 4831 : specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
1680 : : PyObject *kwnames)
1681 : : {
1682 [ - + ]: 4831 : if (PyCFunction_GET_FUNCTION(callable) == NULL) {
1683 : 0 : return 1;
1684 : : }
1685 [ + + + + ]: 4831 : switch (PyCFunction_GET_FLAGS(callable) &
1686 : : (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
1687 : : METH_KEYWORDS | METH_METHOD)) {
1688 : 933 : case METH_O: {
1689 [ - + ]: 933 : if (kwnames) {
1690 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
1691 : 0 : return -1;
1692 : : }
1693 [ - + ]: 933 : if (nargs != 1) {
1694 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
1695 : 0 : return 1;
1696 : : }
1697 : : /* len(o) */
1698 : 933 : PyInterpreterState *interp = _PyInterpreterState_GET();
1699 [ + + ]: 933 : if (callable == interp->callable_cache.len) {
1700 : 437 : instr->op.code = CALL_NO_KW_LEN;
1701 : 437 : return 0;
1702 : : }
1703 : 496 : instr->op.code = CALL_NO_KW_BUILTIN_O;
1704 : 496 : return 0;
1705 : : }
1706 : 1531 : case METH_FASTCALL: {
1707 [ - + ]: 1531 : if (kwnames) {
1708 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
1709 : 0 : return -1;
1710 : : }
1711 [ + + ]: 1531 : if (nargs == 2) {
1712 : : /* isinstance(o1, o2) */
1713 : 1091 : PyInterpreterState *interp = _PyInterpreterState_GET();
1714 [ + + ]: 1091 : if (callable == interp->callable_cache.isinstance) {
1715 : 498 : instr->op.code = CALL_NO_KW_ISINSTANCE;
1716 : 498 : return 0;
1717 : : }
1718 : : }
1719 : 1033 : instr->op.code = CALL_NO_KW_BUILTIN_FAST;
1720 : 1033 : return 0;
1721 : : }
1722 : 463 : case METH_FASTCALL | METH_KEYWORDS: {
1723 : 463 : instr->op.code = CALL_BUILTIN_FAST_WITH_KEYWORDS;
1724 : 463 : return 0;
1725 : : }
1726 : 1904 : default:
1727 : : SPECIALIZATION_FAIL(CALL,
1728 : : builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable)));
1729 : 1904 : return 1;
1730 : : }
1731 : : }
1732 : :
1733 : : #ifdef Py_STATS
1734 : : static int
1735 : : call_fail_kind(PyObject *callable)
1736 : : {
1737 : : assert(!PyCFunction_CheckExact(callable));
1738 : : assert(!PyFunction_Check(callable));
1739 : : assert(!PyType_Check(callable));
1740 : : assert(!Py_IS_TYPE(callable, &PyMethodDescr_Type));
1741 : : assert(!PyMethod_Check(callable));
1742 : : if (PyInstanceMethod_Check(callable)) {
1743 : : return SPEC_FAIL_CALL_INSTANCE_METHOD;
1744 : : }
1745 : : // builtin method
1746 : : else if (PyCMethod_Check(callable)) {
1747 : : return SPEC_FAIL_CALL_CMETHOD;
1748 : : }
1749 : : else if (Py_TYPE(callable) == &PyWrapperDescr_Type) {
1750 : : return SPEC_FAIL_CALL_OPERATOR_WRAPPER;
1751 : : }
1752 : : else if (Py_TYPE(callable) == &_PyMethodWrapper_Type) {
1753 : : return SPEC_FAIL_CALL_METHOD_WRAPPER;
1754 : : }
1755 : : return SPEC_FAIL_OTHER;
1756 : : }
1757 : : #endif
1758 : :
1759 : :
1760 : : /* TODO:
1761 : : - Specialize calling classes.
1762 : : */
1763 : : void
1764 : 21614 : _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
1765 : : PyObject *kwnames)
1766 : : {
1767 : : assert(ENABLE_SPECIALIZATION);
1768 : : assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL);
1769 : 21614 : _PyCallCache *cache = (_PyCallCache *)(instr + 1);
1770 : : int fail;
1771 [ + + ]: 21614 : if (PyCFunction_CheckExact(callable)) {
1772 : 4831 : fail = specialize_c_call(callable, instr, nargs, kwnames);
1773 : : }
1774 [ + + ]: 16783 : else if (PyFunction_Check(callable)) {
1775 : 5218 : fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs,
1776 : : kwnames, false);
1777 : : }
1778 [ + + ]: 11565 : else if (PyType_Check(callable)) {
1779 : 2789 : fail = specialize_class_call(callable, instr, nargs, kwnames);
1780 : : }
1781 [ + + ]: 8776 : else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
1782 : 5989 : fail = specialize_method_descriptor((PyMethodDescrObject *)callable,
1783 : : instr, nargs, kwnames);
1784 : : }
1785 [ + + ]: 2787 : else if (PyMethod_Check(callable)) {
1786 : 2624 : PyObject *func = ((PyMethodObject *)callable)->im_func;
1787 [ + - ]: 2624 : if (PyFunction_Check(func)) {
1788 : 2624 : fail = specialize_py_call((PyFunctionObject *)func,
1789 : : instr, nargs+1, kwnames, true);
1790 : : } else {
1791 : : SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD);
1792 : 0 : fail = -1;
1793 : : }
1794 : : }
1795 : : else {
1796 : : SPECIALIZATION_FAIL(CALL, call_fail_kind(callable));
1797 : 163 : fail = -1;
1798 : : }
1799 [ + + ]: 21614 : if (fail) {
1800 : : STAT_INC(CALL, failure);
1801 : : assert(!PyErr_Occurred());
1802 : 8361 : instr->op.code = CALL;
1803 : 8361 : cache->counter = adaptive_counter_backoff(cache->counter);
1804 : : }
1805 : : else {
1806 : : STAT_INC(CALL, success);
1807 : : assert(!PyErr_Occurred());
1808 : 13253 : cache->counter = adaptive_counter_cooldown();
1809 : : }
1810 : 21614 : }
1811 : :
1812 : : #ifdef Py_STATS
1813 : : static int
1814 : : binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
1815 : : {
1816 : : switch (oparg) {
1817 : : case NB_ADD:
1818 : : case NB_INPLACE_ADD:
1819 : : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1820 : : return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES;
1821 : : }
1822 : : return SPEC_FAIL_BINARY_OP_ADD_OTHER;
1823 : : case NB_AND:
1824 : : case NB_INPLACE_AND:
1825 : : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1826 : : return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES;
1827 : : }
1828 : : if (PyLong_CheckExact(lhs)) {
1829 : : return SPEC_FAIL_BINARY_OP_AND_INT;
1830 : : }
1831 : : return SPEC_FAIL_BINARY_OP_AND_OTHER;
1832 : : case NB_FLOOR_DIVIDE:
1833 : : case NB_INPLACE_FLOOR_DIVIDE:
1834 : : return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE;
1835 : : case NB_LSHIFT:
1836 : : case NB_INPLACE_LSHIFT:
1837 : : return SPEC_FAIL_BINARY_OP_LSHIFT;
1838 : : case NB_MATRIX_MULTIPLY:
1839 : : case NB_INPLACE_MATRIX_MULTIPLY:
1840 : : return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY;
1841 : : case NB_MULTIPLY:
1842 : : case NB_INPLACE_MULTIPLY:
1843 : : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1844 : : return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES;
1845 : : }
1846 : : return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER;
1847 : : case NB_OR:
1848 : : case NB_INPLACE_OR:
1849 : : return SPEC_FAIL_BINARY_OP_OR;
1850 : : case NB_POWER:
1851 : : case NB_INPLACE_POWER:
1852 : : return SPEC_FAIL_BINARY_OP_POWER;
1853 : : case NB_REMAINDER:
1854 : : case NB_INPLACE_REMAINDER:
1855 : : return SPEC_FAIL_BINARY_OP_REMAINDER;
1856 : : case NB_RSHIFT:
1857 : : case NB_INPLACE_RSHIFT:
1858 : : return SPEC_FAIL_BINARY_OP_RSHIFT;
1859 : : case NB_SUBTRACT:
1860 : : case NB_INPLACE_SUBTRACT:
1861 : : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1862 : : return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES;
1863 : : }
1864 : : return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER;
1865 : : case NB_TRUE_DIVIDE:
1866 : : case NB_INPLACE_TRUE_DIVIDE:
1867 : : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1868 : : return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES;
1869 : : }
1870 : : if (PyFloat_CheckExact(lhs)) {
1871 : : return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT;
1872 : : }
1873 : : return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER;
1874 : : case NB_XOR:
1875 : : case NB_INPLACE_XOR:
1876 : : return SPEC_FAIL_BINARY_OP_XOR;
1877 : : }
1878 : : Py_UNREACHABLE();
1879 : : }
1880 : : #endif
1881 : :
1882 : : void
1883 : 3401 : _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
1884 : : int oparg, PyObject **locals)
1885 : : {
1886 : : assert(ENABLE_SPECIALIZATION);
1887 : : assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP);
1888 : 3401 : _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1);
1889 [ + + + + ]: 3401 : switch (oparg) {
1890 : 733 : case NB_ADD:
1891 : : case NB_INPLACE_ADD:
1892 [ + + ]: 733 : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1893 : 99 : break;
1894 : : }
1895 [ + + ]: 634 : if (PyUnicode_CheckExact(lhs)) {
1896 : 327 : _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1];
1897 [ + + ]: 572 : bool to_store = (next.op.code == STORE_FAST ||
1898 [ + + ]: 245 : next.op.code == STORE_FAST__LOAD_FAST);
1899 [ + + + + ]: 327 : if (to_store && locals[next.op.arg] == lhs) {
1900 : 47 : instr->op.code = BINARY_OP_INPLACE_ADD_UNICODE;
1901 : 47 : goto success;
1902 : : }
1903 : 280 : instr->op.code = BINARY_OP_ADD_UNICODE;
1904 : 280 : goto success;
1905 : : }
1906 [ + + ]: 307 : if (PyLong_CheckExact(lhs)) {
1907 : 193 : instr->op.code = BINARY_OP_ADD_INT;
1908 : 193 : goto success;
1909 : : }
1910 [ + + ]: 114 : if (PyFloat_CheckExact(lhs)) {
1911 : 20 : instr->op.code = BINARY_OP_ADD_FLOAT;
1912 : 20 : goto success;
1913 : : }
1914 : 94 : break;
1915 : 253 : case NB_MULTIPLY:
1916 : : case NB_INPLACE_MULTIPLY:
1917 [ + + ]: 253 : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1918 : 181 : break;
1919 : : }
1920 [ + + ]: 72 : if (PyLong_CheckExact(lhs)) {
1921 : 61 : instr->op.code = BINARY_OP_MULTIPLY_INT;
1922 : 61 : goto success;
1923 : : }
1924 [ + - ]: 11 : if (PyFloat_CheckExact(lhs)) {
1925 : 11 : instr->op.code = BINARY_OP_MULTIPLY_FLOAT;
1926 : 11 : goto success;
1927 : : }
1928 : 0 : break;
1929 : 216 : case NB_SUBTRACT:
1930 : : case NB_INPLACE_SUBTRACT:
1931 [ + + ]: 216 : if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
1932 : 48 : break;
1933 : : }
1934 [ + + ]: 168 : if (PyLong_CheckExact(lhs)) {
1935 : 120 : instr->op.code = BINARY_OP_SUBTRACT_INT;
1936 : 120 : goto success;
1937 : : }
1938 [ + + ]: 48 : if (PyFloat_CheckExact(lhs)) {
1939 : 31 : instr->op.code = BINARY_OP_SUBTRACT_FLOAT;
1940 : 31 : goto success;
1941 : : }
1942 : 17 : break;
1943 : : }
1944 : 2638 : SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs));
1945 : : STAT_INC(BINARY_OP, failure);
1946 : 2638 : instr->op.code = BINARY_OP;
1947 : 2638 : cache->counter = adaptive_counter_backoff(cache->counter);
1948 : 2638 : return;
1949 : 763 : success:
1950 : : STAT_INC(BINARY_OP, success);
1951 : 763 : cache->counter = adaptive_counter_cooldown();
1952 : : }
1953 : :
1954 : :
1955 : : #ifdef Py_STATS
1956 : : static int
1957 : : compare_op_fail_kind(PyObject *lhs, PyObject *rhs)
1958 : : {
1959 : : if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
1960 : : if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) {
1961 : : return SPEC_FAIL_COMPARE_FLOAT_LONG;
1962 : : }
1963 : : if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) {
1964 : : return SPEC_FAIL_COMPARE_LONG_FLOAT;
1965 : : }
1966 : : return SPEC_FAIL_COMPARE_DIFFERENT_TYPES;
1967 : : }
1968 : : if (PyBytes_CheckExact(lhs)) {
1969 : : return SPEC_FAIL_COMPARE_BYTES;
1970 : : }
1971 : : if (PyTuple_CheckExact(lhs)) {
1972 : : return SPEC_FAIL_COMPARE_TUPLE;
1973 : : }
1974 : : if (PyList_CheckExact(lhs)) {
1975 : : return SPEC_FAIL_COMPARE_LIST;
1976 : : }
1977 : : if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) {
1978 : : return SPEC_FAIL_COMPARE_SET;
1979 : : }
1980 : : if (PyBool_Check(lhs)) {
1981 : : return SPEC_FAIL_COMPARE_BOOL;
1982 : : }
1983 : : if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) {
1984 : : return SPEC_FAIL_COMPARE_BASEOBJECT;
1985 : : }
1986 : : return SPEC_FAIL_OTHER;
1987 : : }
1988 : : #endif
1989 : :
1990 : : void
1991 : 3834 : _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
1992 : : int oparg)
1993 : : {
1994 : : assert(ENABLE_SPECIALIZATION);
1995 : : assert(_PyOpcode_Caches[COMPARE_AND_BRANCH] == INLINE_CACHE_ENTRIES_COMPARE_OP);
1996 : 3834 : _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1);
1997 : : #ifndef NDEBUG
1998 : : int next_opcode = instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1].op.code;
1999 : : assert(next_opcode == POP_JUMP_IF_FALSE || next_opcode == POP_JUMP_IF_TRUE);
2000 : : #endif
2001 [ + + ]: 3834 : if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
2002 : : SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs));
2003 : 136 : goto failure;
2004 : : }
2005 [ + + ]: 3698 : if (PyFloat_CheckExact(lhs)) {
2006 : 44 : instr->op.code = COMPARE_AND_BRANCH_FLOAT;
2007 : 44 : goto success;
2008 : : }
2009 [ + + ]: 3654 : if (PyLong_CheckExact(lhs)) {
2010 [ + + + + : 2911 : if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) {
+ + + + +
- + + ]
2011 : 1160 : instr->op.code = COMPARE_AND_BRANCH_INT;
2012 : 1160 : goto success;
2013 : : }
2014 : : else {
2015 : : SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_BIG_INT);
2016 : 1751 : goto failure;
2017 : : }
2018 : : }
2019 [ + + ]: 743 : if (PyUnicode_CheckExact(lhs)) {
2020 : 436 : int cmp = oparg >> 4;
2021 [ + + + + ]: 436 : if (cmp != Py_EQ && cmp != Py_NE) {
2022 : : SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_STRING);
2023 : 12 : goto failure;
2024 : : }
2025 : : else {
2026 : 424 : instr->op.code = COMPARE_AND_BRANCH_STR;
2027 : 424 : goto success;
2028 : : }
2029 : : }
2030 : : SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs));
2031 : 307 : failure:
2032 : : STAT_INC(COMPARE_AND_BRANCH, failure);
2033 : 2206 : instr->op.code = COMPARE_AND_BRANCH;
2034 : 2206 : cache->counter = adaptive_counter_backoff(cache->counter);
2035 : 2206 : return;
2036 : 1628 : success:
2037 : : STAT_INC(COMPARE_AND_BRANCH, success);
2038 : 1628 : cache->counter = adaptive_counter_cooldown();
2039 : : }
2040 : :
2041 : : #ifdef Py_STATS
2042 : : static int
2043 : : unpack_sequence_fail_kind(PyObject *seq)
2044 : : {
2045 : : if (PySequence_Check(seq)) {
2046 : : return SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE;
2047 : : }
2048 : : if (PyIter_Check(seq)) {
2049 : : return SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR;
2050 : : }
2051 : : return SPEC_FAIL_OTHER;
2052 : : }
2053 : : #endif
2054 : :
2055 : : void
2056 : 532 : _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg)
2057 : : {
2058 : : assert(ENABLE_SPECIALIZATION);
2059 : : assert(_PyOpcode_Caches[UNPACK_SEQUENCE] ==
2060 : : INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
2061 : 532 : _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)(instr + 1);
2062 [ + + ]: 532 : if (PyTuple_CheckExact(seq)) {
2063 [ - + ]: 525 : if (PyTuple_GET_SIZE(seq) != oparg) {
2064 : : SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR);
2065 : 0 : goto failure;
2066 : : }
2067 [ + + ]: 525 : if (PyTuple_GET_SIZE(seq) == 2) {
2068 : 415 : instr->op.code = UNPACK_SEQUENCE_TWO_TUPLE;
2069 : 415 : goto success;
2070 : : }
2071 : 110 : instr->op.code = UNPACK_SEQUENCE_TUPLE;
2072 : 110 : goto success;
2073 : : }
2074 [ + - ]: 7 : if (PyList_CheckExact(seq)) {
2075 [ - + ]: 7 : if (PyList_GET_SIZE(seq) != oparg) {
2076 : : SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR);
2077 : 0 : goto failure;
2078 : : }
2079 : 7 : instr->op.code = UNPACK_SEQUENCE_LIST;
2080 : 7 : goto success;
2081 : : }
2082 : : SPECIALIZATION_FAIL(UNPACK_SEQUENCE, unpack_sequence_fail_kind(seq));
2083 : 0 : failure:
2084 : : STAT_INC(UNPACK_SEQUENCE, failure);
2085 : 0 : instr->op.code = UNPACK_SEQUENCE;
2086 : 0 : cache->counter = adaptive_counter_backoff(cache->counter);
2087 : 0 : return;
2088 : 532 : success:
2089 : : STAT_INC(UNPACK_SEQUENCE, success);
2090 : 532 : cache->counter = adaptive_counter_cooldown();
2091 : : }
2092 : :
2093 : : #ifdef Py_STATS
2094 : :
2095 : : int
2096 : : _PySpecialization_ClassifyIterator(PyObject *iter)
2097 : : {
2098 : : if (PyGen_CheckExact(iter)) {
2099 : : return SPEC_FAIL_FOR_ITER_GENERATOR;
2100 : : }
2101 : : if (PyCoro_CheckExact(iter)) {
2102 : : return SPEC_FAIL_FOR_ITER_COROUTINE;
2103 : : }
2104 : : if (PyAsyncGen_CheckExact(iter)) {
2105 : : return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR;
2106 : : }
2107 : : PyTypeObject *t = Py_TYPE(iter);
2108 : : if (t == &PyListIter_Type) {
2109 : : return SPEC_FAIL_FOR_ITER_LIST;
2110 : : }
2111 : : if (t == &PyTupleIter_Type) {
2112 : : return SPEC_FAIL_FOR_ITER_TUPLE;
2113 : : }
2114 : : if (t == &PyDictIterKey_Type) {
2115 : : return SPEC_FAIL_FOR_ITER_DICT_KEYS;
2116 : : }
2117 : : if (t == &PyDictIterValue_Type) {
2118 : : return SPEC_FAIL_FOR_ITER_DICT_VALUES;
2119 : : }
2120 : : if (t == &PyDictIterItem_Type) {
2121 : : return SPEC_FAIL_FOR_ITER_DICT_ITEMS;
2122 : : }
2123 : : if (t == &PySetIter_Type) {
2124 : : return SPEC_FAIL_FOR_ITER_SET;
2125 : : }
2126 : : if (t == &PyUnicodeIter_Type) {
2127 : : return SPEC_FAIL_FOR_ITER_STRING;
2128 : : }
2129 : : if (t == &PyBytesIter_Type) {
2130 : : return SPEC_FAIL_FOR_ITER_BYTES;
2131 : : }
2132 : : if (t == &PyRangeIter_Type) {
2133 : : return SPEC_FAIL_FOR_ITER_RANGE;
2134 : : }
2135 : : if (t == &PyEnum_Type) {
2136 : : return SPEC_FAIL_FOR_ITER_ENUMERATE;
2137 : : }
2138 : : if (t == &PyMap_Type) {
2139 : : return SPEC_FAIL_FOR_ITER_MAP;
2140 : : }
2141 : : if (t == &PyZip_Type) {
2142 : : return SPEC_FAIL_FOR_ITER_ZIP;
2143 : : }
2144 : : if (t == &PySeqIter_Type) {
2145 : : return SPEC_FAIL_FOR_ITER_SEQ_ITER;
2146 : : }
2147 : : if (t == &PyListRevIter_Type) {
2148 : : return SPEC_FAIL_FOR_ITER_REVERSED_LIST;
2149 : : }
2150 : : if (t == &_PyUnicodeASCIIIter_Type) {
2151 : : return SPEC_FAIL_FOR_ITER_ASCII_STRING;
2152 : : }
2153 : : const char *name = t->tp_name;
2154 : : if (strncmp(name, "itertools", 9) == 0) {
2155 : : return SPEC_FAIL_FOR_ITER_ITERTOOLS;
2156 : : }
2157 : : if (strncmp(name, "callable_iterator", 17) == 0) {
2158 : : return SPEC_FAIL_FOR_ITER_CALLABLE;
2159 : : }
2160 : : return SPEC_FAIL_OTHER;
2161 : : }
2162 : :
2163 : : #endif
2164 : :
2165 : : void
2166 : 3275 : _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
2167 : : {
2168 : : assert(ENABLE_SPECIALIZATION);
2169 : : assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER);
2170 : 3275 : _PyForIterCache *cache = (_PyForIterCache *)(instr + 1);
2171 : 3275 : PyTypeObject *tp = Py_TYPE(iter);
2172 [ + + ]: 3275 : if (tp == &PyListIter_Type) {
2173 : 519 : instr->op.code = FOR_ITER_LIST;
2174 : 519 : goto success;
2175 : : }
2176 [ + + ]: 2756 : else if (tp == &PyTupleIter_Type) {
2177 : 507 : instr->op.code = FOR_ITER_TUPLE;
2178 : 507 : goto success;
2179 : : }
2180 [ + + ]: 2249 : else if (tp == &PyRangeIter_Type) {
2181 : 101 : instr->op.code = FOR_ITER_RANGE;
2182 : 101 : goto success;
2183 : : }
2184 [ + + + - ]: 2148 : else if (tp == &PyGen_Type && oparg <= SHRT_MAX) {
2185 : : assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR);
2186 : 22 : instr->op.code = FOR_ITER_GEN;
2187 : 22 : goto success;
2188 : : }
2189 : : SPECIALIZATION_FAIL(FOR_ITER,
2190 : : _PySpecialization_ClassifyIterator(iter));
2191 : : STAT_INC(FOR_ITER, failure);
2192 : 2126 : instr->op.code = FOR_ITER;
2193 : 2126 : cache->counter = adaptive_counter_backoff(cache->counter);
2194 : 2126 : return;
2195 : 1149 : success:
2196 : : STAT_INC(FOR_ITER, success);
2197 : 1149 : cache->counter = adaptive_counter_cooldown();
2198 : : }
2199 : :
2200 : : void
2201 : 10 : _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr)
2202 : : {
2203 : : assert(ENABLE_SPECIALIZATION);
2204 : : assert(_PyOpcode_Caches[SEND] == INLINE_CACHE_ENTRIES_SEND);
2205 : 10 : _PySendCache *cache = (_PySendCache *)(instr + 1);
2206 : 10 : PyTypeObject *tp = Py_TYPE(receiver);
2207 [ + + - + ]: 10 : if (tp == &PyGen_Type || tp == &PyCoro_Type) {
2208 : 4 : instr->op.code = SEND_GEN;
2209 : 4 : goto success;
2210 : : }
2211 : : SPECIALIZATION_FAIL(SEND,
2212 : : _PySpecialization_ClassifyIterator(receiver));
2213 : : STAT_INC(SEND, failure);
2214 : 6 : instr->op.code = SEND;
2215 : 6 : cache->counter = adaptive_counter_backoff(cache->counter);
2216 : 6 : return;
2217 : 4 : success:
2218 : : STAT_INC(SEND, success);
2219 : 4 : cache->counter = adaptive_counter_cooldown();
2220 : : }
|