From 55a29e922d15c0c5202dc1f8782ec4ecf9dcae0e Mon Sep 17 00:00:00 2001
From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Date: Fri, 16 Dec 2022 16:44:10 +0800
Subject: [PATCH 1/4] Specialize LOAD_ATTR for managed dicts

---
 Include/internal/pycore_opcode.h              |   22 +-
 Include/opcode.h                              |   35 +-
 Lib/opcode.py                                 |    1 +
 .../specialize.c                              | 2177 +++++++++++++++++
 Python/bytecodes.c                            |   23 +
 Python/generated_cases.c.h                    |   23 +
 Python/opcode_targets.h                       |   20 +-
 Python/specialize.c                           |    8 +-
 8 files changed, 2267 insertions(+), 42 deletions(-)
 create mode 100644 PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c

diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h
index da8a272f2fa2d0..d702580d498084 100644
--- a/Include/internal/pycore_opcode.h
+++ b/Include/internal/pycore_opcode.h
@@ -152,6 +152,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
     [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR,
     [LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR,
     [LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR,
+    [LOAD_ATTR_METHOD_MANAGED_DICT] = LOAD_ATTR,
     [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR,
     [LOAD_ATTR_METHOD_WITH_DICT] = LOAD_ATTR,
     [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR,
@@ -313,12 +314,12 @@ static const char *const _PyOpcode_OpName[263] = {
     [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT",
     [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT",
     [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT",
-    [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT",
+    [LOAD_ATTR_METHOD_MANAGED_DICT] = "LOAD_ATTR_METHOD_MANAGED_DICT",
     [LIST_TO_TUPLE] = "LIST_TO_TUPLE",
     [RETURN_VALUE] = "RETURN_VALUE",
     [IMPORT_STAR] = "IMPORT_STAR",
     [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
-    [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES",
+    [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT",
     [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP",
     [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR",
     [POP_EXCEPT] = "POP_EXCEPT",
@@ -345,7 +346,7 @@ static const char *const _PyOpcode_OpName[263] = {
     [JUMP_FORWARD] = "JUMP_FORWARD",
     [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP",
     [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP",
-    [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST",
+    [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES",
     [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE",
     [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE",
     [LOAD_GLOBAL] = "LOAD_GLOBAL",
@@ -353,7 +354,7 @@ static const char *const _PyOpcode_OpName[263] = {
     [CONTAINS_OP] = "CONTAINS_OP",
     [RERAISE] = "RERAISE",
     [COPY] = "COPY",
-    [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST",
+    [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST",
     [BINARY_OP] = "BINARY_OP",
     [SEND] = "SEND",
     [LOAD_FAST] = "LOAD_FAST",
@@ -373,9 +374,9 @@ static const char *const _PyOpcode_OpName[263] = {
     [STORE_DEREF] = "STORE_DEREF",
     [DELETE_DEREF] = "DELETE_DEREF",
     [JUMP_BACKWARD] = "JUMP_BACKWARD",
-    [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST",
+    [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST",
     [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX",
-    [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
+    [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST",
     [EXTENDED_ARG] = "EXTENDED_ARG",
     [LIST_APPEND] = "LIST_APPEND",
     [SET_ADD] = "SET_ADD",
@@ -385,27 +386,27 @@ static const char *const _PyOpcode_OpName[263] = {
     [YIELD_VALUE] = "YIELD_VALUE",
     [RESUME] = "RESUME",
     [MATCH_CLASS] = "MATCH_CLASS",
+    [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
     [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE",
-    [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
     [FORMAT_VALUE] = "FORMAT_VALUE",
     [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
     [BUILD_STRING] = "BUILD_STRING",
+    [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
     [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT",
     [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT",
     [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST",
-    [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
     [LIST_EXTEND] = "LIST_EXTEND",
     [SET_UPDATE] = "SET_UPDATE",
     [DICT_MERGE] = "DICT_MERGE",
     [DICT_UPDATE] = "DICT_UPDATE",
+    [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
     [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
     [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
     [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
     [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
-    [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
     [CALL] = "CALL",
     [KW_NAMES] = "KW_NAMES",
-    [173] = "<173>",
+    [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
     [174] = "<174>",
     [175] = "<175>",
     [176] = "<176>",
@@ -499,7 +500,6 @@ static const char *const _PyOpcode_OpName[263] = {
 #endif
 
 #define EXTRA_CASES \
-    case 173: \
     case 174: \
     case 175: \
     case 176: \
diff --git a/Include/opcode.h b/Include/opcode.h
index 888250ed37e8cb..088c1a5d8ca54e 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -174,23 +174,24 @@ extern "C" {
 #define LOAD_ATTR_WITH_HINT                     78
 #define LOAD_ATTR_METHOD_LAZY_DICT              79
 #define LOAD_ATTR_METHOD_NO_DICT                80
-#define LOAD_ATTR_METHOD_WITH_DICT              81
-#define LOAD_ATTR_METHOD_WITH_VALUES            86
-#define LOAD_CONST__LOAD_FAST                  113
-#define LOAD_FAST__LOAD_CONST                  121
-#define LOAD_FAST__LOAD_FAST                   141
-#define LOAD_GLOBAL_BUILTIN                    143
-#define LOAD_GLOBAL_MODULE                     153
-#define STORE_ATTR_INSTANCE_VALUE              154
-#define STORE_ATTR_SLOT                        158
-#define STORE_ATTR_WITH_HINT                   159
-#define STORE_FAST__LOAD_FAST                  160
-#define STORE_FAST__STORE_FAST                 161
-#define STORE_SUBSCR_DICT                      166
-#define STORE_SUBSCR_LIST_INT                  167
-#define UNPACK_SEQUENCE_LIST                   168
-#define UNPACK_SEQUENCE_TUPLE                  169
-#define UNPACK_SEQUENCE_TWO_TUPLE              170
+#define LOAD_ATTR_METHOD_MANAGED_DICT           81
+#define LOAD_ATTR_METHOD_WITH_DICT              86
+#define LOAD_ATTR_METHOD_WITH_VALUES           113
+#define LOAD_CONST__LOAD_FAST                  121
+#define LOAD_FAST__LOAD_CONST                  141
+#define LOAD_FAST__LOAD_FAST                   143
+#define LOAD_GLOBAL_BUILTIN                    153
+#define LOAD_GLOBAL_MODULE                     154
+#define STORE_ATTR_INSTANCE_VALUE              158
+#define STORE_ATTR_SLOT                        159
+#define STORE_ATTR_WITH_HINT                   160
+#define STORE_FAST__LOAD_FAST                  161
+#define STORE_FAST__STORE_FAST                 166
+#define STORE_SUBSCR_DICT                      167
+#define STORE_SUBSCR_LIST_INT                  168
+#define UNPACK_SEQUENCE_LIST                   169
+#define UNPACK_SEQUENCE_TUPLE                  170
+#define UNPACK_SEQUENCE_TWO_TUPLE              173
 #define DO_TRACING                             255
 
 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\
diff --git a/Lib/opcode.py b/Lib/opcode.py
index fc57affbac5814..59f368c0d245af 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -336,6 +336,7 @@ def pseudo_op(name, op, real_ops):
         # These will always push [unbound method, self] onto the stack.
         "LOAD_ATTR_METHOD_LAZY_DICT",
         "LOAD_ATTR_METHOD_NO_DICT",
+        "LOAD_ATTR_METHOD_MANAGED_DICT",
         "LOAD_ATTR_METHOD_WITH_DICT",
         "LOAD_ATTR_METHOD_WITH_VALUES",
     ],
diff --git a/PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c b/PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c
new file mode 100644
index 00000000000000..1dfba1b8609b74
--- /dev/null
+++ b/PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c
@@ -0,0 +1,2177 @@
+#include "Python.h"
+#include "pycore_code.h"
+#include "pycore_dict.h"
+#include "pycore_function.h"      // _PyFunction_GetVersionForCurrentState()
+#include "pycore_global_strings.h"  // _Py_ID()
+#include "pycore_long.h"
+#include "pycore_moduleobject.h"
+#include "pycore_object.h"
+#include "pycore_opcode.h"        // _PyOpcode_Caches
+#include "structmember.h"         // struct PyMemberDef, T_OFFSET_EX
+#include "pycore_descrobject.h"
+
+#include <stdlib.h> // rand()
+
+/* For guidance on adding or extending families of instructions see
+ * ./adaptive.md
+ */
+
+#ifdef Py_STATS
+PyStats _py_stats_struct = { 0 };
+PyStats *_py_stats = NULL;
+
+#define ADD_STAT_TO_DICT(res, field) \
+    do { \
+        PyObject *val = PyLong_FromUnsignedLongLong(stats->field); \
+        if (val == NULL) { \
+            Py_DECREF(res); \
+            return NULL; \
+        } \
+        if (PyDict_SetItemString(res, #field, val) == -1) { \
+            Py_DECREF(res); \
+            Py_DECREF(val); \
+            return NULL; \
+        } \
+        Py_DECREF(val); \
+    } while(0);
+
+static PyObject*
+stats_to_dict(SpecializationStats *stats)
+{
+    PyObject *res = PyDict_New();
+    if (res == NULL) {
+        return NULL;
+    }
+    ADD_STAT_TO_DICT(res, success);
+    ADD_STAT_TO_DICT(res, failure);
+    ADD_STAT_TO_DICT(res, hit);
+    ADD_STAT_TO_DICT(res, deferred);
+    ADD_STAT_TO_DICT(res, miss);
+    ADD_STAT_TO_DICT(res, deopt);
+    PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS);
+    if (failure_kinds == NULL) {
+        Py_DECREF(res);
+        return NULL;
+    }
+    for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) {
+        PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]);
+        if (stat == NULL) {
+            Py_DECREF(res);
+            Py_DECREF(failure_kinds);
+            return NULL;
+        }
+        PyTuple_SET_ITEM(failure_kinds, i, stat);
+    }
+    if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) {
+        Py_DECREF(res);
+        Py_DECREF(failure_kinds);
+        return NULL;
+    }
+    Py_DECREF(failure_kinds);
+    return res;
+}
+#undef ADD_STAT_TO_DICT
+
+static int
+add_stat_dict(
+    PyObject *res,
+    int opcode,
+    const char *name) {
+
+    SpecializationStats *stats = &_py_stats_struct.opcode_stats[opcode].specialization;
+    PyObject *d = stats_to_dict(stats);
+    if (d == NULL) {
+        return -1;
+    }
+    int err = PyDict_SetItemString(res, name, d);
+    Py_DECREF(d);
+    return err;
+}
+
+#ifdef Py_STATS
+PyObject*
+_Py_GetSpecializationStats(void) {
+    PyObject *stats = PyDict_New();
+    if (stats == NULL) {
+        return NULL;
+    }
+    int err = 0;
+    err += add_stat_dict(stats, LOAD_ATTR, "load_attr");
+    err += add_stat_dict(stats, LOAD_GLOBAL, "load_global");
+    err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr");
+    err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr");
+    err += add_stat_dict(stats, STORE_ATTR, "store_attr");
+    err += add_stat_dict(stats, CALL, "call");
+    err += add_stat_dict(stats, BINARY_OP, "binary_op");
+    err += add_stat_dict(stats, COMPARE_OP, "compare_op");
+    err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence");
+    err += add_stat_dict(stats, FOR_ITER, "for_iter");
+    if (err < 0) {
+        Py_DECREF(stats);
+        return NULL;
+    }
+    return stats;
+}
+#endif
+
+
+#define PRINT_STAT(i, field) \
+    if (stats[i].field) { \
+        fprintf(out, "    opcode[%d]." #field " : %" PRIu64 "\n", i, stats[i].field); \
+    }
+
+static void
+print_spec_stats(FILE *out, OpcodeStats *stats)
+{
+    /* Mark some opcodes as specializable for stats,
+     * even though we don't specialize them yet. */
+    fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE);
+    fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE);
+    for (int i = 0; i < 256; i++) {
+        if (_PyOpcode_Caches[i]) {
+            fprintf(out, "opcode[%d].specializable : 1\n", i);
+        }
+        PRINT_STAT(i, specialization.success);
+        PRINT_STAT(i, specialization.failure);
+        PRINT_STAT(i, specialization.hit);
+        PRINT_STAT(i, specialization.deferred);
+        PRINT_STAT(i, specialization.miss);
+        PRINT_STAT(i, specialization.deopt);
+        PRINT_STAT(i, execution_count);
+        for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) {
+            uint64_t val = stats[i].specialization.failure_kinds[j];
+            if (val) {
+                fprintf(out, "    opcode[%d].specialization.failure_kinds[%d] : %"
+                    PRIu64 "\n", i, j, val);
+            }
+        }
+        for(int j = 0; j < 256; j++) {
+            if (stats[i].pair_count[j]) {
+                fprintf(out, "opcode[%d].pair_count[%d] : %" PRIu64 "\n",
+                        i, j, stats[i].pair_count[j]);
+            }
+        }
+    }
+}
+#undef PRINT_STAT
+
+
+static void
+print_call_stats(FILE *out, CallStats *stats)
+{
+    fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls);
+    fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls);
+    fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed);
+    fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created);
+    for (int i = 0; i < EVAL_CALL_KINDS; i++) {
+        fprintf(out, "Calls via PyEval_EvalFrame[%d] : %" PRIu64 "\n", i, stats->eval_calls[i]);
+    }
+}
+
+static void
+print_object_stats(FILE *out, ObjectStats *stats)
+{
+    fprintf(out, "Object allocations from freelist: %" PRIu64 "\n", stats->from_freelist);
+    fprintf(out, "Object frees to freelist: %" PRIu64 "\n", stats->to_freelist);
+    fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations);
+    fprintf(out, "Object allocations to 512 bytes: %" PRIu64 "\n", stats->allocations512);
+    fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k);
+    fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big);
+    fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees);
+    fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values);
+    fprintf(out, "Object interpreter increfs: %" PRIu64 "\n", stats->interpreter_increfs);
+    fprintf(out, "Object interpreter decrefs: %" PRIu64 "\n", stats->interpreter_decrefs);
+    fprintf(out, "Object increfs: %" PRIu64 "\n", stats->increfs);
+    fprintf(out, "Object decrefs: %" PRIu64 "\n", stats->decrefs);
+    fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request);
+    fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
+    fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
+    fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
+    fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits);
+    fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses);
+    fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
+    fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits);
+    fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses);
+}
+
+static void
+print_stats(FILE *out, PyStats *stats) {
+    print_spec_stats(out, stats->opcode_stats);
+    print_call_stats(out, &stats->call_stats);
+    print_object_stats(out, &stats->object_stats);
+}
+
+void
+_Py_StatsClear(void)
+{
+    _py_stats_struct = (PyStats) { 0 };
+}
+
+void
+_Py_PrintSpecializationStats(int to_file)
+{
+    FILE *out = stderr;
+    if (to_file) {
+        /* Write to a file instead of stderr. */
+# ifdef MS_WINDOWS
+        const char *dirname = "c:\\temp\\py_stats\\";
+# else
+        const char *dirname = "/tmp/py_stats/";
+# endif
+        /* Use random 160 bit number as file name,
+        * to avoid both accidental collisions and
+        * symlink attacks. */
+        unsigned char rand[20];
+        char hex_name[41];
+        _PyOS_URandomNonblock(rand, 20);
+        for (int i = 0; i < 20; i++) {
+            hex_name[2*i] = "0123456789abcdef"[rand[i]&15];
+            hex_name[2*i+1] = "0123456789abcdef"[(rand[i]>>4)&15];
+        }
+        hex_name[40] = '\0';
+        char buf[64];
+        assert(strlen(dirname) + 40 + strlen(".txt") < 64);
+        sprintf(buf, "%s%s.txt", dirname, hex_name);
+        FILE *fout = fopen(buf, "w");
+        if (fout) {
+            out = fout;
+        }
+    }
+    else {
+        fprintf(out, "Specialization stats:\n");
+    }
+    print_stats(out, &_py_stats_struct);
+    if (out != stderr) {
+        fclose(out);
+    }
+}
+
+#ifdef Py_STATS
+
+#define SPECIALIZATION_FAIL(opcode, kind) \
+do { \
+    if (_py_stats) { \
+        _py_stats->opcode_stats[opcode].specialization.failure_kinds[kind]++; \
+    } \
+} while (0)
+
+#endif
+#endif
+
+#ifndef SPECIALIZATION_FAIL
+#define SPECIALIZATION_FAIL(opcode, kind) ((void)0)
+#endif
+
+// Initialize warmup counters and insert superinstructions. This cannot fail.
+void
+_PyCode_Quicken(PyCodeObject *code)
+{
+    int previous_opcode = 0;
+    _Py_CODEUNIT *instructions = _PyCode_CODE(code);
+    for (int i = 0; i < Py_SIZE(code); i++) {
+        int opcode = _PyOpcode_Deopt[_Py_OPCODE(instructions[i])];
+        int caches = _PyOpcode_Caches[opcode];
+        if (caches) {
+            instructions[i + 1].cache = adaptive_counter_warmup();
+            previous_opcode = 0;
+            i += caches;
+            continue;
+        }
+        switch (previous_opcode << 8 | opcode) {
+            case LOAD_CONST << 8 | LOAD_FAST:
+                instructions[i - 1].opcode = LOAD_CONST__LOAD_FAST;
+                break;
+            case LOAD_FAST << 8 | LOAD_CONST:
+                instructions[i - 1].opcode = LOAD_FAST__LOAD_CONST;
+                break;
+            case LOAD_FAST << 8 | LOAD_FAST:
+                instructions[i - 1].opcode = LOAD_FAST__LOAD_FAST;
+                break;
+            case STORE_FAST << 8 | LOAD_FAST:
+                instructions[i - 1].opcode = STORE_FAST__LOAD_FAST;
+                break;
+            case STORE_FAST << 8 | STORE_FAST:
+                instructions[i - 1].opcode = STORE_FAST__STORE_FAST;
+                break;
+        }
+        previous_opcode = opcode;
+    }
+}
+
+#define SIMPLE_FUNCTION 0
+
+/* Common */
+
+#define SPEC_FAIL_OTHER 0
+#define SPEC_FAIL_NO_DICT 1
+#define SPEC_FAIL_OVERRIDDEN 2
+#define SPEC_FAIL_OUT_OF_VERSIONS 3
+#define SPEC_FAIL_OUT_OF_RANGE 4
+#define SPEC_FAIL_EXPECTED_ERROR 5
+#define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 6
+#define SPEC_FAIL_NOT_PY_FUNCTION 7
+
+
+#define SPEC_FAIL_LOAD_GLOBAL_NON_DICT 17
+#define SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT 18
+
+/* Attributes */
+
+#define SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR 8
+#define SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR 9
+#define SPEC_FAIL_ATTR_NOT_DESCRIPTOR 10
+#define SPEC_FAIL_ATTR_METHOD 11
+#define SPEC_FAIL_ATTR_MUTABLE_CLASS 12
+#define SPEC_FAIL_ATTR_PROPERTY 13
+#define SPEC_FAIL_ATTR_NON_OBJECT_SLOT 14
+#define SPEC_FAIL_ATTR_READ_ONLY 15
+#define SPEC_FAIL_ATTR_AUDITED_SLOT 16
+#define SPEC_FAIL_ATTR_NOT_MANAGED_DICT 17
+#define SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT 18
+#define SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND 19
+
+#define SPEC_FAIL_ATTR_SHADOWED 21
+#define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
+#define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23
+#define SPEC_FAIL_ATTR_OBJECT_SLOT 24
+#define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25
+#define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26
+#define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27
+#define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28
+#define SPEC_FAIL_ATTR_NOT_IN_KEYS 29
+#define SPEC_FAIL_ATTR_NOT_IN_DICT 30
+
+/* Binary subscr and store subscr */
+
+#define SPEC_FAIL_SUBSCR_ARRAY_INT 8
+#define SPEC_FAIL_SUBSCR_ARRAY_SLICE 9
+#define SPEC_FAIL_SUBSCR_LIST_SLICE 10
+#define SPEC_FAIL_SUBSCR_TUPLE_SLICE 11
+#define SPEC_FAIL_SUBSCR_STRING_INT 12
+#define SPEC_FAIL_SUBSCR_STRING_SLICE 13
+#define SPEC_FAIL_SUBSCR_BUFFER_INT 15
+#define SPEC_FAIL_SUBSCR_BUFFER_SLICE 16
+#define SPEC_FAIL_SUBSCR_SEQUENCE_INT 17
+
+/* Store subscr */
+#define SPEC_FAIL_SUBSCR_BYTEARRAY_INT 18
+#define SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE 19
+#define SPEC_FAIL_SUBSCR_PY_SIMPLE 20
+#define SPEC_FAIL_SUBSCR_PY_OTHER 21
+#define SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE 22
+#define SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE 23
+
+/* Binary op */
+
+#define SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES          8
+#define SPEC_FAIL_BINARY_OP_ADD_OTHER                    9
+#define SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES         10
+#define SPEC_FAIL_BINARY_OP_AND_INT                     11
+#define SPEC_FAIL_BINARY_OP_AND_OTHER                   12
+#define SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE                13
+#define SPEC_FAIL_BINARY_OP_LSHIFT                      14
+#define SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY             15
+#define SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES    16
+#define SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER              17
+#define SPEC_FAIL_BINARY_OP_OR                          18
+#define SPEC_FAIL_BINARY_OP_POWER                       19
+#define SPEC_FAIL_BINARY_OP_REMAINDER                   20
+#define SPEC_FAIL_BINARY_OP_RSHIFT                      21
+#define SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES    22
+#define SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER              23
+#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES 24
+#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT           25
+#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER           26
+#define SPEC_FAIL_BINARY_OP_XOR                         27
+
+/* Calls */
+#define SPEC_FAIL_CALL_COMPLEX_PARAMETERS 9
+#define SPEC_FAIL_CALL_CO_NOT_OPTIMIZED 10
+/* SPEC_FAIL_METHOD  defined as 11 above */
+
+#define SPEC_FAIL_CALL_INSTANCE_METHOD 11
+#define SPEC_FAIL_CALL_CMETHOD 12
+#define SPEC_FAIL_CALL_PYCFUNCTION 13
+#define SPEC_FAIL_CALL_PYCFUNCTION_WITH_KEYWORDS 14
+#define SPEC_FAIL_CALL_PYCFUNCTION_FAST_WITH_KEYWORDS 15
+#define SPEC_FAIL_CALL_PYCFUNCTION_NOARGS 16
+#define SPEC_FAIL_CALL_BAD_CALL_FLAGS 17
+#define SPEC_FAIL_CALL_CLASS 18
+#define SPEC_FAIL_CALL_PYTHON_CLASS 19
+#define SPEC_FAIL_CALL_METHOD_DESCRIPTOR 20
+#define SPEC_FAIL_CALL_BOUND_METHOD 21
+#define SPEC_FAIL_CALL_STR 22
+#define SPEC_FAIL_CALL_CLASS_NO_VECTORCALL 23
+#define SPEC_FAIL_CALL_CLASS_MUTABLE 24
+#define SPEC_FAIL_CALL_KWNAMES 25
+#define SPEC_FAIL_CALL_METHOD_WRAPPER 26
+#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 27
+#define SPEC_FAIL_CALL_PYFUNCTION 28
+#define SPEC_FAIL_CALL_PEP_523 29
+
+/* COMPARE_OP */
+#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
+#define SPEC_FAIL_COMPARE_OP_STRING 13
+#define SPEC_FAIL_COMPARE_OP_NOT_FOLLOWED_BY_COND_JUMP 14
+#define SPEC_FAIL_COMPARE_OP_BIG_INT 15
+#define SPEC_FAIL_COMPARE_OP_BYTES 16
+#define SPEC_FAIL_COMPARE_OP_TUPLE 17
+#define SPEC_FAIL_COMPARE_OP_LIST 18
+#define SPEC_FAIL_COMPARE_OP_SET 19
+#define SPEC_FAIL_COMPARE_OP_BOOL 20
+#define SPEC_FAIL_COMPARE_OP_BASEOBJECT 21
+#define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 22
+#define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 23
+#define SPEC_FAIL_COMPARE_OP_EXTENDED_ARG 24
+
+/* FOR_ITER */
+#define SPEC_FAIL_FOR_ITER_GENERATOR 10
+#define SPEC_FAIL_FOR_ITER_COROUTINE 11
+#define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12
+#define SPEC_FAIL_FOR_ITER_LIST 13
+#define SPEC_FAIL_FOR_ITER_TUPLE 14
+#define SPEC_FAIL_FOR_ITER_SET 15
+#define SPEC_FAIL_FOR_ITER_STRING 16
+#define SPEC_FAIL_FOR_ITER_BYTES 17
+#define SPEC_FAIL_FOR_ITER_RANGE 18
+#define SPEC_FAIL_FOR_ITER_ITERTOOLS 19
+#define SPEC_FAIL_FOR_ITER_DICT_KEYS 20
+#define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21
+#define SPEC_FAIL_FOR_ITER_DICT_VALUES 22
+#define SPEC_FAIL_FOR_ITER_ENUMERATE 23
+#define SPEC_FAIL_FOR_ITER_MAP 24
+#define SPEC_FAIL_FOR_ITER_ZIP 25
+#define SPEC_FAIL_FOR_ITER_SEQ_ITER 26
+#define SPEC_FAIL_FOR_ITER_REVERSED_LIST 27
+#define SPEC_FAIL_FOR_ITER_CALLABLE 28
+#define SPEC_FAIL_FOR_ITER_ASCII_STRING 29
+
+// UNPACK_SEQUENCE
+
+#define SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR 8
+#define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 9
+
+static int function_kind(PyCodeObject *code);
+static bool function_check_args(PyObject *o, int expected_argcount, int opcode);
+static uint32_t function_get_version(PyObject *o, int opcode);
+
+static int
+specialize_module_load_attr(
+    PyObject *owner, _Py_CODEUNIT *instr, PyObject *name
+) {
+    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
+    PyModuleObject *m = (PyModuleObject *)owner;
+    assert((owner->ob_type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
+    PyDictObject *dict = (PyDictObject *)m->md_dict;
+    if (dict == NULL) {
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NO_DICT);
+        return -1;
+    }
+    if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT);
+        return -1;
+    }
+    Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__));
+    assert(index != DKIX_ERROR);
+    if (index != DKIX_EMPTY) {
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND);
+        return -1;
+    }
+    index = _PyDict_LookupIndex(dict, name);
+    assert (index != DKIX_ERROR);
+    if (index != (uint16_t)index) {
+        SPECIALIZATION_FAIL(LOAD_ATTR,
+                            index == DKIX_EMPTY ?
+                            SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND :
+                            SPEC_FAIL_OUT_OF_RANGE);
+        return -1;
+    }
+    uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(dict->ma_keys);
+    if (keys_version == 0) {
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
+        return -1;
+    }
+    write_u32(cache->version, keys_version);
+    cache->index = (uint16_t)index;
+    _py_set_opcode(instr, LOAD_ATTR_MODULE);
+    return 0;
+}
+
+
+
+/* Attribute specialization */
+
+typedef enum {
+    OVERRIDING, /* Is an overriding descriptor, and will remain so. */
+    METHOD, /* Attribute has Py_TPFLAGS_METHOD_DESCRIPTOR set */
+    PROPERTY, /* Is a property */
+    OBJECT_SLOT, /* Is an object slot descriptor */
+    OTHER_SLOT, /* Is a slot descriptor of another type */
+    NON_OVERRIDING, /* Is another non-overriding descriptor, and is an instance of an immutable class*/
+    BUILTIN_CLASSMETHOD, /* Builtin methods with METH_CLASS */
+    PYTHON_CLASSMETHOD, /* Python classmethod(func) object */
+    NON_DESCRIPTOR, /* Is not a descriptor, and is an instance of an immutable class */
+    MUTABLE,   /* Instance of a mutable class; might, or might not, be a descriptor */
+    ABSENT, /* Attribute is not present on the class */
+    DUNDER_CLASS, /* __class__ attribute */
+    GETSET_OVERRIDDEN, /* __getattribute__ or __setattr__ has been overridden */
+    GETATTRIBUTE_IS_PYTHON_FUNCTION  /* Descriptor requires calling a Python __getattribute__ */
+} DescriptorClassification;
+
+
+static DescriptorClassification
+analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store)
+{
+    bool has_getattr = false;
+    if (store) {
+        if (type->tp_setattro != PyObject_GenericSetAttr) {
+            *descr = NULL;
+            return GETSET_OVERRIDDEN;
+        }
+    }
+    else {
+        getattrofunc getattro_slot = type->tp_getattro;
+        if (getattro_slot == PyObject_GenericGetAttr) {
+            /* Normal attribute lookup; */
+            has_getattr = false;
+        }
+        else if (getattro_slot == _Py_slot_tp_getattr_hook ||
+            getattro_slot == _Py_slot_tp_getattro) {
+            /* One or both of __getattribute__ or __getattr__ may have been
+             overridden See typeobject.c for why these functions are special. */
+            PyObject *getattribute = _PyType_Lookup(type,
+                &_Py_ID(__getattribute__));
+            PyInterpreterState *interp = _PyInterpreterState_GET();
+            bool has_custom_getattribute = getattribute != NULL &&
+                getattribute != interp->callable_cache.object__getattribute__;
+            has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL;
+            if (has_custom_getattribute) {
+                if (getattro_slot == _Py_slot_tp_getattro &&
+                    !has_getattr &&
+                    Py_IS_TYPE(getattribute, &PyFunction_Type)) {
+                    *descr = getattribute;
+                    return GETATTRIBUTE_IS_PYTHON_FUNCTION;
+                }
+                /* Potentially both __getattr__ and __getattribute__ are set.
+                   Too complicated */
+                *descr = NULL;
+                return GETSET_OVERRIDDEN;
+            }
+            /* Potentially has __getattr__ but no custom __getattribute__.
+               Fall through to usual descriptor analysis.
+               Usual attribute lookup should only be allowed at runtime
+               if we can guarantee that there is no way an exception can be
+               raised. This means some specializations, e.g. specializing
+               for property() isn't safe.
+            */
+        }
+        else {
+            *descr = NULL;
+            return GETSET_OVERRIDDEN;
+        }
+    }
+    PyObject *descriptor = _PyType_Lookup(type, name);
+    *descr = descriptor;
+    if (descriptor == NULL) {
+        return ABSENT;
+    }
+    PyTypeObject *desc_cls = Py_TYPE(descriptor);
+    if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) {
+        return MUTABLE;
+    }
+    if (desc_cls->tp_descr_set) {
+        if (desc_cls == &PyMemberDescr_Type) {
+            PyMemberDescrObject *member = (PyMemberDescrObject *)descriptor;
+            struct PyMemberDef *dmem = member->d_member;
+            if (dmem->type == T_OBJECT_EX) {
+                return OBJECT_SLOT;
+            }
+            return OTHER_SLOT;
+        }
+        if (desc_cls == &PyProperty_Type) {
+            /* We can't detect at runtime whether an attribute exists
+               with property. So that means we may have to call
+               __getattr__. */
+            return has_getattr ? GETSET_OVERRIDDEN : PROPERTY;
+        }
+        if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) {
+            if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) {
+                return DUNDER_CLASS;
+            }
+        }
+        if (store) {
+            return OVERRIDING;
+        }
+    }
+    if (desc_cls->tp_descr_get) {
+        if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) {
+            return METHOD;
+        }
+        if (Py_IS_TYPE(descriptor, &PyClassMethodDescr_Type)) {
+            return BUILTIN_CLASSMETHOD;
+        }
+        if (Py_IS_TYPE(descriptor, &PyClassMethod_Type)) {
+            return PYTHON_CLASSMETHOD;
+        }
+        return NON_OVERRIDING;
+    }
+    return NON_DESCRIPTOR;
+}
+
+static int
+specialize_dict_access(
+    PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type,
+    DescriptorClassification kind, PyObject *name,
+    int base_op, int values_op, int hint_op)
+{
+    assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT ||
+        kind == BUILTIN_CLASSMETHOD || kind == PYTHON_CLASSMETHOD);
+    // No descriptor, or non overriding.
+    if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
+        SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
+        return 0;
+    }
+    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
+    PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+    if (_PyDictOrValues_IsValues(dorv)) {
+        // Virtual dictionary
+        PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
+        assert(PyUnicode_CheckExact(name));
+        Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
+        assert (index != DKIX_ERROR);
+        if (index != (uint16_t)index) {
+            SPECIALIZATION_FAIL(base_op,
+                                index == DKIX_EMPTY ?
+                                SPEC_FAIL_ATTR_NOT_IN_KEYS :
+                                SPEC_FAIL_OUT_OF_RANGE);
+            return 0;
+        }
+        write_u32(cache->version, type->tp_version_tag);
+        cache->index = (uint16_t)index;
+        _py_set_opcode(instr, values_op);
+    }
+    else {
+        PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
+        if (dict == NULL || !PyDict_CheckExact(dict)) {
+            SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
+            return 0;
+        }
+        // We found an instance with a __dict__.
+        Py_ssize_t index =
+            _PyDict_LookupIndex(dict, name);
+        if (index != (uint16_t)index) {
+            SPECIALIZATION_FAIL(base_op,
+                                index == DKIX_EMPTY ?
+                                SPEC_FAIL_ATTR_NOT_IN_DICT :
+                                SPEC_FAIL_OUT_OF_RANGE);
+            return 0;
+        }
+        cache->index = (uint16_t)index;
+        write_u32(cache->version, type->tp_version_tag);
+        _py_set_opcode(instr, hint_op);
+    }
+    return 1;
+}
+
+static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name,
+    PyObject* descr, DescriptorClassification kind);
+static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name);
+
+void
+_Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
+{
+    assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
+    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
+    PyTypeObject *type = Py_TYPE(owner);
+    if (!_PyType_IsReady(type)) {
+        // We *might* not really need this check, but we inherited it from
+        // PyObject_GenericGetAttr and friends... and this way we still do the
+        // right thing if someone forgets to call PyType_Ready(type):
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
+        goto fail;
+    }
+    if (PyModule_CheckExact(owner)) {
+        if (specialize_module_load_attr(owner, instr, name))
+        {
+            goto fail;
+        }
+        goto success;
+    }
+    if (PyType_Check(owner)) {
+        if (specialize_class_load_attr(owner, instr, name)) {
+            goto fail;
+        }
+        goto success;
+    }
+    PyObject *descr = NULL;
+    DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0);
+    assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
+    switch(kind) {
+        case OVERRIDING:
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
+            goto fail;
+        case METHOD:
+        {
+            int oparg = _Py_OPARG(*instr);
+            if (oparg & 1) {
+                if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) {
+                    goto success;
+                }
+            }
+            else {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
+            }
+            goto fail;
+        }
+        case PROPERTY:
+        {
+            _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
+            assert(Py_TYPE(descr) == &PyProperty_Type);
+            PyObject *fget = ((_PyPropertyObject *)descr)->prop_get;
+            if (fget == NULL) {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
+                goto fail;
+            }
+            if (!Py_IS_TYPE(fget, &PyFunction_Type)) {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
+                goto fail;
+            }
+            if (!function_check_args(fget, 1, LOAD_ATTR)) {
+                goto fail;
+            }
+            uint32_t version = function_get_version(fget, LOAD_ATTR);
+            if (version == 0) {
+                goto fail;
+            }
+            write_u32(lm_cache->keys_version, version);
+            assert(type->tp_version_tag != 0);
+            write_u32(lm_cache->type_version, type->tp_version_tag);
+            /* borrowed */
+            write_obj(lm_cache->descr, fget);
+            _py_set_opcode(instr, LOAD_ATTR_PROPERTY);
+            goto success;
+        }
+        case OBJECT_SLOT:
+        {
+            PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
+            struct PyMemberDef *dmem = member->d_member;
+            Py_ssize_t offset = dmem->offset;
+            if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
+                goto fail;
+            }
+            if (dmem->flags & PY_AUDIT_READ) {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT);
+                goto fail;
+            }
+            if (offset != (uint16_t)offset) {
+                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
+                goto fail;
+            }
+            assert(dmem->type == T_OBJECT_EX);
+            assert(offset > 0);
+            cache->index = (uint16_t)offset;
+            write_u32(cache->version, type->tp_version_tag);
+            _py_set_opcode(instr, LOAD_ATTR_SLOT);
+            goto success;
+        }
+        case DUNDER_CLASS:
+        {
+            Py_ssize_t offset = offsetof(PyObject, ob_type);
+            assert(offset == (uint16_t)offset);
+            cache->index = (uint16_t)offset;
+            write_u32(cache->version, type->tp_version_tag);
+            _py_set_opcode(instr, LOAD_ATTR_SLOT);
+            goto success;
+        }
+        case OTHER_SLOT:
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
+            goto fail;
+        case MUTABLE:
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
+            goto fail;
+        case GETSET_OVERRIDDEN:
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN);
+            goto fail;
+        case GETATTRIBUTE_IS_PYTHON_FUNCTION:
+        {
+            assert(type->tp_getattro == _Py_slot_tp_getattro);
+            assert(Py_IS_TYPE(descr, &PyFunction_Type));
+            _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
+            if (!function_check_args(descr, 2, LOAD_ATTR)) {
+                goto fail;
+            }
+            uint32_t version = function_get_version(descr, LOAD_ATTR);
+            if (version == 0) {
+                goto fail;
+            }
+            write_u32(lm_cache->keys_version, version);
+            /* borrowed */
+            write_obj(lm_cache->descr, descr);
+            write_u32(lm_cache->type_version, type->tp_version_tag);
+            _py_set_opcode(instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN);
+            goto success;
+        }
+        case BUILTIN_CLASSMETHOD:
+        case PYTHON_CLASSMETHOD:
+        case NON_OVERRIDING:
+        case NON_DESCRIPTOR:
+        case ABSENT:
+            break;
+    }
+    if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR,
+                               LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
+    {
+        goto success;
+    }
+fail:
+    STAT_INC(LOAD_ATTR, failure);
+    assert(!PyErr_Occurred());
+    _py_set_opcode(instr, LOAD_ATTR);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(LOAD_ATTR, success);
+    assert(!PyErr_Occurred());
+    cache->counter = adaptive_counter_cooldown();
+}
+
+void
+_Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
+{
+    assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR);
+    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
+    PyTypeObject *type = Py_TYPE(owner);
+    if (!_PyType_IsReady(type)) {
+        // We *might* not really need this check, but we inherited it from
+        // PyObject_GenericSetAttr and friends... and this way we still do the
+        // right thing if someone forgets to call PyType_Ready(type):
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
+        goto fail;
+    }
+    if (PyModule_CheckExact(owner)) {
+        SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
+        goto fail;
+    }
+    PyObject *descr;
+    DescriptorClassification kind = analyze_descriptor(type, name, &descr, 1);
+    switch(kind) {
+        case OVERRIDING:
+            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
+            goto fail;
+        case METHOD:
+            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_METHOD);
+            goto fail;
+        case PROPERTY:
+            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_PROPERTY);
+            goto fail;
+        case OBJECT_SLOT:
+        {
+            PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
+            struct PyMemberDef *dmem = member->d_member;
+            Py_ssize_t offset = dmem->offset;
+            if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
+                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_EXPECTED_ERROR);
+                goto fail;
+            }
+            if (dmem->flags & READONLY) {
+                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_READ_ONLY);
+                goto fail;
+            }
+            if (offset != (uint16_t)offset) {
+                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OUT_OF_RANGE);
+                goto fail;
+            }
+            assert(dmem->type == T_OBJECT_EX);
+            assert(offset > 0);
+            cache->index = (uint16_t)offset;
+            write_u32(cache->version, type->tp_version_tag);
+            _py_set_opcode(instr, STORE_ATTR_SLOT);
+            goto success;
+        }
+        case DUNDER_CLASS:
+        case OTHER_SLOT:
+            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
+            goto fail;
+        case MUTABLE:
+            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
+            goto fail;
+        case GETATTRIBUTE_IS_PYTHON_FUNCTION:
+        case GETSET_OVERRIDDEN:
+            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
+            goto fail;
+        case BUILTIN_CLASSMETHOD:
+        case PYTHON_CLASSMETHOD:
+        case NON_OVERRIDING:
+        case NON_DESCRIPTOR:
+        case ABSENT:
+            break;
+    }
+    if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR,
+                               STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT))
+    {
+        goto success;
+    }
+fail:
+    STAT_INC(STORE_ATTR, failure);
+    assert(!PyErr_Occurred());
+    _py_set_opcode(instr, STORE_ATTR);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(STORE_ATTR, success);
+    assert(!PyErr_Occurred());
+    cache->counter = adaptive_counter_cooldown();
+}
+
+
+#ifdef Py_STATS
+static int
+load_attr_fail_kind(DescriptorClassification kind)
+{
+    switch (kind) {
+        case OVERRIDING:
+            return SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR;
+        case METHOD:
+            return SPEC_FAIL_ATTR_METHOD;
+        case PROPERTY:
+            return SPEC_FAIL_ATTR_PROPERTY;
+        case OBJECT_SLOT:
+            return SPEC_FAIL_ATTR_OBJECT_SLOT;
+        case OTHER_SLOT:
+            return SPEC_FAIL_ATTR_NON_OBJECT_SLOT;
+        case DUNDER_CLASS:
+            return SPEC_FAIL_OTHER;
+        case MUTABLE:
+            return SPEC_FAIL_ATTR_MUTABLE_CLASS;
+        case GETSET_OVERRIDDEN:
+        case GETATTRIBUTE_IS_PYTHON_FUNCTION:
+            return SPEC_FAIL_OVERRIDDEN;
+        case BUILTIN_CLASSMETHOD:
+            return SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD;
+        case PYTHON_CLASSMETHOD:
+            return SPEC_FAIL_ATTR_CLASS_METHOD_OBJ;
+        case NON_OVERRIDING:
+            return SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR;
+        case NON_DESCRIPTOR:
+            return SPEC_FAIL_ATTR_NOT_DESCRIPTOR;
+        case ABSENT:
+            return SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE;
+    }
+    Py_UNREACHABLE();
+}
+#endif
+
+static int
+specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
+                             PyObject *name)
+{
+    _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
+    if (!PyType_CheckExact(owner) || _PyType_Lookup(Py_TYPE(owner), name)) {
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE);
+        return -1;
+    }
+    PyObject *descr = NULL;
+    DescriptorClassification kind = 0;
+    kind = analyze_descriptor((PyTypeObject *)owner, name, &descr, 0);
+    switch (kind) {
+        case METHOD:
+        case NON_DESCRIPTOR:
+            write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag);
+            write_obj(cache->descr, descr);
+            _py_set_opcode(instr, LOAD_ATTR_CLASS);
+            return 0;
+#ifdef Py_STATS
+        case ABSENT:
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
+            return -1;
+#endif
+        default:
+            SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind));
+            return -1;
+    }
+}
+
+typedef enum {
+    MANAGED_VALUES = 1,
+    MANAGED_DICT = 2,
+    OFFSET_DICT = 3,
+    NO_DICT = 4,
+    LAZY_DICT = 5,
+} ObjectDictKind;
+
+// Please collect stats carefully before and after modifying. A subtle change
+// can cause a significant drop in cache hits. A possible test is
+// python.exe -m test_typing test_re test_dis test_zlib.
+static int
+specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
+PyObject *descr, DescriptorClassification kind)
+{
+    _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
+    PyTypeObject *owner_cls = Py_TYPE(owner);
+
+    assert(kind == METHOD && descr != NULL);
+    ObjectDictKind dictkind;
+    PyDictKeysObject *keys;
+    if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+        PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+        keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
+        if (_PyDictOrValues_IsValues(dorv)) {
+            dictkind = MANAGED_VALUES;
+        }
+        else {
+            // User has directly accessed __dict__.
+            dictkind = MANAGED_DICT;
+        }
+    }
+    else {
+        Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
+        if (dictoffset < 0 || dictoffset > INT16_MAX) {
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
+            goto fail;
+        }
+        if (dictoffset == 0) {
+            dictkind = NO_DICT;
+            keys = NULL;
+        }
+        else {
+            PyObject *dict = *(PyObject **) ((char *)owner + dictoffset);
+            if (dict == NULL) {
+                // This object will have a dict if user access __dict__
+                dictkind = LAZY_DICT;
+                keys = NULL;
+            }
+            else {
+                keys = ((PyDictObject *)dict)->ma_keys;
+                dictkind = OFFSET_DICT;
+            }
+        }
+    }
+    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT || dictkind == MANAGED_DICT) {
+        Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
+        if (index != DKIX_EMPTY) {
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
+            goto fail;
+        }
+        uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(keys);
+        if (keys_version == 0) {
+            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
+            goto fail;
+        }
+        write_u32(cache->keys_version, keys_version);
+    }
+    switch(dictkind) {
+        case NO_DICT:
+            _py_set_opcode(instr, LOAD_ATTR_METHOD_NO_DICT);
+            break;
+        case MANAGED_VALUES:
+            _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_VALUES);
+            break;
+        case MANAGED_DICT:
+            _py_set_opcode(instr, LOAD_ATTR_METHOD_MANAGED_DICT);
+            break;
+        case OFFSET_DICT:
+            assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
+            _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_DICT);
+            break;
+        case LAZY_DICT:
+            assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
+            _py_set_opcode(instr, LOAD_ATTR_METHOD_LAZY_DICT);
+            break;
+    }
+    /* `descr` is borrowed. This is safe for methods (even inherited ones from
+    *  super classes!) as long as tp_version_tag is validated for two main reasons:
+    *
+    *  1. The class will always hold a reference to the method so it will
+    *  usually not be GC-ed. Should it be deleted in Python, e.g.
+    *  `del obj.meth`, tp_version_tag will be invalidated, because of reason 2.
+    *
+    *  2. The pre-existing type method cache (MCACHE) uses the same principles
+    *  of caching a borrowed descriptor. The MCACHE infrastructure does all the
+    *  heavy lifting for us. E.g. it invalidates tp_version_tag on any MRO
+    *  modification, on any type object change along said MRO, etc. (see
+    *  PyType_Modified usages in typeobject.c). The MCACHE has been
+    *  working since Python 2.6 and it's battle-tested.
+    */
+    write_u32(cache->type_version, owner_cls->tp_version_tag);
+    write_obj(cache->descr, descr);
+    return 1;
+fail:
+    return 0;
+}
+
+void
+_Py_Specialize_LoadGlobal(
+    PyObject *globals, PyObject *builtins,
+    _Py_CODEUNIT *instr, PyObject *name)
+{
+    assert(_PyOpcode_Caches[LOAD_GLOBAL] == INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
+    /* Use inline cache */
+    _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)(instr + 1);
+    assert(PyUnicode_CheckExact(name));
+    if (!PyDict_CheckExact(globals)) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT);
+        goto fail;
+    }
+    PyDictKeysObject * globals_keys = ((PyDictObject *)globals)->ma_keys;
+    if (!DK_IS_UNICODE(globals_keys)) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
+        goto fail;
+    }
+    Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name);
+    if (index == DKIX_ERROR) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
+        goto fail;
+    }
+    if (index != DKIX_EMPTY) {
+        if (index != (uint16_t)index) {
+            SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
+            goto fail;
+        }
+        uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(globals_keys);
+        if (keys_version == 0) {
+            SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
+            goto fail;
+        }
+        cache->index = (uint16_t)index;
+        write_u32(cache->module_keys_version, keys_version);
+        _py_set_opcode(instr, LOAD_GLOBAL_MODULE);
+        goto success;
+    }
+    if (!PyDict_CheckExact(builtins)) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT);
+        goto fail;
+    }
+    PyDictKeysObject * builtin_keys = ((PyDictObject *)builtins)->ma_keys;
+    if (!DK_IS_UNICODE(builtin_keys)) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
+        goto fail;
+    }
+    index = _PyDictKeys_StringLookup(builtin_keys, name);
+    if (index == DKIX_ERROR) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
+        goto fail;
+    }
+    if (index != (uint16_t)index) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
+        goto fail;
+    }
+    uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState(globals_keys);
+    if (globals_version == 0) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
+        goto fail;
+    }
+    uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState(builtin_keys);
+    if (builtins_version == 0) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
+        goto fail;
+    }
+    if (builtins_version > UINT16_MAX) {
+        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
+        goto fail;
+    }
+    cache->index = (uint16_t)index;
+    write_u32(cache->module_keys_version, globals_version);
+    cache->builtin_keys_version = (uint16_t)builtins_version;
+    _py_set_opcode(instr, LOAD_GLOBAL_BUILTIN);
+    goto success;
+fail:
+    STAT_INC(LOAD_GLOBAL, failure);
+    assert(!PyErr_Occurred());
+    _py_set_opcode(instr, LOAD_GLOBAL);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(LOAD_GLOBAL, success);
+    assert(!PyErr_Occurred());
+    cache->counter = adaptive_counter_cooldown();
+}
+
+#ifdef Py_STATS
+static int
+binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub)
+{
+    if (container_type == &PyUnicode_Type) {
+        if (PyLong_CheckExact(sub)) {
+            return SPEC_FAIL_SUBSCR_STRING_INT;
+        }
+        if (PySlice_Check(sub)) {
+            return SPEC_FAIL_SUBSCR_STRING_SLICE;
+        }
+        return SPEC_FAIL_OTHER;
+    }
+    else if (strcmp(container_type->tp_name, "array.array") == 0) {
+        if (PyLong_CheckExact(sub)) {
+            return SPEC_FAIL_SUBSCR_ARRAY_INT;
+        }
+        if (PySlice_Check(sub)) {
+            return SPEC_FAIL_SUBSCR_ARRAY_SLICE;
+        }
+        return SPEC_FAIL_OTHER;
+    }
+    else if (container_type->tp_as_buffer) {
+        if (PyLong_CheckExact(sub)) {
+            return SPEC_FAIL_SUBSCR_BUFFER_INT;
+        }
+        if (PySlice_Check(sub)) {
+            return SPEC_FAIL_SUBSCR_BUFFER_SLICE;
+        }
+        return SPEC_FAIL_OTHER;
+    }
+    else if (container_type->tp_as_sequence) {
+        if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) {
+            return SPEC_FAIL_SUBSCR_SEQUENCE_INT;
+        }
+    }
+    return SPEC_FAIL_OTHER;
+}
+#endif
+
+static int
+function_kind(PyCodeObject *code) {
+    int flags = code->co_flags;
+    if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) {
+        return SPEC_FAIL_CALL_COMPLEX_PARAMETERS;
+    }
+    if ((flags & CO_OPTIMIZED) == 0) {
+        return SPEC_FAIL_CALL_CO_NOT_OPTIMIZED;
+    }
+    return SIMPLE_FUNCTION;
+}
+
+/* Returning false indicates a failure. */
+static bool
+function_check_args(PyObject *o, int expected_argcount, int opcode)
+{
+    assert(Py_IS_TYPE(o, &PyFunction_Type));
+    PyFunctionObject *func = (PyFunctionObject *)o;
+    PyCodeObject *fcode = (PyCodeObject *)func->func_code;
+    int kind = function_kind(fcode);
+    if (kind != SIMPLE_FUNCTION) {
+        SPECIALIZATION_FAIL(opcode, kind);
+        return false;
+    }
+    if (fcode->co_argcount != expected_argcount) {
+        SPECIALIZATION_FAIL(opcode, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
+        return false;
+    }
+    return true;
+}
+
+/* Returning 0 indicates a failure. */
+static uint32_t
+function_get_version(PyObject *o, int opcode)
+{
+    assert(Py_IS_TYPE(o, &PyFunction_Type));
+    PyFunctionObject *func = (PyFunctionObject *)o;
+    uint32_t version = _PyFunction_GetVersionForCurrentState(func);
+    if (version == 0) {
+        SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS);
+        return 0;
+    }
+    return version;
+}
+
+void
+_Py_Specialize_BinarySubscr(
+     PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
+{
+    assert(_PyOpcode_Caches[BINARY_SUBSCR] ==
+           INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
+    _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)(instr + 1);
+    PyTypeObject *container_type = Py_TYPE(container);
+    if (container_type == &PyList_Type) {
+        if (PyLong_CheckExact(sub)) {
+            _py_set_opcode(instr, BINARY_SUBSCR_LIST_INT);
+            goto success;
+        }
+        SPECIALIZATION_FAIL(BINARY_SUBSCR,
+            PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_LIST_SLICE : SPEC_FAIL_OTHER);
+        goto fail;
+    }
+    if (container_type == &PyTuple_Type) {
+        if (PyLong_CheckExact(sub)) {
+            _py_set_opcode(instr, BINARY_SUBSCR_TUPLE_INT);
+            goto success;
+        }
+        SPECIALIZATION_FAIL(BINARY_SUBSCR,
+            PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_TUPLE_SLICE : SPEC_FAIL_OTHER);
+        goto fail;
+    }
+    if (container_type == &PyDict_Type) {
+        _py_set_opcode(instr, BINARY_SUBSCR_DICT);
+        goto success;
+    }
+    PyTypeObject *cls = Py_TYPE(container);
+    PyObject *descriptor = _PyType_Lookup(cls, &_Py_ID(__getitem__));
+    if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) {
+        if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+            SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE);
+            goto fail;
+        }
+        PyFunctionObject *func = (PyFunctionObject *)descriptor;
+        PyCodeObject *fcode = (PyCodeObject *)func->func_code;
+        int kind = function_kind(fcode);
+        if (kind != SIMPLE_FUNCTION) {
+            SPECIALIZATION_FAIL(BINARY_SUBSCR, kind);
+            goto fail;
+        }
+        if (fcode->co_argcount != 2) {
+            SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
+            goto fail;
+        }
+        assert(cls->tp_version_tag != 0);
+        write_u32(cache->type_version, cls->tp_version_tag);
+        int version = _PyFunction_GetVersionForCurrentState(func);
+        if (version == 0 || version != (uint16_t)version) {
+            SPECIALIZATION_FAIL(BINARY_SUBSCR, version == 0 ?
+                SPEC_FAIL_OUT_OF_VERSIONS : SPEC_FAIL_OUT_OF_RANGE);
+            goto fail;
+        }
+        cache->func_version = version;
+        ((PyHeapTypeObject *)container_type)->_spec_cache.getitem = descriptor;
+        _py_set_opcode(instr, BINARY_SUBSCR_GETITEM);
+        goto success;
+    }
+    SPECIALIZATION_FAIL(BINARY_SUBSCR,
+                        binary_subscr_fail_kind(container_type, sub));
+fail:
+    STAT_INC(BINARY_SUBSCR, failure);
+    assert(!PyErr_Occurred());
+    _py_set_opcode(instr, BINARY_SUBSCR);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(BINARY_SUBSCR, success);
+    assert(!PyErr_Occurred());
+    cache->counter = adaptive_counter_cooldown();
+}
+
+void
+_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
+{
+    _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
+    PyTypeObject *container_type = Py_TYPE(container);
+    if (container_type == &PyList_Type) {
+        if (PyLong_CheckExact(sub)) {
+            if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
+                && ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container))
+            {
+                _py_set_opcode(instr, STORE_SUBSCR_LIST_INT);
+                goto success;
+            }
+            else {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
+                goto fail;
+            }
+        }
+        else if (PySlice_Check(sub)) {
+            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_LIST_SLICE);
+            goto fail;
+        }
+        else {
+            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
+            goto fail;
+        }
+    }
+    if (container_type == &PyDict_Type) {
+        _py_set_opcode(instr, STORE_SUBSCR_DICT);
+         goto success;
+    }
+#ifdef Py_STATS
+    PyMappingMethods *as_mapping = container_type->tp_as_mapping;
+    if (as_mapping && (as_mapping->mp_ass_subscript
+                       == PyDict_Type.tp_as_mapping->mp_ass_subscript)) {
+        SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE);
+        goto fail;
+    }
+    if (PyObject_CheckBuffer(container)) {
+        if (PyLong_CheckExact(sub) && (((size_t)Py_SIZE(sub)) > 1)) {
+            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
+        }
+        else if (strcmp(container_type->tp_name, "array.array") == 0) {
+            if (PyLong_CheckExact(sub)) {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_INT);
+            }
+            else if (PySlice_Check(sub)) {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_SLICE);
+            }
+            else {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
+            }
+        }
+        else if (PyByteArray_CheckExact(container)) {
+            if (PyLong_CheckExact(sub)) {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_INT);
+            }
+            else if (PySlice_Check(sub)) {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE);
+            }
+            else {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
+            }
+        }
+        else {
+            if (PyLong_CheckExact(sub)) {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_INT);
+            }
+            else if (PySlice_Check(sub)) {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_SLICE);
+            }
+            else {
+                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
+            }
+        }
+        goto fail;
+    }
+    PyObject *descriptor = _PyType_Lookup(container_type, &_Py_ID(__setitem__));
+    if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) {
+        PyFunctionObject *func = (PyFunctionObject *)descriptor;
+        PyCodeObject *code = (PyCodeObject *)func->func_code;
+        int kind = function_kind(code);
+        if (kind == SIMPLE_FUNCTION) {
+            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_SIMPLE);
+        }
+        else {
+            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_OTHER);
+        }
+        goto fail;
+    }
+#endif
+    SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
+fail:
+    STAT_INC(STORE_SUBSCR, failure);
+    assert(!PyErr_Occurred());
+    _py_set_opcode(instr, STORE_SUBSCR);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(STORE_SUBSCR, success);
+    assert(!PyErr_Occurred());
+    cache->counter = adaptive_counter_cooldown();
+}
+
+static int
+specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
+                      PyObject *kwnames)
+{
+    PyTypeObject *tp = _PyType_CAST(callable);
+    if (tp->tp_new == PyBaseObject_Type.tp_new) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PYTHON_CLASS);
+        return -1;
+    }
+    if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
+        int oparg = _Py_OPARG(*instr);
+        if (nargs == 1 && kwnames == NULL && oparg == 1) {
+            if (tp == &PyUnicode_Type) {
+                _py_set_opcode(instr, CALL_NO_KW_STR_1);
+                return 0;
+            }
+            else if (tp == &PyType_Type) {
+                _py_set_opcode(instr, CALL_NO_KW_TYPE_1);
+                return 0;
+            }
+            else if (tp == &PyTuple_Type) {
+                _py_set_opcode(instr, CALL_NO_KW_TUPLE_1);
+                return 0;
+            }
+        }
+        if (tp->tp_vectorcall != NULL) {
+            _py_set_opcode(instr, CALL_BUILTIN_CLASS);
+            return 0;
+        }
+        SPECIALIZATION_FAIL(CALL, tp == &PyUnicode_Type ?
+            SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL);
+        return -1;
+    }
+    SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_CLASS_MUTABLE);
+    return -1;
+}
+
+#ifdef Py_STATS
+static int
+builtin_call_fail_kind(int ml_flags)
+{
+    switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
+        METH_KEYWORDS | METH_METHOD)) {
+        case METH_VARARGS:
+            return SPEC_FAIL_CALL_PYCFUNCTION;
+        case METH_VARARGS | METH_KEYWORDS:
+            return SPEC_FAIL_CALL_PYCFUNCTION_WITH_KEYWORDS;
+        case METH_FASTCALL | METH_KEYWORDS:
+            return SPEC_FAIL_CALL_PYCFUNCTION_FAST_WITH_KEYWORDS;
+        case METH_NOARGS:
+            return SPEC_FAIL_CALL_PYCFUNCTION_NOARGS;
+        /* This case should never happen with PyCFunctionObject -- only
+            PyMethodObject. See zlib.compressobj()'s methods for an example.
+        */
+        case METH_METHOD | METH_FASTCALL | METH_KEYWORDS:
+        default:
+            return SPEC_FAIL_CALL_BAD_CALL_FLAGS;
+    }
+}
+#endif
+
+static int
+specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
+                             int nargs, PyObject *kwnames)
+{
+    if (kwnames) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
+        return -1;
+    }
+
+    switch (descr->d_method->ml_flags &
+        (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
+        METH_KEYWORDS | METH_METHOD)) {
+        case METH_NOARGS: {
+            if (nargs != 1) {
+                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
+                return -1;
+            }
+            _py_set_opcode(instr, CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS);
+            return 0;
+        }
+        case METH_O: {
+            if (nargs != 2) {
+                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
+                return -1;
+            }
+            PyInterpreterState *interp = _PyInterpreterState_GET();
+            PyObject *list_append = interp->callable_cache.list_append;
+            _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_CALL + 1];
+            bool pop = (_Py_OPCODE(next) == POP_TOP);
+            int oparg = _Py_OPARG(*instr);
+            if ((PyObject *)descr == list_append && oparg == 1 && pop) {
+                _py_set_opcode(instr, CALL_NO_KW_LIST_APPEND);
+                return 0;
+            }
+            _py_set_opcode(instr, CALL_NO_KW_METHOD_DESCRIPTOR_O);
+            return 0;
+        }
+        case METH_FASTCALL: {
+            _py_set_opcode(instr, CALL_NO_KW_METHOD_DESCRIPTOR_FAST);
+            return 0;
+        }
+        case METH_FASTCALL|METH_KEYWORDS: {
+            _py_set_opcode(instr, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS);
+            return 0;
+        }
+    }
+    SPECIALIZATION_FAIL(CALL, builtin_call_fail_kind(descr->d_method->ml_flags));
+    return -1;
+}
+
+static int
+specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
+                   PyObject *kwnames, bool bound_method)
+{
+    _PyCallCache *cache = (_PyCallCache *)(instr + 1);
+    PyCodeObject *code = (PyCodeObject *)func->func_code;
+    int kind = function_kind(code);
+    /* Don't specialize if PEP 523 is active */
+    if (_PyInterpreterState_GET()->eval_frame) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523);
+        return -1;
+    }
+    if (kwnames) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
+        return -1;
+    }
+    if (kind != SIMPLE_FUNCTION) {
+        SPECIALIZATION_FAIL(CALL, kind);
+        return -1;
+    }
+    int argcount = code->co_argcount;
+    int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults);
+    assert(defcount <= argcount);
+    int min_args = argcount-defcount;
+    if (nargs > argcount || nargs < min_args) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
+        return -1;
+    }
+    assert(nargs <= argcount && nargs >= min_args);
+    assert(min_args >= 0 && defcount >= 0);
+    assert(defcount == 0 || func->func_defaults != NULL);
+    if (min_args > 0xffff) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE);
+        return -1;
+    }
+    int version = _PyFunction_GetVersionForCurrentState(func);
+    if (version == 0) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS);
+        return -1;
+    }
+    write_u32(cache->func_version, version);
+    cache->min_args = min_args;
+    if (argcount == nargs) {
+        _py_set_opcode(instr, bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS);
+    }
+    else if (bound_method) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD);
+        return -1;
+    }
+    else {
+        _py_set_opcode(instr, CALL_PY_WITH_DEFAULTS);
+    }
+    return 0;
+}
+
+static int
+specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
+                  PyObject *kwnames)
+{
+    if (PyCFunction_GET_FUNCTION(callable) == NULL) {
+        return 1;
+    }
+    switch (PyCFunction_GET_FLAGS(callable) &
+        (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
+        METH_KEYWORDS | METH_METHOD)) {
+        case METH_O: {
+            if (kwnames) {
+                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
+                return -1;
+            }
+            if (nargs != 1) {
+                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
+                return 1;
+            }
+            /* len(o) */
+            PyInterpreterState *interp = _PyInterpreterState_GET();
+            if (callable == interp->callable_cache.len) {
+                _py_set_opcode(instr, CALL_NO_KW_LEN);
+                return 0;
+            }
+            _py_set_opcode(instr, CALL_NO_KW_BUILTIN_O);
+            return 0;
+        }
+        case METH_FASTCALL: {
+            if (kwnames) {
+                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
+                return -1;
+            }
+            if (nargs == 2) {
+                /* isinstance(o1, o2) */
+                PyInterpreterState *interp = _PyInterpreterState_GET();
+                if (callable == interp->callable_cache.isinstance) {
+                    _py_set_opcode(instr, CALL_NO_KW_ISINSTANCE);
+                    return 0;
+                }
+            }
+            _py_set_opcode(instr, CALL_NO_KW_BUILTIN_FAST);
+            return 0;
+        }
+        case METH_FASTCALL | METH_KEYWORDS: {
+            _py_set_opcode(instr, CALL_BUILTIN_FAST_WITH_KEYWORDS);
+            return 0;
+        }
+        default:
+            SPECIALIZATION_FAIL(CALL,
+                builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable)));
+            return 1;
+    }
+}
+
+#ifdef Py_STATS
+static int
+call_fail_kind(PyObject *callable)
+{
+    if (PyCFunction_CheckExact(callable)) {
+        return SPEC_FAIL_CALL_PYCFUNCTION;
+    }
+    else if (PyFunction_Check(callable)) {
+        return SPEC_FAIL_CALL_PYFUNCTION;
+    }
+    else if (PyInstanceMethod_Check(callable)) {
+        return SPEC_FAIL_CALL_INSTANCE_METHOD;
+    }
+    else if (PyMethod_Check(callable)) {
+        return SPEC_FAIL_CALL_BOUND_METHOD;
+    }
+    // builtin method
+    else if (PyCMethod_Check(callable)) {
+        return SPEC_FAIL_CALL_CMETHOD;
+    }
+    else if (PyType_Check(callable)) {
+        if (((PyTypeObject *)callable)->tp_new == PyBaseObject_Type.tp_new) {
+            return SPEC_FAIL_CALL_PYTHON_CLASS;
+        }
+        else {
+            return SPEC_FAIL_CALL_CLASS;
+        }
+    }
+    else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
+        return SPEC_FAIL_CALL_METHOD_DESCRIPTOR;
+    }
+    else if (Py_TYPE(callable) == &PyWrapperDescr_Type) {
+        return SPEC_FAIL_CALL_OPERATOR_WRAPPER;
+    }
+    else if (Py_TYPE(callable) == &_PyMethodWrapper_Type) {
+        return SPEC_FAIL_CALL_METHOD_WRAPPER;
+    }
+    return SPEC_FAIL_OTHER;
+}
+#endif
+
+
+/* TODO:
+    - Specialize calling classes.
+*/
+void
+_Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
+                    PyObject *kwnames)
+{
+    assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL);
+    _PyCallCache *cache = (_PyCallCache *)(instr + 1);
+    int fail;
+    if (PyCFunction_CheckExact(callable)) {
+        fail = specialize_c_call(callable, instr, nargs, kwnames);
+    }
+    else if (PyFunction_Check(callable)) {
+        fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs,
+                                  kwnames, false);
+    }
+    else if (PyType_Check(callable)) {
+        fail = specialize_class_call(callable, instr, nargs, kwnames);
+    }
+    else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
+        fail = specialize_method_descriptor((PyMethodDescrObject *)callable,
+                                            instr, nargs, kwnames);
+    }
+    else if (Py_TYPE(callable) == &PyMethod_Type) {
+        PyObject *func = ((PyMethodObject *)callable)->im_func;
+        if (PyFunction_Check(func)) {
+            fail = specialize_py_call((PyFunctionObject *)func,
+                                      instr, nargs+1, kwnames, true);
+        } else {
+            SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD);
+            fail = -1;
+        }
+    }
+    else {
+        SPECIALIZATION_FAIL(CALL, call_fail_kind(callable));
+        fail = -1;
+    }
+    if (fail) {
+        STAT_INC(CALL, failure);
+        assert(!PyErr_Occurred());
+        _py_set_opcode(instr, CALL);
+        cache->counter = adaptive_counter_backoff(cache->counter);
+    }
+    else {
+        STAT_INC(CALL, success);
+        assert(!PyErr_Occurred());
+        cache->counter = adaptive_counter_cooldown();
+    }
+}
+
+#ifdef Py_STATS
+static int
+binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
+{
+    switch (oparg) {
+        case NB_ADD:
+        case NB_INPLACE_ADD:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES;
+            }
+            return SPEC_FAIL_BINARY_OP_ADD_OTHER;
+        case NB_AND:
+        case NB_INPLACE_AND:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES;
+            }
+            if (PyLong_CheckExact(lhs)) {
+                return SPEC_FAIL_BINARY_OP_AND_INT;
+            }
+            return SPEC_FAIL_BINARY_OP_AND_OTHER;
+        case NB_FLOOR_DIVIDE:
+        case NB_INPLACE_FLOOR_DIVIDE:
+            return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE;
+        case NB_LSHIFT:
+        case NB_INPLACE_LSHIFT:
+            return SPEC_FAIL_BINARY_OP_LSHIFT;
+        case NB_MATRIX_MULTIPLY:
+        case NB_INPLACE_MATRIX_MULTIPLY:
+            return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY;
+        case NB_MULTIPLY:
+        case NB_INPLACE_MULTIPLY:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES;
+            }
+            return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER;
+        case NB_OR:
+        case NB_INPLACE_OR:
+            return SPEC_FAIL_BINARY_OP_OR;
+        case NB_POWER:
+        case NB_INPLACE_POWER:
+            return SPEC_FAIL_BINARY_OP_POWER;
+        case NB_REMAINDER:
+        case NB_INPLACE_REMAINDER:
+            return SPEC_FAIL_BINARY_OP_REMAINDER;
+        case NB_RSHIFT:
+        case NB_INPLACE_RSHIFT:
+            return SPEC_FAIL_BINARY_OP_RSHIFT;
+        case NB_SUBTRACT:
+        case NB_INPLACE_SUBTRACT:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES;
+            }
+            return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER;
+        case NB_TRUE_DIVIDE:
+        case NB_INPLACE_TRUE_DIVIDE:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES;
+            }
+            if (PyFloat_CheckExact(lhs)) {
+                return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT;
+            }
+            return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER;
+        case NB_XOR:
+        case NB_INPLACE_XOR:
+            return SPEC_FAIL_BINARY_OP_XOR;
+    }
+    Py_UNREACHABLE();
+}
+#endif
+
+void
+_Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
+                        int oparg, PyObject **locals)
+{
+    assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP);
+    _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1);
+    switch (oparg) {
+        case NB_ADD:
+        case NB_INPLACE_ADD:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                break;
+            }
+            if (PyUnicode_CheckExact(lhs)) {
+                _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1];
+                bool to_store = (_Py_OPCODE(next) == STORE_FAST ||
+                                 _Py_OPCODE(next) == STORE_FAST__LOAD_FAST);
+                if (to_store && locals[_Py_OPARG(next)] == lhs) {
+                    _py_set_opcode(instr, BINARY_OP_INPLACE_ADD_UNICODE);
+                    goto success;
+                }
+                _py_set_opcode(instr, BINARY_OP_ADD_UNICODE);
+                goto success;
+            }
+            if (PyLong_CheckExact(lhs)) {
+                _py_set_opcode(instr, BINARY_OP_ADD_INT);
+                goto success;
+            }
+            if (PyFloat_CheckExact(lhs)) {
+                _py_set_opcode(instr, BINARY_OP_ADD_FLOAT);
+                goto success;
+            }
+            break;
+        case NB_MULTIPLY:
+        case NB_INPLACE_MULTIPLY:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                break;
+            }
+            if (PyLong_CheckExact(lhs)) {
+                _py_set_opcode(instr, BINARY_OP_MULTIPLY_INT);
+                goto success;
+            }
+            if (PyFloat_CheckExact(lhs)) {
+                _py_set_opcode(instr, BINARY_OP_MULTIPLY_FLOAT);
+                goto success;
+            }
+            break;
+        case NB_SUBTRACT:
+        case NB_INPLACE_SUBTRACT:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                break;
+            }
+            if (PyLong_CheckExact(lhs)) {
+                _py_set_opcode(instr, BINARY_OP_SUBTRACT_INT);
+                goto success;
+            }
+            if (PyFloat_CheckExact(lhs)) {
+                _py_set_opcode(instr, BINARY_OP_SUBTRACT_FLOAT);
+                goto success;
+            }
+            break;
+    }
+    SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs));
+    STAT_INC(BINARY_OP, failure);
+    _py_set_opcode(instr, BINARY_OP);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(BINARY_OP, success);
+    cache->counter = adaptive_counter_cooldown();
+}
+
+
+#ifdef Py_STATS
+static int
+compare_op_fail_kind(PyObject *lhs, PyObject *rhs)
+{
+    if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
+        if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) {
+            return SPEC_FAIL_COMPARE_OP_FLOAT_LONG;
+        }
+        if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) {
+            return SPEC_FAIL_COMPARE_OP_LONG_FLOAT;
+        }
+        return SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES;
+    }
+    if (PyBytes_CheckExact(lhs)) {
+        return SPEC_FAIL_COMPARE_OP_BYTES;
+    }
+    if (PyTuple_CheckExact(lhs)) {
+        return SPEC_FAIL_COMPARE_OP_TUPLE;
+    }
+    if (PyList_CheckExact(lhs)) {
+        return SPEC_FAIL_COMPARE_OP_LIST;
+    }
+    if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) {
+        return SPEC_FAIL_COMPARE_OP_SET;
+    }
+    if (PyBool_Check(lhs)) {
+        return SPEC_FAIL_COMPARE_OP_BOOL;
+    }
+    if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) {
+        return SPEC_FAIL_COMPARE_OP_BASEOBJECT;
+    }
+    return SPEC_FAIL_OTHER;
+}
+#endif
+
+
+static int compare_masks[] = {
+    // 1-bit: jump if less than
+    // 2-bit: jump if equal
+    // 4-bit: jump if greater
+    [Py_LT] = 1 | 0 | 0,
+    [Py_LE] = 1 | 2 | 0,
+    [Py_EQ] = 0 | 2 | 0,
+    [Py_NE] = 1 | 0 | 4,
+    [Py_GT] = 0 | 0 | 4,
+    [Py_GE] = 0 | 2 | 4,
+};
+
+void
+_Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
+                         int oparg)
+{
+    assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP);
+    _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1);
+    int next_opcode = _Py_OPCODE(instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1]);
+    if (next_opcode != POP_JUMP_IF_FALSE && next_opcode != POP_JUMP_IF_TRUE) {
+        if (next_opcode == EXTENDED_ARG) {
+            SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_EXTENDED_ARG);
+            goto failure;
+        }
+        SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_NOT_FOLLOWED_BY_COND_JUMP);
+        goto failure;
+    }
+    assert(oparg <= Py_GE);
+    int when_to_jump_mask = compare_masks[oparg];
+    if (next_opcode == POP_JUMP_IF_FALSE) {
+        when_to_jump_mask = (1 | 2 | 4) & ~when_to_jump_mask;
+    }
+    if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
+        SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
+        goto failure;
+    }
+    if (PyFloat_CheckExact(lhs)) {
+        _py_set_opcode(instr, COMPARE_OP_FLOAT_JUMP);
+        cache->mask = when_to_jump_mask;
+        goto success;
+    }
+    if (PyLong_CheckExact(lhs)) {
+        if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) {
+            _py_set_opcode(instr, COMPARE_OP_INT_JUMP);
+            cache->mask = when_to_jump_mask;
+            goto success;
+        }
+        else {
+            SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_BIG_INT);
+            goto failure;
+        }
+    }
+    if (PyUnicode_CheckExact(lhs)) {
+        if (oparg != Py_EQ && oparg != Py_NE) {
+            SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING);
+            goto failure;
+        }
+        else {
+            _py_set_opcode(instr, COMPARE_OP_STR_JUMP);
+            cache->mask = (when_to_jump_mask & 2) == 0;
+            goto success;
+        }
+    }
+    SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
+failure:
+    STAT_INC(COMPARE_OP, failure);
+    _py_set_opcode(instr, COMPARE_OP);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(COMPARE_OP, success);
+    cache->counter = adaptive_counter_cooldown();
+}
+
+#ifdef Py_STATS
+static int
+unpack_sequence_fail_kind(PyObject *seq)
+{
+    if (PySequence_Check(seq)) {
+        return SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE;
+    }
+    if (PyIter_Check(seq)) {
+        return SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR;
+    }
+    return SPEC_FAIL_OTHER;
+}
+#endif
+
+void
+_Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg)
+{
+    assert(_PyOpcode_Caches[UNPACK_SEQUENCE] ==
+           INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
+    _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)(instr + 1);
+    if (PyTuple_CheckExact(seq)) {
+        if (PyTuple_GET_SIZE(seq) != oparg) {
+            SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR);
+            goto failure;
+        }
+        if (PyTuple_GET_SIZE(seq) == 2) {
+            _py_set_opcode(instr, UNPACK_SEQUENCE_TWO_TUPLE);
+            goto success;
+        }
+        _py_set_opcode(instr, UNPACK_SEQUENCE_TUPLE);
+        goto success;
+    }
+    if (PyList_CheckExact(seq)) {
+        if (PyList_GET_SIZE(seq) != oparg) {
+            SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR);
+            goto failure;
+        }
+        _py_set_opcode(instr, UNPACK_SEQUENCE_LIST);
+        goto success;
+    }
+    SPECIALIZATION_FAIL(UNPACK_SEQUENCE, unpack_sequence_fail_kind(seq));
+failure:
+    STAT_INC(UNPACK_SEQUENCE, failure);
+    _py_set_opcode(instr, UNPACK_SEQUENCE);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(UNPACK_SEQUENCE, success);
+    cache->counter = adaptive_counter_cooldown();
+}
+
+#ifdef Py_STATS
+
+int
+ _PySpecialization_ClassifyIterator(PyObject *iter)
+{
+    if (PyGen_CheckExact(iter)) {
+        return SPEC_FAIL_FOR_ITER_GENERATOR;
+    }
+    if (PyCoro_CheckExact(iter)) {
+        return SPEC_FAIL_FOR_ITER_COROUTINE;
+    }
+    if (PyAsyncGen_CheckExact(iter)) {
+        return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR;
+    }
+    PyTypeObject *t = Py_TYPE(iter);
+    if (t == &PyListIter_Type) {
+        return SPEC_FAIL_FOR_ITER_LIST;
+    }
+    if (t == &PyTupleIter_Type) {
+        return SPEC_FAIL_FOR_ITER_TUPLE;
+    }
+    if (t == &PyDictIterKey_Type) {
+        return SPEC_FAIL_FOR_ITER_DICT_KEYS;
+    }
+    if (t == &PyDictIterValue_Type) {
+        return SPEC_FAIL_FOR_ITER_DICT_VALUES;
+    }
+    if (t == &PyDictIterItem_Type) {
+        return SPEC_FAIL_FOR_ITER_DICT_ITEMS;
+    }
+    if (t == &PySetIter_Type) {
+        return SPEC_FAIL_FOR_ITER_SET;
+    }
+    if (t == &PyUnicodeIter_Type) {
+        return SPEC_FAIL_FOR_ITER_STRING;
+    }
+    if (t == &PyBytesIter_Type) {
+        return SPEC_FAIL_FOR_ITER_BYTES;
+    }
+    if (t == &PyRangeIter_Type) {
+        return SPEC_FAIL_FOR_ITER_RANGE;
+    }
+    if (t == &PyEnum_Type) {
+        return SPEC_FAIL_FOR_ITER_ENUMERATE;
+    }
+    if (t == &PyMap_Type) {
+        return SPEC_FAIL_FOR_ITER_MAP;
+    }
+    if (t == &PyZip_Type) {
+        return SPEC_FAIL_FOR_ITER_ZIP;
+    }
+    if (t == &PySeqIter_Type) {
+        return SPEC_FAIL_FOR_ITER_SEQ_ITER;
+    }
+    if (t == &PyListRevIter_Type) {
+        return SPEC_FAIL_FOR_ITER_REVERSED_LIST;
+    }
+    if (t == &_PyUnicodeASCIIIter_Type) {
+        return SPEC_FAIL_FOR_ITER_ASCII_STRING;
+    }
+    const char *name = t->tp_name;
+    if (strncmp(name, "itertools", 9) == 0) {
+        return SPEC_FAIL_FOR_ITER_ITERTOOLS;
+    }
+    if (strncmp(name, "callable_iterator", 17) == 0) {
+        return SPEC_FAIL_FOR_ITER_CALLABLE;
+    }
+    return SPEC_FAIL_OTHER;
+}
+
+#endif
+
+void
+_Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
+{
+    assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER);
+    _PyForIterCache *cache = (_PyForIterCache *)(instr + 1);
+    PyTypeObject *tp = Py_TYPE(iter);
+    _Py_CODEUNIT next = instr[1+INLINE_CACHE_ENTRIES_FOR_ITER];
+    int next_op = _PyOpcode_Deopt[_Py_OPCODE(next)];
+    if (tp == &PyListIter_Type) {
+        _py_set_opcode(instr, FOR_ITER_LIST);
+        goto success;
+    }
+    else if (tp == &PyTupleIter_Type) {
+        _py_set_opcode(instr, FOR_ITER_TUPLE);
+        goto success;
+    }
+    else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) {
+        _py_set_opcode(instr, FOR_ITER_RANGE);
+        goto success;
+    }
+    else if (tp == &PyGen_Type && oparg <= SHRT_MAX) {
+        assert(_Py_OPCODE(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1]) == END_FOR);
+        _py_set_opcode(instr, FOR_ITER_GEN);
+        goto success;
+    }
+    SPECIALIZATION_FAIL(FOR_ITER,
+                        _PySpecialization_ClassifyIterator(iter));
+    STAT_INC(FOR_ITER, failure);
+    _py_set_opcode(instr, FOR_ITER);
+    cache->counter = adaptive_counter_backoff(cache->counter);
+    return;
+success:
+    STAT_INC(FOR_ITER, success);
+    cache->counter = adaptive_counter_cooldown();
+}
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index c56f1d3ef9f498..b8e0df3f054516 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2726,6 +2726,29 @@ dummy_func(
             JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
         }
 
