LCOV - code coverage report
Current view: top level - Python - specialize.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 629 725 86.8 %
Date: 2023-03-20 08:15:36 Functions: 24 24 100.0 %
Branches: 343 438 78.3 %

           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                 :            : }

Generated by: LCOV version 1.14