+        // error: LOAD_ATTR has irregular stack effect
+        inst(LOAD_ATTR_METHOD_MANAGED_DICT) {
+            assert(cframe.use_tracing == 0);
+            PyObject *self = TOP();
+            PyTypeObject *self_cls = Py_TYPE(self);
+            _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
+            uint32_t type_version = read_u32(cache->type_version);
+            assert(type_version != 0);
+            DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR)
+            assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+            PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
+            DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+            PyDictKeysObject *keys = ((PyHeapTypeObject *)self_cls)->ht_cached_keys;
+            DEOPT_IF(keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
+            STAT_INC(LOAD_ATTR, hit);
+            PyObject *res = read_obj(cache->descr);
+            assert(res != NULL);
+            assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
+            SET_TOP(Py_NewRef(res));
+            PUSH(self);
+            JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
+        }
+
         // error: LOAD_ATTR has irregular stack effect
         inst(LOAD_ATTR_METHOD_WITH_DICT) {
             /* Can be either a managed dict, or a tp_dictoffset offset.*/
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 63635fbfc2f4cb..85ba03d47f8054 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2968,6 +2968,29 @@
             DISPATCH();
         }
 
+        TARGET(LOAD_ATTR_METHOD_MANAGED_DICT) {
+            assert(cframe.use_tracing == 0);
+            PyObject *self = TOP();
+            PyTypeObject *self_cls = Py_TYPE(self);
+            _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
+            uint32_t type_version = read_u32(cache->type_version);
+            assert(type_version != 0);
+            DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR)
+            assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+            PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
+            DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
+            PyDictKeysObject *keys = ((PyHeapTypeObject *)self_cls)->ht_cached_keys;
+            DEOPT_IF(keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
+            STAT_INC(LOAD_ATTR, hit);
+            PyObject *res = read_obj(cache->descr);
+            assert(res != NULL);
+            assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
+            SET_TOP(Py_NewRef(res));
+            PUSH(self);
+            JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
+            DISPATCH();
+        }
+
         TARGET(LOAD_ATTR_METHOD_WITH_DICT) {
             /* Can be either a managed dict, or a tp_dictoffset offset.*/
             assert(cframe.use_tracing == 0);
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index be3ad01c151c04..67f5bacecc8c74 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -80,12 +80,12 @@ static void *opcode_targets[256] = {
     &&TARGET_LOAD_ATTR_WITH_HINT,
     &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
     &&TARGET_LOAD_ATTR_METHOD_NO_DICT,
-    &&TARGET_LOAD_ATTR_METHOD_WITH_DICT,
+    &&TARGET_LOAD_ATTR_METHOD_MANAGED_DICT,
     &&TARGET_LIST_TO_TUPLE,
     &&TARGET_RETURN_VALUE,
     &&TARGET_IMPORT_STAR,
     &&TARGET_SETUP_ANNOTATIONS,
-    &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
+    &&TARGET_LOAD_ATTR_METHOD_WITH_DICT,
     &&TARGET_ASYNC_GEN_WRAP,
     &&TARGET_PREP_RERAISE_STAR,
     &&TARGET_POP_EXCEPT,
@@ -112,7 +112,7 @@ static void *opcode_targets[256] = {
     &&TARGET_JUMP_FORWARD,
     &&TARGET_JUMP_IF_FALSE_OR_POP,
     &&TARGET_JUMP_IF_TRUE_OR_POP,
-    &&TARGET_LOAD_CONST__LOAD_FAST,
+    &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
     &&TARGET_POP_JUMP_IF_FALSE,
     &&TARGET_POP_JUMP_IF_TRUE,
     &&TARGET_LOAD_GLOBAL,
@@ -120,7 +120,7 @@ static void *opcode_targets[256] = {
     &&TARGET_CONTAINS_OP,
     &&TARGET_RERAISE,
     &&TARGET_COPY,
-    &&TARGET_LOAD_FAST__LOAD_CONST,
+    &&TARGET_LOAD_CONST__LOAD_FAST,
     &&TARGET_BINARY_OP,
     &&TARGET_SEND,
     &&TARGET_LOAD_FAST,
@@ -140,9 +140,9 @@ static void *opcode_targets[256] = {
     &&TARGET_STORE_DEREF,
     &&TARGET_DELETE_DEREF,
     &&TARGET_JUMP_BACKWARD,
-    &&TARGET_LOAD_FAST__LOAD_FAST,
+    &&TARGET_LOAD_FAST__LOAD_CONST,
     &&TARGET_CALL_FUNCTION_EX,
-    &&TARGET_LOAD_GLOBAL_BUILTIN,
+    &&TARGET_LOAD_FAST__LOAD_FAST,
     &&TARGET_EXTENDED_ARG,
     &&TARGET_LIST_APPEND,
     &&TARGET_SET_ADD,
@@ -152,27 +152,27 @@ static void *opcode_targets[256] = {
     &&TARGET_YIELD_VALUE,
     &&TARGET_RESUME,
     &&TARGET_MATCH_CLASS,
+    &&TARGET_LOAD_GLOBAL_BUILTIN,
     &&TARGET_LOAD_GLOBAL_MODULE,
-    &&TARGET_STORE_ATTR_INSTANCE_VALUE,
     &&TARGET_FORMAT_VALUE,
     &&TARGET_BUILD_CONST_KEY_MAP,
     &&TARGET_BUILD_STRING,
+    &&TARGET_STORE_ATTR_INSTANCE_VALUE,
     &&TARGET_STORE_ATTR_SLOT,
     &&TARGET_STORE_ATTR_WITH_HINT,
     &&TARGET_STORE_FAST__LOAD_FAST,
-    &&TARGET_STORE_FAST__STORE_FAST,
     &&TARGET_LIST_EXTEND,
     &&TARGET_SET_UPDATE,
     &&TARGET_DICT_MERGE,
     &&TARGET_DICT_UPDATE,
+    &&TARGET_STORE_FAST__STORE_FAST,
     &&TARGET_STORE_SUBSCR_DICT,
     &&TARGET_STORE_SUBSCR_LIST_INT,
     &&TARGET_UNPACK_SEQUENCE_LIST,
     &&TARGET_UNPACK_SEQUENCE_TUPLE,
-    &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
     &&TARGET_CALL,
     &&TARGET_KW_NAMES,
-    &&_unknown_opcode,
+    &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
diff --git a/Python/specialize.c b/Python/specialize.c
index d1a38450fff02a..0ef98fe62927e8 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -334,7 +334,6 @@ _PyCode_Quicken(PyCodeObject *code)
 #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
 #define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23
 #define SPEC_FAIL_ATTR_OBJECT_SLOT 24
-#define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25
 #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26
 #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27
 #define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28
@@ -1020,6 +1019,7 @@ PyObject *descr, DescriptorClassification kind)
             dictkind = MANAGED_VALUES;
         }
         else {
+            // User has directly accessed __dict__.
             dictkind = MANAGED_DICT;
         }
     }
@@ -1046,7 +1046,7 @@ PyObject *descr, DescriptorClassification kind)
             }
         }
     }
-    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT) {
+    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT || dictkind == MANAGED_DICT) {
         Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
         if (index != DKIX_EMPTY) {
             SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
@@ -1067,8 +1067,8 @@ PyObject *descr, DescriptorClassification kind)
             _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_VALUES);
             break;
         case MANAGED_DICT:
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT);
-            goto fail;
+            _py_set_opcode(instr, LOAD_ATTR_METHOD_MANAGED_DICT);
+            break;
         case OFFSET_DICT:
             assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
             _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_DICT);

From e209b9e898bda3f748bffb4fd2e3e34346b55d4b Mon Sep 17 00:00:00 2001
From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Date: Fri, 16 Dec 2022 16:44:47 +0800
Subject: [PATCH 2/4] Remove a temp file

---
 .../specialize.c                              | 2177 -----------------
 1 file changed, 2177 deletions(-)
 delete mode 100644 PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c

diff --git a/PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c b/PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c
deleted file mode 100644
index 1dfba1b8609b74..00000000000000
--- a/PCbuild/enc_temp_folder/229bb4fd2db66edaf5b17b24bdacb6c/specialize.c
+++ /dev/null
@@ -1,2177 +0,0 @@
-#include "Python.h"
-#include "pycore_code.h"
-#include "pycore_dict.h"
-#include "pycore_function.h"      // _PyFunction_GetVersionForCurrentState()
-#include "pycore_global_strings.h"  // _Py_ID()
-#include "pycore_long.h"
-#include "pycore_moduleobject.h"
-#include "pycore_object.h"
-#include "pycore_opcode.h"        // _PyOpcode_Caches
-#include "structmember.h"         // struct PyMemberDef, T_OFFSET_EX
-#include "pycore_descrobject.h"
-
-#include <stdlib.h> // rand()
-
-/* For guidance on adding or extending families of instructions see
- * ./adaptive.md
- */
-
-#ifdef Py_STATS
-PyStats _py_stats_struct = { 0 };
-PyStats *_py_stats = NULL;
-
-#define ADD_STAT_TO_DICT(res, field) \
-    do { \
-        PyObject *val = PyLong_FromUnsignedLongLong(stats->field); \
-        if (val == NULL) { \
-            Py_DECREF(res); \
-            return NULL; \
-        } \
-        if (PyDict_SetItemString(res, #field, val) == -1) { \
-            Py_DECREF(res); \
-            Py_DECREF(val); \
-            return NULL; \
-        } \
-        Py_DECREF(val); \
-    } while(0);
-
-static PyObject*
-stats_to_dict(SpecializationStats *stats)
-{
-    PyObject *res = PyDict_New();
-    if (res == NULL) {
-        return NULL;
-    }
-    ADD_STAT_TO_DICT(res, success);
-    ADD_STAT_TO_DICT(res, failure);
-    ADD_STAT_TO_DICT(res, hit);
-    ADD_STAT_TO_DICT(res, deferred);
-    ADD_STAT_TO_DICT(res, miss);
-    ADD_STAT_TO_DICT(res, deopt);
-    PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS);
-    if (failure_kinds == NULL) {
-        Py_DECREF(res);
-        return NULL;
-    }
-    for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) {
-        PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]);
-        if (stat == NULL) {
-            Py_DECREF(res);
-            Py_DECREF(failure_kinds);
-            return NULL;
-        }
-        PyTuple_SET_ITEM(failure_kinds, i, stat);
-    }
-    if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) {
-        Py_DECREF(res);
-        Py_DECREF(failure_kinds);
-        return NULL;
-    }
-    Py_DECREF(failure_kinds);
-    return res;
-}
-#undef ADD_STAT_TO_DICT
-
-static int
-add_stat_dict(
-    PyObject *res,
-    int opcode,
-    const char *name) {
-
-    SpecializationStats *stats = &_py_stats_struct.opcode_stats[opcode].specialization;
-    PyObject *d = stats_to_dict(stats);
-    if (d == NULL) {
-        return -1;
-    }
-    int err = PyDict_SetItemString(res, name, d);
-    Py_DECREF(d);
-    return err;
-}
-
-#ifdef Py_STATS
-PyObject*
-_Py_GetSpecializationStats(void) {
-    PyObject *stats = PyDict_New();
-    if (stats == NULL) {
-        return NULL;
-    }
-    int err = 0;
-    err += add_stat_dict(stats, LOAD_ATTR, "load_attr");
-    err += add_stat_dict(stats, LOAD_GLOBAL, "load_global");
-    err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr");
-    err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr");
-    err += add_stat_dict(stats, STORE_ATTR, "store_attr");
-    err += add_stat_dict(stats, CALL, "call");
-    err += add_stat_dict(stats, BINARY_OP, "binary_op");
-    err += add_stat_dict(stats, COMPARE_OP, "compare_op");
-    err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence");
-    err += add_stat_dict(stats, FOR_ITER, "for_iter");
-    if (err < 0) {
-        Py_DECREF(stats);
-        return NULL;
-    }
-    return stats;
-}
-#endif
-
-
-#define PRINT_STAT(i, field) \
-    if (stats[i].field) { \
-        fprintf(out, "    opcode[%d]." #field " : %" PRIu64 "\n", i, stats[i].field); \
-    }
-
-static void
-print_spec_stats(FILE *out, OpcodeStats *stats)
-{
-    /* Mark some opcodes as specializable for stats,
-     * even though we don't specialize them yet. */
-    fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE);
-    fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE);
-    for (int i = 0; i < 256; i++) {
-        if (_PyOpcode_Caches[i]) {
-            fprintf(out, "opcode[%d].specializable : 1\n", i);
-        }
-        PRINT_STAT(i, specialization.success);
-        PRINT_STAT(i, specialization.failure);
-        PRINT_STAT(i, specialization.hit);
-        PRINT_STAT(i, specialization.deferred);
-        PRINT_STAT(i, specialization.miss);
-        PRINT_STAT(i, specialization.deopt);
-        PRINT_STAT(i, execution_count);
-        for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) {
-            uint64_t val = stats[i].specialization.failure_kinds[j];
-            if (val) {
-                fprintf(out, "    opcode[%d].specialization.failure_kinds[%d] : %"
-                    PRIu64 "\n", i, j, val);
-            }
-        }
-        for(int j = 0; j < 256; j++) {
-            if (stats[i].pair_count[j]) {
-                fprintf(out, "opcode[%d].pair_count[%d] : %" PRIu64 "\n",
-                        i, j, stats[i].pair_count[j]);
-            }
-        }
-    }
-}
-#undef PRINT_STAT
-
-
-static void
-print_call_stats(FILE *out, CallStats *stats)
-{
-    fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls);
-    fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls);
-    fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed);
-    fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created);
-    for (int i = 0; i < EVAL_CALL_KINDS; i++) {
-        fprintf(out, "Calls via PyEval_EvalFrame[%d] : %" PRIu64 "\n", i, stats->eval_calls[i]);
-    }
-}
-
-static void
-print_object_stats(FILE *out, ObjectStats *stats)
-{
-    fprintf(out, "Object allocations from freelist: %" PRIu64 "\n", stats->from_freelist);
-    fprintf(out, "Object frees to freelist: %" PRIu64 "\n", stats->to_freelist);
-    fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations);
-    fprintf(out, "Object allocations to 512 bytes: %" PRIu64 "\n", stats->allocations512);
-    fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k);
-    fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big);
-    fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees);
-    fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values);
-    fprintf(out, "Object interpreter increfs: %" PRIu64 "\n", stats->interpreter_increfs);
-    fprintf(out, "Object interpreter decrefs: %" PRIu64 "\n", stats->interpreter_decrefs);
-    fprintf(out, "Object increfs: %" PRIu64 "\n", stats->increfs);
-    fprintf(out, "Object decrefs: %" PRIu64 "\n", stats->decrefs);
-    fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request);
-    fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
-    fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
-    fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
-    fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits);
-    fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses);
-    fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
-    fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits);
-    fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses);
-}
-
-static void
-print_stats(FILE *out, PyStats *stats) {
-    print_spec_stats(out, stats->opcode_stats);
-    print_call_stats(out, &stats->call_stats);
-    print_object_stats(out, &stats->object_stats);
-}
-
-void
-_Py_StatsClear(void)
-{
-    _py_stats_struct = (PyStats) { 0 };
-}
-
-void
-_Py_PrintSpecializationStats(int to_file)
-{
-    FILE *out = stderr;
-    if (to_file) {
-        /* Write to a file instead of stderr. */
-# ifdef MS_WINDOWS
-        const char *dirname = "c:\\temp\\py_stats\\";
-# else
-        const char *dirname = "/tmp/py_stats/";
-# endif
-        /* Use random 160 bit number as file name,
-        * to avoid both accidental collisions and
-        * symlink attacks. */
-        unsigned char rand[20];
-        char hex_name[41];
-        _PyOS_URandomNonblock(rand, 20);
-        for (int i = 0; i < 20; i++) {
-            hex_name[2*i] = "0123456789abcdef"[rand[i]&15];
-            hex_name[2*i+1] = "0123456789abcdef"[(rand[i]>>4)&15];
-        }
-        hex_name[40] = '\0';
-        char buf[64];
-        assert(strlen(dirname) + 40 + strlen(".txt") < 64);
-        sprintf(buf, "%s%s.txt", dirname, hex_name);
-        FILE *fout = fopen(buf, "w");
-        if (fout) {
-            out = fout;
-        }
-    }
-    else {
-        fprintf(out, "Specialization stats:\n");
-    }
-    print_stats(out, &_py_stats_struct);
-    if (out != stderr) {
-        fclose(out);
-    }
-}
-
-#ifdef Py_STATS
-
-#define SPECIALIZATION_FAIL(opcode, kind) \
-do { \
-    if (_py_stats) { \
-        _py_stats->opcode_stats[opcode].specialization.failure_kinds[kind]++; \
-    } \
-} while (0)
-
-#endif
-#endif
-
-#ifndef SPECIALIZATION_FAIL
-#define SPECIALIZATION_FAIL(opcode, kind) ((void)0)
-#endif
-
-// Initialize warmup counters and insert superinstructions. This cannot fail.
-void
-_PyCode_Quicken(PyCodeObject *code)
-{
-    int previous_opcode = 0;
-    _Py_CODEUNIT *instructions = _PyCode_CODE(code);
-    for (int i = 0; i < Py_SIZE(code); i++) {
-        int opcode = _PyOpcode_Deopt[_Py_OPCODE(instructions[i])];
-        int caches = _PyOpcode_Caches[opcode];
-        if (caches) {
-            instructions[i + 1].cache = adaptive_counter_warmup();
-            previous_opcode = 0;
-            i += caches;
-            continue;
-        }
-        switch (previous_opcode << 8 | opcode) {
-            case LOAD_CONST << 8 | LOAD_FAST:
-                instructions[i - 1].opcode = LOAD_CONST__LOAD_FAST;
-                break;
-            case LOAD_FAST << 8 | LOAD_CONST:
-                instructions[i - 1].opcode = LOAD_FAST__LOAD_CONST;
-                break;
-            case LOAD_FAST << 8 | LOAD_FAST:
-                instructions[i - 1].opcode = LOAD_FAST__LOAD_FAST;
-                break;
-            case STORE_FAST << 8 | LOAD_FAST:
-                instructions[i - 1].opcode = STORE_FAST__LOAD_FAST;
-                break;
-            case STORE_FAST << 8 | STORE_FAST:
-                instructions[i - 1].opcode = STORE_FAST__STORE_FAST;
-                break;
-        }
-        previous_opcode = opcode;
-    }
-}
-
-#define SIMPLE_FUNCTION 0
-
-/* Common */
-
-#define SPEC_FAIL_OTHER 0
-#define SPEC_FAIL_NO_DICT 1
-#define SPEC_FAIL_OVERRIDDEN 2
-#define SPEC_FAIL_OUT_OF_VERSIONS 3
-#define SPEC_FAIL_OUT_OF_RANGE 4
-#define SPEC_FAIL_EXPECTED_ERROR 5
-#define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 6
-#define SPEC_FAIL_NOT_PY_FUNCTION 7
-
-
-#define SPEC_FAIL_LOAD_GLOBAL_NON_DICT 17
-#define SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT 18
-
-/* Attributes */
-
-#define SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR 8
-#define SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR 9
-#define SPEC_FAIL_ATTR_NOT_DESCRIPTOR 10
-#define SPEC_FAIL_ATTR_METHOD 11
-#define SPEC_FAIL_ATTR_MUTABLE_CLASS 12
-#define SPEC_FAIL_ATTR_PROPERTY 13
-#define SPEC_FAIL_ATTR_NON_OBJECT_SLOT 14
-#define SPEC_FAIL_ATTR_READ_ONLY 15
-#define SPEC_FAIL_ATTR_AUDITED_SLOT 16
-#define SPEC_FAIL_ATTR_NOT_MANAGED_DICT 17
-#define SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT 18
-#define SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND 19
-
-#define SPEC_FAIL_ATTR_SHADOWED 21
-#define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
-#define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23
-#define SPEC_FAIL_ATTR_OBJECT_SLOT 24
-#define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25
-#define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26
-#define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27
-#define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28
-#define SPEC_FAIL_ATTR_NOT_IN_KEYS 29
-#define SPEC_FAIL_ATTR_NOT_IN_DICT 30
-
-/* Binary subscr and store subscr */
-
-#define SPEC_FAIL_SUBSCR_ARRAY_INT 8
-#define SPEC_FAIL_SUBSCR_ARRAY_SLICE 9
-#define SPEC_FAIL_SUBSCR_LIST_SLICE 10
-#define SPEC_FAIL_SUBSCR_TUPLE_SLICE 11
-#define SPEC_FAIL_SUBSCR_STRING_INT 12
-#define SPEC_FAIL_SUBSCR_STRING_SLICE 13
-#define SPEC_FAIL_SUBSCR_BUFFER_INT 15
-#define SPEC_FAIL_SUBSCR_BUFFER_SLICE 16
-#define SPEC_FAIL_SUBSCR_SEQUENCE_INT 17
-
-/* Store subscr */
-#define SPEC_FAIL_SUBSCR_BYTEARRAY_INT 18
-#define SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE 19
-#define SPEC_FAIL_SUBSCR_PY_SIMPLE 20
-#define SPEC_FAIL_SUBSCR_PY_OTHER 21
-#define SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE 22
-#define SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE 23
-
-/* Binary op */
-
-#define SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES          8
-#define SPEC_FAIL_BINARY_OP_ADD_OTHER                    9
-#define SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES         10
-#define SPEC_FAIL_BINARY_OP_AND_INT                     11
-#define SPEC_FAIL_BINARY_OP_AND_OTHER                   12
-#define SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE                13
-#define SPEC_FAIL_BINARY_OP_LSHIFT                      14
-#define SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY             15
-#define SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES    16
-#define SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER              17
-#define SPEC_FAIL_BINARY_OP_OR                          18
-#define SPEC_FAIL_BINARY_OP_POWER                       19
-#define SPEC_FAIL_BINARY_OP_REMAINDER                   20
-#define SPEC_FAIL_BINARY_OP_RSHIFT                      21
-#define SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES    22
-#define SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER              23
-#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES 24
-#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT           25
-#define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER           26
-#define SPEC_FAIL_BINARY_OP_XOR                         27
-
-/* Calls */
-#define SPEC_FAIL_CALL_COMPLEX_PARAMETERS 9
-#define SPEC_FAIL_CALL_CO_NOT_OPTIMIZED 10
-/* SPEC_FAIL_METHOD  defined as 11 above */
-
-#define SPEC_FAIL_CALL_INSTANCE_METHOD 11
-#define SPEC_FAIL_CALL_CMETHOD 12
-#define SPEC_FAIL_CALL_PYCFUNCTION 13
-#define SPEC_FAIL_CALL_PYCFUNCTION_WITH_KEYWORDS 14
-#define SPEC_FAIL_CALL_PYCFUNCTION_FAST_WITH_KEYWORDS 15
-#define SPEC_FAIL_CALL_PYCFUNCTION_NOARGS 16
-#define SPEC_FAIL_CALL_BAD_CALL_FLAGS 17
-#define SPEC_FAIL_CALL_CLASS 18
-#define SPEC_FAIL_CALL_PYTHON_CLASS 19
-#define SPEC_FAIL_CALL_METHOD_DESCRIPTOR 20
-#define SPEC_FAIL_CALL_BOUND_METHOD 21
-#define SPEC_FAIL_CALL_STR 22
-#define SPEC_FAIL_CALL_CLASS_NO_VECTORCALL 23
-#define SPEC_FAIL_CALL_CLASS_MUTABLE 24
-#define SPEC_FAIL_CALL_KWNAMES 25
-#define SPEC_FAIL_CALL_METHOD_WRAPPER 26
-#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 27
-#define SPEC_FAIL_CALL_PYFUNCTION 28
-#define SPEC_FAIL_CALL_PEP_523 29
-
-/* COMPARE_OP */
-#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
-#define SPEC_FAIL_COMPARE_OP_STRING 13
-#define SPEC_FAIL_COMPARE_OP_NOT_FOLLOWED_BY_COND_JUMP 14
-#define SPEC_FAIL_COMPARE_OP_BIG_INT 15
-#define SPEC_FAIL_COMPARE_OP_BYTES 16
-#define SPEC_FAIL_COMPARE_OP_TUPLE 17
-#define SPEC_FAIL_COMPARE_OP_LIST 18
-#define SPEC_FAIL_COMPARE_OP_SET 19
-#define SPEC_FAIL_COMPARE_OP_BOOL 20
-#define SPEC_FAIL_COMPARE_OP_BASEOBJECT 21
-#define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 22
-#define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 23
-#define SPEC_FAIL_COMPARE_OP_EXTENDED_ARG 24
-
-/* FOR_ITER */
-#define SPEC_FAIL_FOR_ITER_GENERATOR 10
-#define SPEC_FAIL_FOR_ITER_COROUTINE 11
-#define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12
-#define SPEC_FAIL_FOR_ITER_LIST 13
-#define SPEC_FAIL_FOR_ITER_TUPLE 14
-#define SPEC_FAIL_FOR_ITER_SET 15
-#define SPEC_FAIL_FOR_ITER_STRING 16
-#define SPEC_FAIL_FOR_ITER_BYTES 17
-#define SPEC_FAIL_FOR_ITER_RANGE 18
-#define SPEC_FAIL_FOR_ITER_ITERTOOLS 19
-#define SPEC_FAIL_FOR_ITER_DICT_KEYS 20
-#define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21
-#define SPEC_FAIL_FOR_ITER_DICT_VALUES 22
-#define SPEC_FAIL_FOR_ITER_ENUMERATE 23
-#define SPEC_FAIL_FOR_ITER_MAP 24
-#define SPEC_FAIL_FOR_ITER_ZIP 25
-#define SPEC_FAIL_FOR_ITER_SEQ_ITER 26
-#define SPEC_FAIL_FOR_ITER_REVERSED_LIST 27
-#define SPEC_FAIL_FOR_ITER_CALLABLE 28
-#define SPEC_FAIL_FOR_ITER_ASCII_STRING 29
-
-// UNPACK_SEQUENCE
-
-#define SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR 8
-#define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 9
-
-static int function_kind(PyCodeObject *code);
-static bool function_check_args(PyObject *o, int expected_argcount, int opcode);
-static uint32_t function_get_version(PyObject *o, int opcode);
-
-static int
-specialize_module_load_attr(
-    PyObject *owner, _Py_CODEUNIT *instr, PyObject *name
-) {
-    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
-    PyModuleObject *m = (PyModuleObject *)owner;
-    assert((owner->ob_type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0);
-    PyDictObject *dict = (PyDictObject *)m->md_dict;
-    if (dict == NULL) {
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NO_DICT);
-        return -1;
-    }
-    if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT);
-        return -1;
-    }
-    Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__));
-    assert(index != DKIX_ERROR);
-    if (index != DKIX_EMPTY) {
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND);
-        return -1;
-    }
-    index = _PyDict_LookupIndex(dict, name);
-    assert (index != DKIX_ERROR);
-    if (index != (uint16_t)index) {
-        SPECIALIZATION_FAIL(LOAD_ATTR,
-                            index == DKIX_EMPTY ?
-                            SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND :
-                            SPEC_FAIL_OUT_OF_RANGE);
-        return -1;
-    }
-    uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(dict->ma_keys);
-    if (keys_version == 0) {
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
-        return -1;
-    }
-    write_u32(cache->version, keys_version);
-    cache->index = (uint16_t)index;
-    _py_set_opcode(instr, LOAD_ATTR_MODULE);
-    return 0;
-}
-
-
-
-/* Attribute specialization */
-
-typedef enum {
-    OVERRIDING, /* Is an overriding descriptor, and will remain so. */
-    METHOD, /* Attribute has Py_TPFLAGS_METHOD_DESCRIPTOR set */
-    PROPERTY, /* Is a property */
-    OBJECT_SLOT, /* Is an object slot descriptor */
-    OTHER_SLOT, /* Is a slot descriptor of another type */
-    NON_OVERRIDING, /* Is another non-overriding descriptor, and is an instance of an immutable class*/
-    BUILTIN_CLASSMETHOD, /* Builtin methods with METH_CLASS */
-    PYTHON_CLASSMETHOD, /* Python classmethod(func) object */
-    NON_DESCRIPTOR, /* Is not a descriptor, and is an instance of an immutable class */
-    MUTABLE,   /* Instance of a mutable class; might, or might not, be a descriptor */
-    ABSENT, /* Attribute is not present on the class */
-    DUNDER_CLASS, /* __class__ attribute */
-    GETSET_OVERRIDDEN, /* __getattribute__ or __setattr__ has been overridden */
-    GETATTRIBUTE_IS_PYTHON_FUNCTION  /* Descriptor requires calling a Python __getattribute__ */
-} DescriptorClassification;
-
-
-static DescriptorClassification
-analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store)
-{
-    bool has_getattr = false;
-    if (store) {
-        if (type->tp_setattro != PyObject_GenericSetAttr) {
-            *descr = NULL;
-            return GETSET_OVERRIDDEN;
-        }
-    }
-    else {
-        getattrofunc getattro_slot = type->tp_getattro;
-        if (getattro_slot == PyObject_GenericGetAttr) {
-            /* Normal attribute lookup; */
-            has_getattr = false;
-        }
-        else if (getattro_slot == _Py_slot_tp_getattr_hook ||
-            getattro_slot == _Py_slot_tp_getattro) {
-            /* One or both of __getattribute__ or __getattr__ may have been
-             overridden See typeobject.c for why these functions are special. */
-            PyObject *getattribute = _PyType_Lookup(type,
-                &_Py_ID(__getattribute__));
-            PyInterpreterState *interp = _PyInterpreterState_GET();
-            bool has_custom_getattribute = getattribute != NULL &&
-                getattribute != interp->callable_cache.object__getattribute__;
-            has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL;
-            if (has_custom_getattribute) {
-                if (getattro_slot == _Py_slot_tp_getattro &&
-                    !has_getattr &&
-                    Py_IS_TYPE(getattribute, &PyFunction_Type)) {
-                    *descr = getattribute;
-                    return GETATTRIBUTE_IS_PYTHON_FUNCTION;
-                }
-                /* Potentially both __getattr__ and __getattribute__ are set.
-                   Too complicated */
-                *descr = NULL;
-                return GETSET_OVERRIDDEN;
-            }
-            /* Potentially has __getattr__ but no custom __getattribute__.
-               Fall through to usual descriptor analysis.
-               Usual attribute lookup should only be allowed at runtime
-               if we can guarantee that there is no way an exception can be
-               raised. This means some specializations, e.g. specializing
-               for property() isn't safe.
-            */
-        }
-        else {
-            *descr = NULL;
-            return GETSET_OVERRIDDEN;
-        }
-    }
-    PyObject *descriptor = _PyType_Lookup(type, name);
-    *descr = descriptor;
-    if (descriptor == NULL) {
-        return ABSENT;
-    }
-    PyTypeObject *desc_cls = Py_TYPE(descriptor);
-    if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) {
-        return MUTABLE;
-    }
-    if (desc_cls->tp_descr_set) {
-        if (desc_cls == &PyMemberDescr_Type) {
-            PyMemberDescrObject *member = (PyMemberDescrObject *)descriptor;
-            struct PyMemberDef *dmem = member->d_member;
-            if (dmem->type == T_OBJECT_EX) {
-                return OBJECT_SLOT;
-            }
-            return OTHER_SLOT;
-        }
-        if (desc_cls == &PyProperty_Type) {
-            /* We can't detect at runtime whether an attribute exists
-               with property. So that means we may have to call
-               __getattr__. */
-            return has_getattr ? GETSET_OVERRIDDEN : PROPERTY;
-        }
-        if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) {
-            if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) {
-                return DUNDER_CLASS;
-            }
-        }
-        if (store) {
-            return OVERRIDING;
-        }
-    }
-    if (desc_cls->tp_descr_get) {
-        if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) {
-            return METHOD;
-        }
-        if (Py_IS_TYPE(descriptor, &PyClassMethodDescr_Type)) {
-            return BUILTIN_CLASSMETHOD;
-        }
-        if (Py_IS_TYPE(descriptor, &PyClassMethod_Type)) {
-            return PYTHON_CLASSMETHOD;
-        }
-        return NON_OVERRIDING;
-    }
-    return NON_DESCRIPTOR;
-}
-
-static int
-specialize_dict_access(
-    PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type,
-    DescriptorClassification kind, PyObject *name,
-    int base_op, int values_op, int hint_op)
-{
-    assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT ||
-        kind == BUILTIN_CLASSMETHOD || kind == PYTHON_CLASSMETHOD);
-    // No descriptor, or non overriding.
-    if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
-        SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
-        return 0;
-    }
-    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
-    PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
-    if (_PyDictOrValues_IsValues(dorv)) {
-        // Virtual dictionary
-        PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
-        assert(PyUnicode_CheckExact(name));
-        Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
-        assert (index != DKIX_ERROR);
-        if (index != (uint16_t)index) {
-            SPECIALIZATION_FAIL(base_op,
-                                index == DKIX_EMPTY ?
-                                SPEC_FAIL_ATTR_NOT_IN_KEYS :
-                                SPEC_FAIL_OUT_OF_RANGE);
-            return 0;
-        }
-        write_u32(cache->version, type->tp_version_tag);
-        cache->index = (uint16_t)index;
-        _py_set_opcode(instr, values_op);
-    }
-    else {
-        PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
-        if (dict == NULL || !PyDict_CheckExact(dict)) {
-            SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
-            return 0;
-        }
-        // We found an instance with a __dict__.
-        Py_ssize_t index =
-            _PyDict_LookupIndex(dict, name);
-        if (index != (uint16_t)index) {
-            SPECIALIZATION_FAIL(base_op,
-                                index == DKIX_EMPTY ?
-                                SPEC_FAIL_ATTR_NOT_IN_DICT :
-                                SPEC_FAIL_OUT_OF_RANGE);
-            return 0;
-        }
-        cache->index = (uint16_t)index;
-        write_u32(cache->version, type->tp_version_tag);
-        _py_set_opcode(instr, hint_op);
-    }
-    return 1;
-}
-
-static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name,
-    PyObject* descr, DescriptorClassification kind);
-static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name);
-
-void
-_Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
-{
-    assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
-    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
-    PyTypeObject *type = Py_TYPE(owner);
-    if (!_PyType_IsReady(type)) {
-        // We *might* not really need this check, but we inherited it from
-        // PyObject_GenericGetAttr and friends... and this way we still do the
-        // right thing if someone forgets to call PyType_Ready(type):
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
-        goto fail;
-    }
-    if (PyModule_CheckExact(owner)) {
-        if (specialize_module_load_attr(owner, instr, name))
-        {
-            goto fail;
-        }
-        goto success;
-    }
-    if (PyType_Check(owner)) {
-        if (specialize_class_load_attr(owner, instr, name)) {
-            goto fail;
-        }
-        goto success;
-    }
-    PyObject *descr = NULL;
-    DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0);
-    assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
-    switch(kind) {
-        case OVERRIDING:
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
-            goto fail;
-        case METHOD:
-        {
-            int oparg = _Py_OPARG(*instr);
-            if (oparg & 1) {
-                if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) {
-                    goto success;
-                }
-            }
-            else {
-                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
-            }
-            goto fail;
-        }
-        case PROPERTY:
-        {
-            _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
-            assert(Py_TYPE(descr) == &PyProperty_Type);
-            PyObject *fget = ((_PyPropertyObject *)descr)->prop_get;
-            if (fget == NULL) {
-                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
-                goto fail;
-            }
-            if (!Py_IS_TYPE(fget, &PyFunction_Type)) {
-                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
-                goto fail;
-            }
-            if (!function_check_args(fget, 1, LOAD_ATTR)) {
-                goto fail;
-            }
-            uint32_t version = function_get_version(fget, LOAD_ATTR);
-            if (version == 0) {
-                goto fail;
-            }
-            write_u32(lm_cache->keys_version, version);
-            assert(type->tp_version_tag != 0);
-            write_u32(lm_cache->type_version, type->tp_version_tag);
-            /* borrowed */
-            write_obj(lm_cache->descr, fget);
-            _py_set_opcode(instr, LOAD_ATTR_PROPERTY);
-            goto success;
-        }
-        case OBJECT_SLOT:
-        {
-            PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
-            struct PyMemberDef *dmem = member->d_member;
-            Py_ssize_t offset = dmem->offset;
-            if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
-                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
-                goto fail;
-            }
-            if (dmem->flags & PY_AUDIT_READ) {
-                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT);
-                goto fail;
-            }
-            if (offset != (uint16_t)offset) {
-                SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
-                goto fail;
-            }
-            assert(dmem->type == T_OBJECT_EX);
-            assert(offset > 0);
-            cache->index = (uint16_t)offset;
-            write_u32(cache->version, type->tp_version_tag);
-            _py_set_opcode(instr, LOAD_ATTR_SLOT);
-            goto success;
-        }
-        case DUNDER_CLASS:
-        {
-            Py_ssize_t offset = offsetof(PyObject, ob_type);
-            assert(offset == (uint16_t)offset);
-            cache->index = (uint16_t)offset;
-            write_u32(cache->version, type->tp_version_tag);
-            _py_set_opcode(instr, LOAD_ATTR_SLOT);
-            goto success;
-        }
-        case OTHER_SLOT:
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
-            goto fail;
-        case MUTABLE:
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
-            goto fail;
-        case GETSET_OVERRIDDEN:
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN);
-            goto fail;
-        case GETATTRIBUTE_IS_PYTHON_FUNCTION:
-        {
-            assert(type->tp_getattro == _Py_slot_tp_getattro);
-            assert(Py_IS_TYPE(descr, &PyFunction_Type));
-            _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
-            if (!function_check_args(descr, 2, LOAD_ATTR)) {
-                goto fail;
-            }
-            uint32_t version = function_get_version(descr, LOAD_ATTR);
-            if (version == 0) {
-                goto fail;
-            }
-            write_u32(lm_cache->keys_version, version);
-            /* borrowed */
-            write_obj(lm_cache->descr, descr);
-            write_u32(lm_cache->type_version, type->tp_version_tag);
-            _py_set_opcode(instr, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN);
-            goto success;
-        }
-        case BUILTIN_CLASSMETHOD:
-        case PYTHON_CLASSMETHOD:
-        case NON_OVERRIDING:
-        case NON_DESCRIPTOR:
-        case ABSENT:
-            break;
-    }
-    if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR,
-                               LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
-    {
-        goto success;
-    }
-fail:
-    STAT_INC(LOAD_ATTR, failure);
-    assert(!PyErr_Occurred());
-    _py_set_opcode(instr, LOAD_ATTR);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(LOAD_ATTR, success);
-    assert(!PyErr_Occurred());
-    cache->counter = adaptive_counter_cooldown();
-}
-
-void
-_Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
-{
-    assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR);
-    _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
-    PyTypeObject *type = Py_TYPE(owner);
-    if (!_PyType_IsReady(type)) {
-        // We *might* not really need this check, but we inherited it from
-        // PyObject_GenericSetAttr and friends... and this way we still do the
-        // right thing if someone forgets to call PyType_Ready(type):
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
-        goto fail;
-    }
-    if (PyModule_CheckExact(owner)) {
-        SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
-        goto fail;
-    }
-    PyObject *descr;
-    DescriptorClassification kind = analyze_descriptor(type, name, &descr, 1);
-    switch(kind) {
-        case OVERRIDING:
-            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
-            goto fail;
-        case METHOD:
-            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_METHOD);
-            goto fail;
-        case PROPERTY:
-            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_PROPERTY);
-            goto fail;
-        case OBJECT_SLOT:
-        {
-            PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
-            struct PyMemberDef *dmem = member->d_member;
-            Py_ssize_t offset = dmem->offset;
-            if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
-                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_EXPECTED_ERROR);
-                goto fail;
-            }
-            if (dmem->flags & READONLY) {
-                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_READ_ONLY);
-                goto fail;
-            }
-            if (offset != (uint16_t)offset) {
-                SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OUT_OF_RANGE);
-                goto fail;
-            }
-            assert(dmem->type == T_OBJECT_EX);
-            assert(offset > 0);
-            cache->index = (uint16_t)offset;
-            write_u32(cache->version, type->tp_version_tag);
-            _py_set_opcode(instr, STORE_ATTR_SLOT);
-            goto success;
-        }
-        case DUNDER_CLASS:
-        case OTHER_SLOT:
-            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
-            goto fail;
-        case MUTABLE:
-            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
-            goto fail;
-        case GETATTRIBUTE_IS_PYTHON_FUNCTION:
-        case GETSET_OVERRIDDEN:
-            SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
-            goto fail;
-        case BUILTIN_CLASSMETHOD:
-        case PYTHON_CLASSMETHOD:
-        case NON_OVERRIDING:
-        case NON_DESCRIPTOR:
-        case ABSENT:
-            break;
-    }
-    if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR,
-                               STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT))
-    {
-        goto success;
-    }
-fail:
-    STAT_INC(STORE_ATTR, failure);
-    assert(!PyErr_Occurred());
-    _py_set_opcode(instr, STORE_ATTR);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(STORE_ATTR, success);
-    assert(!PyErr_Occurred());
-    cache->counter = adaptive_counter_cooldown();
-}
-
-
-#ifdef Py_STATS
-static int
-load_attr_fail_kind(DescriptorClassification kind)
-{
-    switch (kind) {
-        case OVERRIDING:
-            return SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR;
-        case METHOD:
-            return SPEC_FAIL_ATTR_METHOD;
-        case PROPERTY:
-            return SPEC_FAIL_ATTR_PROPERTY;
-        case OBJECT_SLOT:
-            return SPEC_FAIL_ATTR_OBJECT_SLOT;
-        case OTHER_SLOT:
-            return SPEC_FAIL_ATTR_NON_OBJECT_SLOT;
-        case DUNDER_CLASS:
-            return SPEC_FAIL_OTHER;
-        case MUTABLE:
-            return SPEC_FAIL_ATTR_MUTABLE_CLASS;
-        case GETSET_OVERRIDDEN:
-        case GETATTRIBUTE_IS_PYTHON_FUNCTION:
-            return SPEC_FAIL_OVERRIDDEN;
-        case BUILTIN_CLASSMETHOD:
-            return SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD;
-        case PYTHON_CLASSMETHOD:
-            return SPEC_FAIL_ATTR_CLASS_METHOD_OBJ;
-        case NON_OVERRIDING:
-            return SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR;
-        case NON_DESCRIPTOR:
-            return SPEC_FAIL_ATTR_NOT_DESCRIPTOR;
-        case ABSENT:
-            return SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE;
-    }
-    Py_UNREACHABLE();
-}
-#endif
-
-static int
-specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
-                             PyObject *name)
-{
-    _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
-    if (!PyType_CheckExact(owner) || _PyType_Lookup(Py_TYPE(owner), name)) {
-        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE);
-        return -1;
-    }
-    PyObject *descr = NULL;
-    DescriptorClassification kind = 0;
-    kind = analyze_descriptor((PyTypeObject *)owner, name, &descr, 0);
-    switch (kind) {
-        case METHOD:
-        case NON_DESCRIPTOR:
-            write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag);
-            write_obj(cache->descr, descr);
-            _py_set_opcode(instr, LOAD_ATTR_CLASS);
-            return 0;
-#ifdef Py_STATS
-        case ABSENT:
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
-            return -1;
-#endif
-        default:
-            SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind));
-            return -1;
-    }
-}
-
-typedef enum {
-    MANAGED_VALUES = 1,
-    MANAGED_DICT = 2,
-    OFFSET_DICT = 3,
-    NO_DICT = 4,
-    LAZY_DICT = 5,
-} ObjectDictKind;
-
-// Please collect stats carefully before and after modifying. A subtle change
-// can cause a significant drop in cache hits. A possible test is
-// python.exe -m test_typing test_re test_dis test_zlib.
-static int
-specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
-PyObject *descr, DescriptorClassification kind)
-{
-    _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
-    PyTypeObject *owner_cls = Py_TYPE(owner);
-
-    assert(kind == METHOD && descr != NULL);
-    ObjectDictKind dictkind;
-    PyDictKeysObject *keys;
-    if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
-        PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
-        keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
-        if (_PyDictOrValues_IsValues(dorv)) {
-            dictkind = MANAGED_VALUES;
-        }
-        else {
-            // User has directly accessed __dict__.
-            dictkind = MANAGED_DICT;
-        }
-    }
-    else {
-        Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
-        if (dictoffset < 0 || dictoffset > INT16_MAX) {
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
-            goto fail;
-        }
-        if (dictoffset == 0) {
-            dictkind = NO_DICT;
-            keys = NULL;
-        }
-        else {
-            PyObject *dict = *(PyObject **) ((char *)owner + dictoffset);
-            if (dict == NULL) {
-                // This object will have a dict if user access __dict__
-                dictkind = LAZY_DICT;
-                keys = NULL;
-            }
-            else {
-                keys = ((PyDictObject *)dict)->ma_keys;
-                dictkind = OFFSET_DICT;
-            }
-        }
-    }
-    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT || dictkind == MANAGED_DICT) {
-        Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
-        if (index != DKIX_EMPTY) {
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
-            goto fail;
-        }
-        uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(keys);
-        if (keys_version == 0) {
-            SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
-            goto fail;
-        }
-        write_u32(cache->keys_version, keys_version);
-    }
-    switch(dictkind) {
-        case NO_DICT:
-            _py_set_opcode(instr, LOAD_ATTR_METHOD_NO_DICT);
-            break;
-        case MANAGED_VALUES:
-            _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_VALUES);
-            break;
-        case MANAGED_DICT:
-            _py_set_opcode(instr, LOAD_ATTR_METHOD_MANAGED_DICT);
-            break;
-        case OFFSET_DICT:
-            assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
-            _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_DICT);
-            break;
-        case LAZY_DICT:
-            assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
-            _py_set_opcode(instr, LOAD_ATTR_METHOD_LAZY_DICT);
-            break;
-    }
-    /* `descr` is borrowed. This is safe for methods (even inherited ones from
-    *  super classes!) as long as tp_version_tag is validated for two main reasons:
-    *
-    *  1. The class will always hold a reference to the method so it will
-    *  usually not be GC-ed. Should it be deleted in Python, e.g.
-    *  `del obj.meth`, tp_version_tag will be invalidated, because of reason 2.
-    *
-    *  2. The pre-existing type method cache (MCACHE) uses the same principles
-    *  of caching a borrowed descriptor. The MCACHE infrastructure does all the
-    *  heavy lifting for us. E.g. it invalidates tp_version_tag on any MRO
-    *  modification, on any type object change along said MRO, etc. (see
-    *  PyType_Modified usages in typeobject.c). The MCACHE has been
-    *  working since Python 2.6 and it's battle-tested.
-    */
-    write_u32(cache->type_version, owner_cls->tp_version_tag);
-    write_obj(cache->descr, descr);
-    return 1;
-fail:
-    return 0;
-}
-
-void
-_Py_Specialize_LoadGlobal(
-    PyObject *globals, PyObject *builtins,
-    _Py_CODEUNIT *instr, PyObject *name)
-{
-    assert(_PyOpcode_Caches[LOAD_GLOBAL] == INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
-    /* Use inline cache */
-    _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)(instr + 1);
-    assert(PyUnicode_CheckExact(name));
-    if (!PyDict_CheckExact(globals)) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT);
-        goto fail;
-    }
-    PyDictKeysObject * globals_keys = ((PyDictObject *)globals)->ma_keys;
-    if (!DK_IS_UNICODE(globals_keys)) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
-        goto fail;
-    }
-    Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name);
-    if (index == DKIX_ERROR) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
-        goto fail;
-    }
-    if (index != DKIX_EMPTY) {
-        if (index != (uint16_t)index) {
-            SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
-            goto fail;
-        }
-        uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(globals_keys);
-        if (keys_version == 0) {
-            SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
-            goto fail;
-        }
-        cache->index = (uint16_t)index;
-        write_u32(cache->module_keys_version, keys_version);
-        _py_set_opcode(instr, LOAD_GLOBAL_MODULE);
-        goto success;
-    }
-    if (!PyDict_CheckExact(builtins)) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT);
-        goto fail;
-    }
-    PyDictKeysObject * builtin_keys = ((PyDictObject *)builtins)->ma_keys;
-    if (!DK_IS_UNICODE(builtin_keys)) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT);
-        goto fail;
-    }
-    index = _PyDictKeys_StringLookup(builtin_keys, name);
-    if (index == DKIX_ERROR) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR);
-        goto fail;
-    }
-    if (index != (uint16_t)index) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
-        goto fail;
-    }
-    uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState(globals_keys);
-    if (globals_version == 0) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
-        goto fail;
-    }
-    uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState(builtin_keys);
-    if (builtins_version == 0) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS);
-        goto fail;
-    }
-    if (builtins_version > UINT16_MAX) {
-        SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE);
-        goto fail;
-    }
-    cache->index = (uint16_t)index;
-    write_u32(cache->module_keys_version, globals_version);
-    cache->builtin_keys_version = (uint16_t)builtins_version;
-    _py_set_opcode(instr, LOAD_GLOBAL_BUILTIN);
-    goto success;
-fail:
-    STAT_INC(LOAD_GLOBAL, failure);
-    assert(!PyErr_Occurred());
-    _py_set_opcode(instr, LOAD_GLOBAL);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(LOAD_GLOBAL, success);
-    assert(!PyErr_Occurred());
-    cache->counter = adaptive_counter_cooldown();
-}
-
-#ifdef Py_STATS
-static int
-binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub)
-{
-    if (container_type == &PyUnicode_Type) {
-        if (PyLong_CheckExact(sub)) {
-            return SPEC_FAIL_SUBSCR_STRING_INT;
-        }
-        if (PySlice_Check(sub)) {
-            return SPEC_FAIL_SUBSCR_STRING_SLICE;
-        }
-        return SPEC_FAIL_OTHER;
-    }
-    else if (strcmp(container_type->tp_name, "array.array") == 0) {
-        if (PyLong_CheckExact(sub)) {
-            return SPEC_FAIL_SUBSCR_ARRAY_INT;
-        }
-        if (PySlice_Check(sub)) {
-            return SPEC_FAIL_SUBSCR_ARRAY_SLICE;
-        }
-        return SPEC_FAIL_OTHER;
-    }
-    else if (container_type->tp_as_buffer) {
-        if (PyLong_CheckExact(sub)) {
-            return SPEC_FAIL_SUBSCR_BUFFER_INT;
-        }
-        if (PySlice_Check(sub)) {
-            return SPEC_FAIL_SUBSCR_BUFFER_SLICE;
-        }
-        return SPEC_FAIL_OTHER;
-    }
-    else if (container_type->tp_as_sequence) {
-        if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) {
-            return SPEC_FAIL_SUBSCR_SEQUENCE_INT;
-        }
-    }
-    return SPEC_FAIL_OTHER;
-}
-#endif
-
-static int
-function_kind(PyCodeObject *code) {
-    int flags = code->co_flags;
-    if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) {
-        return SPEC_FAIL_CALL_COMPLEX_PARAMETERS;
-    }
-    if ((flags & CO_OPTIMIZED) == 0) {
-        return SPEC_FAIL_CALL_CO_NOT_OPTIMIZED;
-    }
-    return SIMPLE_FUNCTION;
-}
-
-/* Returning false indicates a failure. */
-static bool
-function_check_args(PyObject *o, int expected_argcount, int opcode)
-{
-    assert(Py_IS_TYPE(o, &PyFunction_Type));
-    PyFunctionObject *func = (PyFunctionObject *)o;
-    PyCodeObject *fcode = (PyCodeObject *)func->func_code;
-    int kind = function_kind(fcode);
-    if (kind != SIMPLE_FUNCTION) {
-        SPECIALIZATION_FAIL(opcode, kind);
-        return false;
-    }
-    if (fcode->co_argcount != expected_argcount) {
-        SPECIALIZATION_FAIL(opcode, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
-        return false;
-    }
-    return true;
-}
-
-/* Returning 0 indicates a failure. */
-static uint32_t
-function_get_version(PyObject *o, int opcode)
-{
-    assert(Py_IS_TYPE(o, &PyFunction_Type));
-    PyFunctionObject *func = (PyFunctionObject *)o;
-    uint32_t version = _PyFunction_GetVersionForCurrentState(func);
-    if (version == 0) {
-        SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS);
-        return 0;
-    }
-    return version;
-}
-
-void
-_Py_Specialize_BinarySubscr(
-     PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
-{
-    assert(_PyOpcode_Caches[BINARY_SUBSCR] ==
-           INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
-    _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)(instr + 1);
-    PyTypeObject *container_type = Py_TYPE(container);
-    if (container_type == &PyList_Type) {
-        if (PyLong_CheckExact(sub)) {
-            _py_set_opcode(instr, BINARY_SUBSCR_LIST_INT);
-            goto success;
-        }
-        SPECIALIZATION_FAIL(BINARY_SUBSCR,
-            PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_LIST_SLICE : SPEC_FAIL_OTHER);
-        goto fail;
-    }
-    if (container_type == &PyTuple_Type) {
-        if (PyLong_CheckExact(sub)) {
-            _py_set_opcode(instr, BINARY_SUBSCR_TUPLE_INT);
-            goto success;
-        }
-        SPECIALIZATION_FAIL(BINARY_SUBSCR,
-            PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_TUPLE_SLICE : SPEC_FAIL_OTHER);
-        goto fail;
-    }
-    if (container_type == &PyDict_Type) {
-        _py_set_opcode(instr, BINARY_SUBSCR_DICT);
-        goto success;
-    }
-    PyTypeObject *cls = Py_TYPE(container);
-    PyObject *descriptor = _PyType_Lookup(cls, &_Py_ID(__getitem__));
-    if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) {
-        if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
-            SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE);
-            goto fail;
-        }
-        PyFunctionObject *func = (PyFunctionObject *)descriptor;
-        PyCodeObject *fcode = (PyCodeObject *)func->func_code;
-        int kind = function_kind(fcode);
-        if (kind != SIMPLE_FUNCTION) {
-            SPECIALIZATION_FAIL(BINARY_SUBSCR, kind);
-            goto fail;
-        }
-        if (fcode->co_argcount != 2) {
-            SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
-            goto fail;
-        }
-        assert(cls->tp_version_tag != 0);
-        write_u32(cache->type_version, cls->tp_version_tag);
-        int version = _PyFunction_GetVersionForCurrentState(func);
-        if (version == 0 || version != (uint16_t)version) {
-            SPECIALIZATION_FAIL(BINARY_SUBSCR, version == 0 ?
-                SPEC_FAIL_OUT_OF_VERSIONS : SPEC_FAIL_OUT_OF_RANGE);
-            goto fail;
-        }
-        cache->func_version = version;
-        ((PyHeapTypeObject *)container_type)->_spec_cache.getitem = descriptor;
-        _py_set_opcode(instr, BINARY_SUBSCR_GETITEM);
-        goto success;
-    }
-    SPECIALIZATION_FAIL(BINARY_SUBSCR,
-                        binary_subscr_fail_kind(container_type, sub));
-fail:
-    STAT_INC(BINARY_SUBSCR, failure);
-    assert(!PyErr_Occurred());
-    _py_set_opcode(instr, BINARY_SUBSCR);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(BINARY_SUBSCR, success);
-    assert(!PyErr_Occurred());
-    cache->counter = adaptive_counter_cooldown();
-}
-
-void
-_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
-{
-    _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
-    PyTypeObject *container_type = Py_TYPE(container);
-    if (container_type == &PyList_Type) {
-        if (PyLong_CheckExact(sub)) {
-            if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
-                && ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container))
-            {
-                _py_set_opcode(instr, STORE_SUBSCR_LIST_INT);
-                goto success;
-            }
-            else {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
-                goto fail;
-            }
-        }
-        else if (PySlice_Check(sub)) {
-            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_LIST_SLICE);
-            goto fail;
-        }
-        else {
-            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
-            goto fail;
-        }
-    }
-    if (container_type == &PyDict_Type) {
-        _py_set_opcode(instr, STORE_SUBSCR_DICT);
-         goto success;
-    }
-#ifdef Py_STATS
-    PyMappingMethods *as_mapping = container_type->tp_as_mapping;
-    if (as_mapping && (as_mapping->mp_ass_subscript
-                       == PyDict_Type.tp_as_mapping->mp_ass_subscript)) {
-        SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE);
-        goto fail;
-    }
-    if (PyObject_CheckBuffer(container)) {
-        if (PyLong_CheckExact(sub) && (((size_t)Py_SIZE(sub)) > 1)) {
-            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
-        }
-        else if (strcmp(container_type->tp_name, "array.array") == 0) {
-            if (PyLong_CheckExact(sub)) {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_INT);
-            }
-            else if (PySlice_Check(sub)) {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_SLICE);
-            }
-            else {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
-            }
-        }
-        else if (PyByteArray_CheckExact(container)) {
-            if (PyLong_CheckExact(sub)) {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_INT);
-            }
-            else if (PySlice_Check(sub)) {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE);
-            }
-            else {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
-            }
-        }
-        else {
-            if (PyLong_CheckExact(sub)) {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_INT);
-            }
-            else if (PySlice_Check(sub)) {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_SLICE);
-            }
-            else {
-                SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
-            }
-        }
-        goto fail;
-    }
-    PyObject *descriptor = _PyType_Lookup(container_type, &_Py_ID(__setitem__));
-    if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) {
-        PyFunctionObject *func = (PyFunctionObject *)descriptor;
-        PyCodeObject *code = (PyCodeObject *)func->func_code;
-        int kind = function_kind(code);
-        if (kind == SIMPLE_FUNCTION) {
-            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_SIMPLE);
-        }
-        else {
-            SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_OTHER);
-        }
-        goto fail;
-    }
-#endif
-    SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER);
-fail:
-    STAT_INC(STORE_SUBSCR, failure);
-    assert(!PyErr_Occurred());
-    _py_set_opcode(instr, STORE_SUBSCR);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(STORE_SUBSCR, success);
-    assert(!PyErr_Occurred());
-    cache->counter = adaptive_counter_cooldown();
-}
-
-static int
-specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
-                      PyObject *kwnames)
-{
-    PyTypeObject *tp = _PyType_CAST(callable);
-    if (tp->tp_new == PyBaseObject_Type.tp_new) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PYTHON_CLASS);
-        return -1;
-    }
-    if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
-        int oparg = _Py_OPARG(*instr);
-        if (nargs == 1 && kwnames == NULL && oparg == 1) {
-            if (tp == &PyUnicode_Type) {
-                _py_set_opcode(instr, CALL_NO_KW_STR_1);
-                return 0;
-            }
-            else if (tp == &PyType_Type) {
-                _py_set_opcode(instr, CALL_NO_KW_TYPE_1);
-                return 0;
-            }
-            else if (tp == &PyTuple_Type) {
-                _py_set_opcode(instr, CALL_NO_KW_TUPLE_1);
-                return 0;
-            }
-        }
-        if (tp->tp_vectorcall != NULL) {
-            _py_set_opcode(instr, CALL_BUILTIN_CLASS);
-            return 0;
-        }
-        SPECIALIZATION_FAIL(CALL, tp == &PyUnicode_Type ?
-            SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL);
-        return -1;
-    }
-    SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_CLASS_MUTABLE);
-    return -1;
-}
-
-#ifdef Py_STATS
-static int
-builtin_call_fail_kind(int ml_flags)
-{
-    switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
-        METH_KEYWORDS | METH_METHOD)) {
-        case METH_VARARGS:
-            return SPEC_FAIL_CALL_PYCFUNCTION;
-        case METH_VARARGS | METH_KEYWORDS:
-            return SPEC_FAIL_CALL_PYCFUNCTION_WITH_KEYWORDS;
-        case METH_FASTCALL | METH_KEYWORDS:
-            return SPEC_FAIL_CALL_PYCFUNCTION_FAST_WITH_KEYWORDS;
-        case METH_NOARGS:
-            return SPEC_FAIL_CALL_PYCFUNCTION_NOARGS;
-        /* This case should never happen with PyCFunctionObject -- only
-            PyMethodObject. See zlib.compressobj()'s methods for an example.
-        */
-        case METH_METHOD | METH_FASTCALL | METH_KEYWORDS:
-        default:
-            return SPEC_FAIL_CALL_BAD_CALL_FLAGS;
-    }
-}
-#endif
-
-static int
-specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
-                             int nargs, PyObject *kwnames)
-{
-    if (kwnames) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
-        return -1;
-    }
-
-    switch (descr->d_method->ml_flags &
-        (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
-        METH_KEYWORDS | METH_METHOD)) {
-        case METH_NOARGS: {
-            if (nargs != 1) {
-                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
-                return -1;
-            }
-            _py_set_opcode(instr, CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS);
-            return 0;
-        }
-        case METH_O: {
-            if (nargs != 2) {
-                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
-                return -1;
-            }
-            PyInterpreterState *interp = _PyInterpreterState_GET();
-            PyObject *list_append = interp->callable_cache.list_append;
-            _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_CALL + 1];
-            bool pop = (_Py_OPCODE(next) == POP_TOP);
-            int oparg = _Py_OPARG(*instr);
-            if ((PyObject *)descr == list_append && oparg == 1 && pop) {
-                _py_set_opcode(instr, CALL_NO_KW_LIST_APPEND);
-                return 0;
-            }
-            _py_set_opcode(instr, CALL_NO_KW_METHOD_DESCRIPTOR_O);
-            return 0;
-        }
-        case METH_FASTCALL: {
-            _py_set_opcode(instr, CALL_NO_KW_METHOD_DESCRIPTOR_FAST);
-            return 0;
-        }
-        case METH_FASTCALL|METH_KEYWORDS: {
-            _py_set_opcode(instr, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS);
-            return 0;
-        }
-    }
-    SPECIALIZATION_FAIL(CALL, builtin_call_fail_kind(descr->d_method->ml_flags));
-    return -1;
-}
-
-static int
-specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
-                   PyObject *kwnames, bool bound_method)
-{
-    _PyCallCache *cache = (_PyCallCache *)(instr + 1);
-    PyCodeObject *code = (PyCodeObject *)func->func_code;
-    int kind = function_kind(code);
-    /* Don't specialize if PEP 523 is active */
-    if (_PyInterpreterState_GET()->eval_frame) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523);
-        return -1;
-    }
-    if (kwnames) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
-        return -1;
-    }
-    if (kind != SIMPLE_FUNCTION) {
-        SPECIALIZATION_FAIL(CALL, kind);
-        return -1;
-    }
-    int argcount = code->co_argcount;
-    int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults);
-    assert(defcount <= argcount);
-    int min_args = argcount-defcount;
-    if (nargs > argcount || nargs < min_args) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
-        return -1;
-    }
-    assert(nargs <= argcount && nargs >= min_args);
-    assert(min_args >= 0 && defcount >= 0);
-    assert(defcount == 0 || func->func_defaults != NULL);
-    if (min_args > 0xffff) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE);
-        return -1;
-    }
-    int version = _PyFunction_GetVersionForCurrentState(func);
-    if (version == 0) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS);
-        return -1;
-    }
-    write_u32(cache->func_version, version);
-    cache->min_args = min_args;
-    if (argcount == nargs) {
-        _py_set_opcode(instr, bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS);
-    }
-    else if (bound_method) {
-        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD);
-        return -1;
-    }
-    else {
-        _py_set_opcode(instr, CALL_PY_WITH_DEFAULTS);
-    }
-    return 0;
-}
-
-static int
-specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
-                  PyObject *kwnames)
-{
-    if (PyCFunction_GET_FUNCTION(callable) == NULL) {
-        return 1;
-    }
-    switch (PyCFunction_GET_FLAGS(callable) &
-        (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
-        METH_KEYWORDS | METH_METHOD)) {
-        case METH_O: {
-            if (kwnames) {
-                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
-                return -1;
-            }
-            if (nargs != 1) {
-                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
-                return 1;
-            }
-            /* len(o) */
-            PyInterpreterState *interp = _PyInterpreterState_GET();
-            if (callable == interp->callable_cache.len) {
-                _py_set_opcode(instr, CALL_NO_KW_LEN);
-                return 0;
-            }
-            _py_set_opcode(instr, CALL_NO_KW_BUILTIN_O);
-            return 0;
-        }
-        case METH_FASTCALL: {
-            if (kwnames) {
-                SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
-                return -1;
-            }
-            if (nargs == 2) {
-                /* isinstance(o1, o2) */
-                PyInterpreterState *interp = _PyInterpreterState_GET();
-                if (callable == interp->callable_cache.isinstance) {
-                    _py_set_opcode(instr, CALL_NO_KW_ISINSTANCE);
-                    return 0;
-                }
-            }
-            _py_set_opcode(instr, CALL_NO_KW_BUILTIN_FAST);
-            return 0;
-        }
-        case METH_FASTCALL | METH_KEYWORDS: {
-            _py_set_opcode(instr, CALL_BUILTIN_FAST_WITH_KEYWORDS);
-            return 0;
-        }
-        default:
-            SPECIALIZATION_FAIL(CALL,
-                builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable)));
-            return 1;
-    }
-}
-
-#ifdef Py_STATS
-static int
-call_fail_kind(PyObject *callable)
-{
-    if (PyCFunction_CheckExact(callable)) {
-        return SPEC_FAIL_CALL_PYCFUNCTION;
-    }
-    else if (PyFunction_Check(callable)) {
-        return SPEC_FAIL_CALL_PYFUNCTION;
-    }
-    else if (PyInstanceMethod_Check(callable)) {
-        return SPEC_FAIL_CALL_INSTANCE_METHOD;
-    }
-    else if (PyMethod_Check(callable)) {
-        return SPEC_FAIL_CALL_BOUND_METHOD;
-    }
-    // builtin method
-    else if (PyCMethod_Check(callable)) {
-        return SPEC_FAIL_CALL_CMETHOD;
-    }
-    else if (PyType_Check(callable)) {
-        if (((PyTypeObject *)callable)->tp_new == PyBaseObject_Type.tp_new) {
-            return SPEC_FAIL_CALL_PYTHON_CLASS;
-        }
-        else {
-            return SPEC_FAIL_CALL_CLASS;
-        }
-    }
-    else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
-        return SPEC_FAIL_CALL_METHOD_DESCRIPTOR;
-    }
-    else if (Py_TYPE(callable) == &PyWrapperDescr_Type) {
-        return SPEC_FAIL_CALL_OPERATOR_WRAPPER;
-    }
-    else if (Py_TYPE(callable) == &_PyMethodWrapper_Type) {
-        return SPEC_FAIL_CALL_METHOD_WRAPPER;
-    }
-    return SPEC_FAIL_OTHER;
-}
-#endif
-
-
-/* TODO:
-    - Specialize calling classes.
-*/
-void
-_Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
-                    PyObject *kwnames)
-{
-    assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL);
-    _PyCallCache *cache = (_PyCallCache *)(instr + 1);
-    int fail;
-    if (PyCFunction_CheckExact(callable)) {
-        fail = specialize_c_call(callable, instr, nargs, kwnames);
-    }
-    else if (PyFunction_Check(callable)) {
-        fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs,
-                                  kwnames, false);
-    }
-    else if (PyType_Check(callable)) {
-        fail = specialize_class_call(callable, instr, nargs, kwnames);
-    }
-    else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
-        fail = specialize_method_descriptor((PyMethodDescrObject *)callable,
-                                            instr, nargs, kwnames);
-    }
-    else if (Py_TYPE(callable) == &PyMethod_Type) {
-        PyObject *func = ((PyMethodObject *)callable)->im_func;
-        if (PyFunction_Check(func)) {
-            fail = specialize_py_call((PyFunctionObject *)func,
-                                      instr, nargs+1, kwnames, true);
-        } else {
-            SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD);
-            fail = -1;
-        }
-    }
-    else {
-        SPECIALIZATION_FAIL(CALL, call_fail_kind(callable));
-        fail = -1;
-    }
-    if (fail) {
-        STAT_INC(CALL, failure);
-        assert(!PyErr_Occurred());
-        _py_set_opcode(instr, CALL);
-        cache->counter = adaptive_counter_backoff(cache->counter);
-    }
-    else {
-        STAT_INC(CALL, success);
-        assert(!PyErr_Occurred());
-        cache->counter = adaptive_counter_cooldown();
-    }
-}
-
-#ifdef Py_STATS
-static int
-binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
-{
-    switch (oparg) {
-        case NB_ADD:
-        case NB_INPLACE_ADD:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES;
-            }
-            return SPEC_FAIL_BINARY_OP_ADD_OTHER;
-        case NB_AND:
-        case NB_INPLACE_AND:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES;
-            }
-            if (PyLong_CheckExact(lhs)) {
-                return SPEC_FAIL_BINARY_OP_AND_INT;
-            }
-            return SPEC_FAIL_BINARY_OP_AND_OTHER;
-        case NB_FLOOR_DIVIDE:
-        case NB_INPLACE_FLOOR_DIVIDE:
-            return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE;
-        case NB_LSHIFT:
-        case NB_INPLACE_LSHIFT:
-            return SPEC_FAIL_BINARY_OP_LSHIFT;
-        case NB_MATRIX_MULTIPLY:
-        case NB_INPLACE_MATRIX_MULTIPLY:
-            return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY;
-        case NB_MULTIPLY:
-        case NB_INPLACE_MULTIPLY:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES;
-            }
-            return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER;
-        case NB_OR:
-        case NB_INPLACE_OR:
-            return SPEC_FAIL_BINARY_OP_OR;
-        case NB_POWER:
-        case NB_INPLACE_POWER:
-            return SPEC_FAIL_BINARY_OP_POWER;
-        case NB_REMAINDER:
-        case NB_INPLACE_REMAINDER:
-            return SPEC_FAIL_BINARY_OP_REMAINDER;
-        case NB_RSHIFT:
-        case NB_INPLACE_RSHIFT:
-            return SPEC_FAIL_BINARY_OP_RSHIFT;
-        case NB_SUBTRACT:
-        case NB_INPLACE_SUBTRACT:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES;
-            }
-            return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER;
-        case NB_TRUE_DIVIDE:
-        case NB_INPLACE_TRUE_DIVIDE:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES;
-            }
-            if (PyFloat_CheckExact(lhs)) {
-                return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT;
-            }
-            return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER;
-        case NB_XOR:
-        case NB_INPLACE_XOR:
-            return SPEC_FAIL_BINARY_OP_XOR;
-    }
-    Py_UNREACHABLE();
-}
-#endif
-
-void
-_Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
-                        int oparg, PyObject **locals)
-{
-    assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP);
-    _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1);
-    switch (oparg) {
-        case NB_ADD:
-        case NB_INPLACE_ADD:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                break;
-            }
-            if (PyUnicode_CheckExact(lhs)) {
-                _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1];
-                bool to_store = (_Py_OPCODE(next) == STORE_FAST ||
-                                 _Py_OPCODE(next) == STORE_FAST__LOAD_FAST);
-                if (to_store && locals[_Py_OPARG(next)] == lhs) {
-                    _py_set_opcode(instr, BINARY_OP_INPLACE_ADD_UNICODE);
-                    goto success;
-                }
-                _py_set_opcode(instr, BINARY_OP_ADD_UNICODE);
-                goto success;
-            }
-            if (PyLong_CheckExact(lhs)) {
-                _py_set_opcode(instr, BINARY_OP_ADD_INT);
-                goto success;
-            }
-            if (PyFloat_CheckExact(lhs)) {
-                _py_set_opcode(instr, BINARY_OP_ADD_FLOAT);
-                goto success;
-            }
-            break;
-        case NB_MULTIPLY:
-        case NB_INPLACE_MULTIPLY:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                break;
-            }
-            if (PyLong_CheckExact(lhs)) {
-                _py_set_opcode(instr, BINARY_OP_MULTIPLY_INT);
-                goto success;
-            }
-            if (PyFloat_CheckExact(lhs)) {
-                _py_set_opcode(instr, BINARY_OP_MULTIPLY_FLOAT);
-                goto success;
-            }
-            break;
-        case NB_SUBTRACT:
-        case NB_INPLACE_SUBTRACT:
-            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
-                break;
-            }
-            if (PyLong_CheckExact(lhs)) {
-                _py_set_opcode(instr, BINARY_OP_SUBTRACT_INT);
-                goto success;
-            }
-            if (PyFloat_CheckExact(lhs)) {
-                _py_set_opcode(instr, BINARY_OP_SUBTRACT_FLOAT);
-                goto success;
-            }
-            break;
-    }
-    SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs));
-    STAT_INC(BINARY_OP, failure);
-    _py_set_opcode(instr, BINARY_OP);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(BINARY_OP, success);
-    cache->counter = adaptive_counter_cooldown();
-}
-
-
-#ifdef Py_STATS
-static int
-compare_op_fail_kind(PyObject *lhs, PyObject *rhs)
-{
-    if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
-        if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) {
-            return SPEC_FAIL_COMPARE_OP_FLOAT_LONG;
-        }
-        if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) {
-            return SPEC_FAIL_COMPARE_OP_LONG_FLOAT;
-        }
-        return SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES;
-    }
-    if (PyBytes_CheckExact(lhs)) {
-        return SPEC_FAIL_COMPARE_OP_BYTES;
-    }
-    if (PyTuple_CheckExact(lhs)) {
-        return SPEC_FAIL_COMPARE_OP_TUPLE;
-    }
-    if (PyList_CheckExact(lhs)) {
-        return SPEC_FAIL_COMPARE_OP_LIST;
-    }
-    if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) {
-        return SPEC_FAIL_COMPARE_OP_SET;
-    }
-    if (PyBool_Check(lhs)) {
-        return SPEC_FAIL_COMPARE_OP_BOOL;
-    }
-    if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) {
-        return SPEC_FAIL_COMPARE_OP_BASEOBJECT;
-    }
-    return SPEC_FAIL_OTHER;
-}
-#endif
-
-
-static int compare_masks[] = {
-    // 1-bit: jump if less than
-    // 2-bit: jump if equal
-    // 4-bit: jump if greater
-    [Py_LT] = 1 | 0 | 0,
-    [Py_LE] = 1 | 2 | 0,
-    [Py_EQ] = 0 | 2 | 0,
-    [Py_NE] = 1 | 0 | 4,
-    [Py_GT] = 0 | 0 | 4,
-    [Py_GE] = 0 | 2 | 4,
-};
-
-void
-_Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
-                         int oparg)
-{
-    assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP);
-    _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1);
-    int next_opcode = _Py_OPCODE(instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1]);
-    if (next_opcode != POP_JUMP_IF_FALSE && next_opcode != POP_JUMP_IF_TRUE) {
-        if (next_opcode == EXTENDED_ARG) {
-            SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_EXTENDED_ARG);
-            goto failure;
-        }
-        SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_NOT_FOLLOWED_BY_COND_JUMP);
-        goto failure;
-    }
-    assert(oparg <= Py_GE);
-    int when_to_jump_mask = compare_masks[oparg];
-    if (next_opcode == POP_JUMP_IF_FALSE) {
-        when_to_jump_mask = (1 | 2 | 4) & ~when_to_jump_mask;
-    }
-    if (Py_TYPE(lhs) != Py_TYPE(rhs)) {
-        SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
-        goto failure;
-    }
-    if (PyFloat_CheckExact(lhs)) {
-        _py_set_opcode(instr, COMPARE_OP_FLOAT_JUMP);
-        cache->mask = when_to_jump_mask;
-        goto success;
-    }
-    if (PyLong_CheckExact(lhs)) {
-        if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) {
-            _py_set_opcode(instr, COMPARE_OP_INT_JUMP);
-            cache->mask = when_to_jump_mask;
-            goto success;
-        }
-        else {
-            SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_BIG_INT);
-            goto failure;
-        }
-    }
-    if (PyUnicode_CheckExact(lhs)) {
-        if (oparg != Py_EQ && oparg != Py_NE) {
-            SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING);
-            goto failure;
-        }
-        else {
-            _py_set_opcode(instr, COMPARE_OP_STR_JUMP);
-            cache->mask = (when_to_jump_mask & 2) == 0;
-            goto success;
-        }
-    }
-    SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs));
-failure:
-    STAT_INC(COMPARE_OP, failure);
-    _py_set_opcode(instr, COMPARE_OP);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(COMPARE_OP, success);
-    cache->counter = adaptive_counter_cooldown();
-}
-
-#ifdef Py_STATS
-static int
-unpack_sequence_fail_kind(PyObject *seq)
-{
-    if (PySequence_Check(seq)) {
-        return SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE;
-    }
-    if (PyIter_Check(seq)) {
-        return SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR;
-    }
-    return SPEC_FAIL_OTHER;
-}
-#endif
-
-void
-_Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg)
-{
-    assert(_PyOpcode_Caches[UNPACK_SEQUENCE] ==
-           INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
-    _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)(instr + 1);
-    if (PyTuple_CheckExact(seq)) {
-        if (PyTuple_GET_SIZE(seq) != oparg) {
-            SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR);
-            goto failure;
-        }
-        if (PyTuple_GET_SIZE(seq) == 2) {
-            _py_set_opcode(instr, UNPACK_SEQUENCE_TWO_TUPLE);
-            goto success;
-        }
-        _py_set_opcode(instr, UNPACK_SEQUENCE_TUPLE);
-        goto success;
-    }
-    if (PyList_CheckExact(seq)) {
-        if (PyList_GET_SIZE(seq) != oparg) {
-            SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR);
-            goto failure;
-        }
-        _py_set_opcode(instr, UNPACK_SEQUENCE_LIST);
-        goto success;
-    }
-    SPECIALIZATION_FAIL(UNPACK_SEQUENCE, unpack_sequence_fail_kind(seq));
-failure:
-    STAT_INC(UNPACK_SEQUENCE, failure);
-    _py_set_opcode(instr, UNPACK_SEQUENCE);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(UNPACK_SEQUENCE, success);
-    cache->counter = adaptive_counter_cooldown();
-}
-
-#ifdef Py_STATS
-
-int
- _PySpecialization_ClassifyIterator(PyObject *iter)
-{
-    if (PyGen_CheckExact(iter)) {
-        return SPEC_FAIL_FOR_ITER_GENERATOR;
-    }
-    if (PyCoro_CheckExact(iter)) {
-        return SPEC_FAIL_FOR_ITER_COROUTINE;
-    }
-    if (PyAsyncGen_CheckExact(iter)) {
-        return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR;
-    }
-    PyTypeObject *t = Py_TYPE(iter);
-    if (t == &PyListIter_Type) {
-        return SPEC_FAIL_FOR_ITER_LIST;
-    }
-    if (t == &PyTupleIter_Type) {
-        return SPEC_FAIL_FOR_ITER_TUPLE;
-    }
-    if (t == &PyDictIterKey_Type) {
-        return SPEC_FAIL_FOR_ITER_DICT_KEYS;
-    }
-    if (t == &PyDictIterValue_Type) {
-        return SPEC_FAIL_FOR_ITER_DICT_VALUES;
-    }
-    if (t == &PyDictIterItem_Type) {
-        return SPEC_FAIL_FOR_ITER_DICT_ITEMS;
-    }
-    if (t == &PySetIter_Type) {
-        return SPEC_FAIL_FOR_ITER_SET;
-    }
-    if (t == &PyUnicodeIter_Type) {
-        return SPEC_FAIL_FOR_ITER_STRING;
-    }
-    if (t == &PyBytesIter_Type) {
-        return SPEC_FAIL_FOR_ITER_BYTES;
-    }
-    if (t == &PyRangeIter_Type) {
-        return SPEC_FAIL_FOR_ITER_RANGE;
-    }
-    if (t == &PyEnum_Type) {
-        return SPEC_FAIL_FOR_ITER_ENUMERATE;
-    }
-    if (t == &PyMap_Type) {
-        return SPEC_FAIL_FOR_ITER_MAP;
-    }
-    if (t == &PyZip_Type) {
-        return SPEC_FAIL_FOR_ITER_ZIP;
-    }
-    if (t == &PySeqIter_Type) {
-        return SPEC_FAIL_FOR_ITER_SEQ_ITER;
-    }
-    if (t == &PyListRevIter_Type) {
-        return SPEC_FAIL_FOR_ITER_REVERSED_LIST;
-    }
-    if (t == &_PyUnicodeASCIIIter_Type) {
-        return SPEC_FAIL_FOR_ITER_ASCII_STRING;
-    }
-    const char *name = t->tp_name;
-    if (strncmp(name, "itertools", 9) == 0) {
-        return SPEC_FAIL_FOR_ITER_ITERTOOLS;
-    }
-    if (strncmp(name, "callable_iterator", 17) == 0) {
-        return SPEC_FAIL_FOR_ITER_CALLABLE;
-    }
-    return SPEC_FAIL_OTHER;
-}
-
-#endif
-
-void
-_Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
-{
-    assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER);
-    _PyForIterCache *cache = (_PyForIterCache *)(instr + 1);
-    PyTypeObject *tp = Py_TYPE(iter);
-    _Py_CODEUNIT next = instr[1+INLINE_CACHE_ENTRIES_FOR_ITER];
-    int next_op = _PyOpcode_Deopt[_Py_OPCODE(next)];
-    if (tp == &PyListIter_Type) {
-        _py_set_opcode(instr, FOR_ITER_LIST);
-        goto success;
-    }
-    else if (tp == &PyTupleIter_Type) {
-        _py_set_opcode(instr, FOR_ITER_TUPLE);
-        goto success;
-    }
-    else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) {
-        _py_set_opcode(instr, FOR_ITER_RANGE);
-        goto success;
-    }
-    else if (tp == &PyGen_Type && oparg <= SHRT_MAX) {
-        assert(_Py_OPCODE(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1]) == END_FOR);
-        _py_set_opcode(instr, FOR_ITER_GEN);
-        goto success;
-    }
-    SPECIALIZATION_FAIL(FOR_ITER,
-                        _PySpecialization_ClassifyIterator(iter));
-    STAT_INC(FOR_ITER, failure);
-    _py_set_opcode(instr, FOR_ITER);
-    cache->counter = adaptive_counter_backoff(cache->counter);
-    return;
-success:
-    STAT_INC(FOR_ITER, success);
-    cache->counter = adaptive_counter_cooldown();
-}

From 9e7862b20bfea6e82af8deffcc7c593e5bb6753f Mon Sep 17 00:00:00 2001
From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com>
Date: Fri, 16 Dec 2022 08:50:18 +0000
Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?=
 =?UTF-8?q?rb=5Fit.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../2022-12-16-08-50-16.gh-issue-100288.5XCk0G.rst               | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-12-16-08-50-16.gh-issue-100288.5XCk0G.rst

diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-12-16-08-50-16.gh-issue-100288.5XCk0G.rst b/Misc/NEWS.d/next/Core and Builtins/2022-12-16-08-50-16.gh-issue-100288.5XCk0G.rst
new file mode 100644
index 00000000000000..45182108b1a419
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-12-16-08-50-16.gh-issue-100288.5XCk0G.rst	
@@ -0,0 +1 @@
+Specialize method loading for objects with ``Py_TPFLAGS_MANAGED_DICT`` set.

From 1aecb3c9b9091d04db269a2526db16bec761a904 Mon Sep 17 00:00:00 2001
From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Date: Fri, 16 Dec 2022 18:38:37 +0800
Subject: [PATCH 4/4] Access the correct dict

---
 Python/bytecodes.c         | 6 ++++--
 Python/generated_cases.c.h | 6 ++++--
 Python/specialize.c        | 9 +++++++--
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index b8e0df3f054516..4ba571274612bd 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2738,8 +2738,10 @@ dummy_func(
             assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
             PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
             DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
-            PyDictKeysObject *keys = ((PyHeapTypeObject *)self_cls)->ht_cached_keys;
-            DEOPT_IF(keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
+            PyObject *dict = _PyDictOrValues_GetDict(dorv);
+            PyDictKeysObject *keys = (dict == NULL) ? NULL : ((PyDictObject *)dict)->ma_keys;
+            // Note: cache->keys_version can be 0 when dict is NULL.
+            DEOPT_IF(keys != NULL && keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
             STAT_INC(LOAD_ATTR, hit);
             PyObject *res = read_obj(cache->descr);
             assert(res != NULL);
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 85ba03d47f8054..3e32bdbc98e076 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2979,8 +2979,10 @@
             assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
             PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
             DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
-            PyDictKeysObject *keys = ((PyHeapTypeObject *)self_cls)->ht_cached_keys;
-            DEOPT_IF(keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
+            PyObject *dict = _PyDictOrValues_GetDict(dorv);
+            PyDictKeysObject *keys = (dict == NULL) ? NULL : ((PyDictObject *)dict)->ma_keys;
+            // Note: cache->keys_version can be 0 when dict is NULL.
+            DEOPT_IF(keys != NULL && keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
             STAT_INC(LOAD_ATTR, hit);
             PyObject *res = read_obj(cache->descr);
             assert(res != NULL);
diff --git a/Python/specialize.c b/Python/specialize.c
index 0ef98fe62927e8..5c1345b469634b 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -1014,11 +1014,13 @@ PyObject *descr, DescriptorClassification kind)
     PyDictKeysObject *keys;
     if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
         PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
-        keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
         if (_PyDictOrValues_IsValues(dorv)) {
+            keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
             dictkind = MANAGED_VALUES;
         }
         else {
+            PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
+            keys = dict != NULL ? dict->ma_keys : NULL;
             // User has directly accessed __dict__.
             dictkind = MANAGED_DICT;
         }
@@ -1046,7 +1048,7 @@ PyObject *descr, DescriptorClassification kind)
             }
         }
     }
-    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT || dictkind == MANAGED_DICT) {
+    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT || (dictkind == MANAGED_DICT && keys != NULL)) {
         Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
         if (index != DKIX_EMPTY) {
             SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
@@ -1067,6 +1069,9 @@ PyObject *descr, DescriptorClassification kind)
             _py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_VALUES);
             break;
         case MANAGED_DICT:
+            if (keys == NULL) {
+                write_u32(cache->keys_version, 0);
+            }
             _py_set_opcode(instr, LOAD_ATTR_METHOD_MANAGED_DICT);
             break;
         case OFFSET_DICT: