https://github.com/python/cpython/commit/5847931d11f2d51058e41cbca253a3cba712e899
commit: 5847931d11f2d51058e41cbca253a3cba712e899
branch: main
author: Kumar Aditya <[email protected]>
committer: markshannon <[email protected]>
date: 2026-05-04T09:39:03+01:00
summary:

gh-143732: allow dict subclasses to be specialized  (GH-148128)

files:
M Include/internal/pycore_dict.h
M Include/internal/pycore_opcode_metadata.h
M Include/internal/pycore_uop_ids.h
M Include/internal/pycore_uop_metadata.h
M Lib/test/test_capi/test_opt.py
M Lib/test/test_opcache.py
M Modules/_testinternalcapi/test_cases.c.h
M Objects/dictobject.c
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
M Python/record_functions.c.h
M Python/specialize.c

diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index 6c6e3b77e69fab..ff6588b3e9718c 100644
--- a/Include/internal/pycore_dict.h
+++ b/Include/internal/pycore_dict.h
@@ -44,6 +44,10 @@ extern int _PyDict_Next(
 
 extern int _PyDict_HasOnlyStringKeys(PyObject *mp);
 
+PyAPI_FUNC(PyObject *) _PyDict_Subscript(PyObject *self, PyObject *key);
+PyAPI_FUNC(PyObject *) _PyDict_SubscriptKnownHash(PyObject *self, PyObject 
*key, Py_hash_t hash);
+PyAPI_FUNC(int) _PyDict_StoreSubscript(PyObject *self, PyObject *key, PyObject 
*value);
+
 // Export for '_ctypes' shared extension
 PyAPI_FUNC(Py_ssize_t) _PyDict_SizeOf(PyDictObject *);
 
diff --git a/Include/internal/pycore_opcode_metadata.h 
b/Include/internal/pycore_opcode_metadata.h
index 0d7e367a5618b2..8c4134061de94c 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -1112,7 +1112,7 @@ const struct opcode_metadata 
_PyOpcode_opcode_metadata[267] = {
     [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, 
HAS_LOCAL_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | 
HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
     [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG },
-    [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | 
HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
+    [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | 
HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | 
HAS_RECORDS_VALUE_FLAG },
     [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | 
HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | 
HAS_RECORDS_VALUE_FLAG },
     [BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | 
HAS_ESCAPES_FLAG },
     [BINARY_OP_SUBSCR_LIST_SLICE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | 
HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
@@ -1315,7 +1315,7 @@ const struct opcode_metadata 
_PyOpcode_opcode_metadata[267] = {
     [STORE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | 
HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [STORE_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [STORE_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG 
},
-    [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | 
HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
+    [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | 
HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
     [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | 
HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
     [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG },
     [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@@ -1368,7 +1368,7 @@ _PyOpcode_macro_expansion[256] = {
     [BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 3, .uops = { { 
_GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, 
{ _BINARY_OP_INPLACE_ADD_UNICODE, OPARG_SIMPLE, 5 } } },
     [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, 
OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { 
_BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 
}, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
     [BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, 
OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { 
_BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, 
{ _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
-    [BINARY_OP_SUBSCR_DICT] = { .nuops = 4, .uops = { { _GUARD_NOS_ANY_DICT, 
OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 }, { _POP_TOP, 
OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } },
+    [BINARY_OP_SUBSCR_DICT] = { .nuops = 5, .uops = { { _RECORD_NOS_TYPE, 
OPARG_SIMPLE, 0 }, { _GUARD_NOS_DICT_SUBSCRIPT, OPARG_SIMPLE, 0 }, { 
_BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { 
_POP_TOP, OPARG_SIMPLE, 5 } } },
     [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 5, .uops = { { _RECORD_NOS, 
OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { 
_BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, 
OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } },
     [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, 
OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { 
_BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 
}, { _POP_TOP, OPARG_SIMPLE, 5 } } },
     [BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 5, .uops = { { 
_GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { 
_BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 }, 
{ _POP_TOP, OPARG_SIMPLE, 5 } } },
@@ -1531,7 +1531,7 @@ _PyOpcode_macro_expansion[256] = {
     [STORE_NAME] = { .nuops = 1, .uops = { { _STORE_NAME, OPARG_SIMPLE, 0 } } 
},
     [STORE_SLICE] = { .nuops = 1, .uops = { { _STORE_SLICE, OPARG_SIMPLE, 0 } 
} },
     [STORE_SUBSCR] = { .nuops = 1, .uops = { { _STORE_SUBSCR, OPARG_SIMPLE, 0 
} } },
-    [STORE_SUBSCR_DICT] = { .nuops = 3, .uops = { { _GUARD_NOS_DICT, 
OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_DICT, OPARG_SIMPLE, 1 }, { _POP_TOP, 
OPARG_SIMPLE, 1 } } },
+    [STORE_SUBSCR_DICT] = { .nuops = 4, .uops = { { _RECORD_NOS_TYPE, 
OPARG_SIMPLE, 0 }, { _GUARD_NOS_DICT_STORE_SUBSCRIPT, OPARG_SIMPLE, 0 }, { 
_STORE_SUBSCR_DICT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } },
     [STORE_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, 
OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { 
_STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { 
_POP_TOP, OPARG_SIMPLE, 1 } } },
     [SWAP] = { .nuops = 1, .uops = { { _SWAP, OPARG_SIMPLE, 0 } } },
     [TO_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL, OPARG_SIMPLE, 2 } } },
diff --git a/Include/internal/pycore_uop_ids.h 
b/Include/internal/pycore_uop_ids.h
index bd1440a89bd82e..d1919b9f8df362 100644
--- a/Include/internal/pycore_uop_ids.h
+++ b/Include/internal/pycore_uop_ids.h
@@ -200,9 +200,9 @@ extern "C" {
 #define _GUARD_ITER_VIRTUAL 461
 #define _GUARD_KEYS_VERSION 462
 #define _GUARD_LOAD_SUPER_ATTR_METHOD 463
-#define _GUARD_NOS_ANY_DICT 464
-#define _GUARD_NOS_COMPACT_ASCII 465
-#define _GUARD_NOS_DICT 466
+#define _GUARD_NOS_COMPACT_ASCII 464
+#define _GUARD_NOS_DICT_STORE_SUBSCRIPT 465
+#define _GUARD_NOS_DICT_SUBSCRIPT 466
 #define _GUARD_NOS_FLOAT 467
 #define _GUARD_NOS_INT 468
 #define _GUARD_NOS_ITER_VIRTUAL 469
@@ -845,18 +845,18 @@ extern "C" {
 #define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1057
 #define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1058
 #define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1059
-#define _GUARD_NOS_ANY_DICT_r02 1060
-#define _GUARD_NOS_ANY_DICT_r12 1061
-#define _GUARD_NOS_ANY_DICT_r22 1062
-#define _GUARD_NOS_ANY_DICT_r33 1063
-#define _GUARD_NOS_COMPACT_ASCII_r02 1064
-#define _GUARD_NOS_COMPACT_ASCII_r12 1065
-#define _GUARD_NOS_COMPACT_ASCII_r22 1066
-#define _GUARD_NOS_COMPACT_ASCII_r33 1067
-#define _GUARD_NOS_DICT_r02 1068
-#define _GUARD_NOS_DICT_r12 1069
-#define _GUARD_NOS_DICT_r22 1070
-#define _GUARD_NOS_DICT_r33 1071
+#define _GUARD_NOS_COMPACT_ASCII_r02 1060
+#define _GUARD_NOS_COMPACT_ASCII_r12 1061
+#define _GUARD_NOS_COMPACT_ASCII_r22 1062
+#define _GUARD_NOS_COMPACT_ASCII_r33 1063
+#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1064
+#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1065
+#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1066
+#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1067
+#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1068
+#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1069
+#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1070
+#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1071
 #define _GUARD_NOS_FLOAT_r02 1072
 #define _GUARD_NOS_FLOAT_r12 1073
 #define _GUARD_NOS_FLOAT_r22 1074
diff --git a/Include/internal/pycore_uop_metadata.h 
b/Include/internal/pycore_uop_metadata.h
index 8f543dbeeb8bc9..d6ab67c2e2e86e 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -144,8 +144,8 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_GUARD_TOS_TUPLE] = HAS_EXIT_FLAG,
     [_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS] = HAS_EXIT_FLAG,
     [_BINARY_OP_SUBSCR_TUPLE_INT] = 0,
-    [_GUARD_NOS_DICT] = HAS_EXIT_FLAG,
-    [_GUARD_NOS_ANY_DICT] = HAS_EXIT_FLAG,
+    [_GUARD_NOS_DICT_SUBSCRIPT] = HAS_DEOPT_FLAG,
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT] = HAS_DEOPT_FLAG,
     [_GUARD_TOS_ANY_DICT] = HAS_EXIT_FLAG,
     [_GUARD_TOS_DICT] = HAS_EXIT_FLAG,
     [_GUARD_TOS_FROZENDICT] = HAS_EXIT_FLAG,
@@ -1423,22 +1423,22 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
             { -1, -1, -1 },
         },
     },
-    [_GUARD_NOS_DICT] = {
+    [_GUARD_NOS_DICT_SUBSCRIPT] = {
         .best = { 0, 1, 2, 3 },
         .entries = {
-            { 2, 0, _GUARD_NOS_DICT_r02 },
-            { 2, 1, _GUARD_NOS_DICT_r12 },
-            { 2, 2, _GUARD_NOS_DICT_r22 },
-            { 3, 3, _GUARD_NOS_DICT_r33 },
+            { 2, 0, _GUARD_NOS_DICT_SUBSCRIPT_r02 },
+            { 2, 1, _GUARD_NOS_DICT_SUBSCRIPT_r12 },
+            { 2, 2, _GUARD_NOS_DICT_SUBSCRIPT_r22 },
+            { 3, 3, _GUARD_NOS_DICT_SUBSCRIPT_r33 },
         },
     },
-    [_GUARD_NOS_ANY_DICT] = {
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT] = {
         .best = { 0, 1, 2, 3 },
         .entries = {
-            { 2, 0, _GUARD_NOS_ANY_DICT_r02 },
-            { 2, 1, _GUARD_NOS_ANY_DICT_r12 },
-            { 2, 2, _GUARD_NOS_ANY_DICT_r22 },
-            { 3, 3, _GUARD_NOS_ANY_DICT_r33 },
+            { 3, 0, _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 },
+            { 3, 1, _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 },
+            { 3, 2, _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 },
+            { 3, 3, _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 },
         },
     },
     [_GUARD_TOS_ANY_DICT] = {
@@ -4187,14 +4187,14 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
     [_BINARY_OP_SUBSCR_TUPLE_INT_r03] = _BINARY_OP_SUBSCR_TUPLE_INT,
     [_BINARY_OP_SUBSCR_TUPLE_INT_r13] = _BINARY_OP_SUBSCR_TUPLE_INT,
     [_BINARY_OP_SUBSCR_TUPLE_INT_r23] = _BINARY_OP_SUBSCR_TUPLE_INT,
-    [_GUARD_NOS_DICT_r02] = _GUARD_NOS_DICT,
-    [_GUARD_NOS_DICT_r12] = _GUARD_NOS_DICT,
-    [_GUARD_NOS_DICT_r22] = _GUARD_NOS_DICT,
-    [_GUARD_NOS_DICT_r33] = _GUARD_NOS_DICT,
-    [_GUARD_NOS_ANY_DICT_r02] = _GUARD_NOS_ANY_DICT,
-    [_GUARD_NOS_ANY_DICT_r12] = _GUARD_NOS_ANY_DICT,
-    [_GUARD_NOS_ANY_DICT_r22] = _GUARD_NOS_ANY_DICT,
-    [_GUARD_NOS_ANY_DICT_r33] = _GUARD_NOS_ANY_DICT,
+    [_GUARD_NOS_DICT_SUBSCRIPT_r02] = _GUARD_NOS_DICT_SUBSCRIPT,
+    [_GUARD_NOS_DICT_SUBSCRIPT_r12] = _GUARD_NOS_DICT_SUBSCRIPT,
+    [_GUARD_NOS_DICT_SUBSCRIPT_r22] = _GUARD_NOS_DICT_SUBSCRIPT,
+    [_GUARD_NOS_DICT_SUBSCRIPT_r33] = _GUARD_NOS_DICT_SUBSCRIPT,
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r03] = _GUARD_NOS_DICT_STORE_SUBSCRIPT,
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r13] = _GUARD_NOS_DICT_STORE_SUBSCRIPT,
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r23] = _GUARD_NOS_DICT_STORE_SUBSCRIPT,
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r33] = _GUARD_NOS_DICT_STORE_SUBSCRIPT,
     [_GUARD_TOS_ANY_DICT_r01] = _GUARD_TOS_ANY_DICT,
     [_GUARD_TOS_ANY_DICT_r11] = _GUARD_TOS_ANY_DICT,
     [_GUARD_TOS_ANY_DICT_r22] = _GUARD_TOS_ANY_DICT,
@@ -5386,21 +5386,21 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] 
= {
     [_GUARD_LOAD_SUPER_ATTR_METHOD_r13] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r13",
     [_GUARD_LOAD_SUPER_ATTR_METHOD_r23] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r23",
     [_GUARD_LOAD_SUPER_ATTR_METHOD_r33] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r33",
-    [_GUARD_NOS_ANY_DICT] = "_GUARD_NOS_ANY_DICT",
-    [_GUARD_NOS_ANY_DICT_r02] = "_GUARD_NOS_ANY_DICT_r02",
-    [_GUARD_NOS_ANY_DICT_r12] = "_GUARD_NOS_ANY_DICT_r12",
-    [_GUARD_NOS_ANY_DICT_r22] = "_GUARD_NOS_ANY_DICT_r22",
-    [_GUARD_NOS_ANY_DICT_r33] = "_GUARD_NOS_ANY_DICT_r33",
     [_GUARD_NOS_COMPACT_ASCII] = "_GUARD_NOS_COMPACT_ASCII",
     [_GUARD_NOS_COMPACT_ASCII_r02] = "_GUARD_NOS_COMPACT_ASCII_r02",
     [_GUARD_NOS_COMPACT_ASCII_r12] = "_GUARD_NOS_COMPACT_ASCII_r12",
     [_GUARD_NOS_COMPACT_ASCII_r22] = "_GUARD_NOS_COMPACT_ASCII_r22",
     [_GUARD_NOS_COMPACT_ASCII_r33] = "_GUARD_NOS_COMPACT_ASCII_r33",
-    [_GUARD_NOS_DICT] = "_GUARD_NOS_DICT",
-    [_GUARD_NOS_DICT_r02] = "_GUARD_NOS_DICT_r02",
-    [_GUARD_NOS_DICT_r12] = "_GUARD_NOS_DICT_r12",
-    [_GUARD_NOS_DICT_r22] = "_GUARD_NOS_DICT_r22",
-    [_GUARD_NOS_DICT_r33] = "_GUARD_NOS_DICT_r33",
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT] = "_GUARD_NOS_DICT_STORE_SUBSCRIPT",
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r03] = 
"_GUARD_NOS_DICT_STORE_SUBSCRIPT_r03",
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r13] = 
"_GUARD_NOS_DICT_STORE_SUBSCRIPT_r13",
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r23] = 
"_GUARD_NOS_DICT_STORE_SUBSCRIPT_r23",
+    [_GUARD_NOS_DICT_STORE_SUBSCRIPT_r33] = 
"_GUARD_NOS_DICT_STORE_SUBSCRIPT_r33",
+    [_GUARD_NOS_DICT_SUBSCRIPT] = "_GUARD_NOS_DICT_SUBSCRIPT",
+    [_GUARD_NOS_DICT_SUBSCRIPT_r02] = "_GUARD_NOS_DICT_SUBSCRIPT_r02",
+    [_GUARD_NOS_DICT_SUBSCRIPT_r12] = "_GUARD_NOS_DICT_SUBSCRIPT_r12",
+    [_GUARD_NOS_DICT_SUBSCRIPT_r22] = "_GUARD_NOS_DICT_SUBSCRIPT_r22",
+    [_GUARD_NOS_DICT_SUBSCRIPT_r33] = "_GUARD_NOS_DICT_SUBSCRIPT_r33",
     [_GUARD_NOS_FLOAT] = "_GUARD_NOS_FLOAT",
     [_GUARD_NOS_FLOAT_r02] = "_GUARD_NOS_FLOAT_r02",
     [_GUARD_NOS_FLOAT_r12] = "_GUARD_NOS_FLOAT_r12",
@@ -6321,9 +6321,9 @@ int _PyUop_num_popped(int opcode, int oparg)
             return 0;
         case _BINARY_OP_SUBSCR_TUPLE_INT:
             return 2;
-        case _GUARD_NOS_DICT:
+        case _GUARD_NOS_DICT_SUBSCRIPT:
             return 0;
-        case _GUARD_NOS_ANY_DICT:
+        case _GUARD_NOS_DICT_STORE_SUBSCRIPT:
             return 0;
         case _GUARD_TOS_ANY_DICT:
             return 0;
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index d4af910fb68c61..e371070d0b7c1c 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -2273,10 +2273,49 @@ def f(n):
         self.assertEqual(res, TIER2_THRESHOLD)
         self.assertIsNotNone(ex)
         uops = get_opnames(ex)
-        self.assertEqual(uops.count("_GUARD_NOS_DICT"), 0)
-        self.assertEqual(uops.count("_STORE_SUBSCR_DICT_KNOWN_HASH"), 1)
+        self.assertEqual(uops.count("_GUARD_NOS_DICT_SUBSCRIPT"), 0)
+        self.assertEqual(uops.count("_GUARD_NOS_DICT_STORE_SUBSCRIPT"), 0)
         self.assertEqual(uops.count("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH"), 1)
 
+    def test_dict_subclass_subscr(self):
+        import collections
+
+        def f(n):
+            x = 0
+            d = collections.defaultdict(int)
+            for _ in range(n):
+                d["key"] = 1
+                x += d["key"]
+            return x
+
+        res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
+        self.assertEqual(res, TIER2_THRESHOLD)
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        self.assertEqual(uops.count("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH"), 1)
+        self.assertEqual(uops.count("_STORE_SUBSCR_DICT_KNOWN_HASH"), 1)
+        self.assertEqual(uops.count("_GUARD_NOS_DICT_SUBSCRIPT"), 0)
+        self.assertEqual(uops.count("_GUARD_NOS_DICT_STORE_SUBSCRIPT"), 0)
+        self.assertEqual(uops.count("_GUARD_TYPE"), 1)
+
+    def test_dict_subclass_subscr_with_override(self):
+        class MyDict(dict):
+            def __getitem__(self, key):
+                return 42
+
+        def f(n):
+            d = MyDict()
+            x = 0
+            for _ in range(n):
+                x += d["anything"]
+            return x
+
+        res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
+        self.assertEqual(res, 42 * TIER2_THRESHOLD)
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        self.assertEqual(uops.count("_BINARY_OP_SUBSCR_INIT_CALL"), 1)
+
     def test_remove_guard_for_known_type_list(self):
         def f(n):
             x = 0
@@ -2599,6 +2638,23 @@ def testfunc(n):
         self.assertIn("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH", uops)
         self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops)
 
+    def test_binary_op_subscr_defaultdict_known_hash(self):
+        # str, int, bytes, float, complex, tuple and any python object which 
has generic hash
+        import collections
+
+        def testfunc(n):
+            x = 0
+            d = collections.defaultdict(lambda: 1)
+            for _ in range(n):
+                x += d['a'] + d[1] + d[b'b'] + d[(1, 2)] + d[_GENERIC_KEY] + 
d[1.5] + d[1+2j]
+            return x
+
+        res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+        self.assertEqual(res, 7 * TIER2_THRESHOLD)
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        self.assertIn("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH", uops)
+        self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops)
 
     def test_binary_op_subscr_constant_frozendict_known_hash(self):
         def testfunc(n):
@@ -2635,6 +2691,28 @@ def testfunc(n):
         self.assertIn("_STORE_SUBSCR_DICT_KNOWN_HASH", uops)
         self.assertNotIn("_STORE_SUBSCR_DICT", uops)
 
+    def test_store_subscr_defaultdict_known_hash(self):
+        import collections
+
+        def testfunc(n):
+            d = collections.defaultdict(lambda: 0)
+            for _ in range(n):
+                d['a'] += 1
+                d[1] += 2
+                d[b'b'] += 3
+                d[(1, 2)] += 4
+                d[_GENERIC_KEY] += 5
+                d[1.5] += 6
+                d[1+2j] += 7
+            return d['a'] + d[1] + d[b'b'] + d[(1, 2)] + d[_GENERIC_KEY] + 
d[1.5] + d[1+2j]
+
+        res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+        self.assertEqual(res, 28 * TIER2_THRESHOLD)
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        self.assertIn("_STORE_SUBSCR_DICT_KNOWN_HASH", uops)
+        self.assertNotIn("_STORE_SUBSCR_DICT", uops)
+
     def test_contains_op(self):
         def testfunc(n):
             x = 0
diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index f5f408fcb4b311..9480bf8b87baf3 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -1,3 +1,4 @@
+import collections
 import copy
 import pickle
 import dis
@@ -1863,7 +1864,43 @@ class MyFrozenDict(frozendict):
                 self.assertEqual(a[2], 3)
 
         binary_subscr_frozen_dict_subclass()
-        self.assert_no_opcode(binary_subscr_frozen_dict_subclass, 
"BINARY_OP_SUBSCR_DICT")
+        self.assert_specialized(binary_subscr_frozen_dict_subclass, 
"BINARY_OP_SUBSCR_DICT")
+        self.assert_no_opcode(binary_subscr_frozen_dict_subclass, "BINARY_OP")
+
+        def binary_subscr_defaultdict():
+            for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+                a = collections.defaultdict(lambda: 42, {1: 2, 2: 3})
+                self.assertEqual(a[1], 2)
+                self.assertEqual(a[2], 3)
+                self.assertEqual(a[7], 42)
+
+        binary_subscr_defaultdict()
+        self.assert_specialized(binary_subscr_defaultdict, 
"BINARY_OP_SUBSCR_DICT")
+        self.assert_no_opcode(binary_subscr_defaultdict, "BINARY_OP")
+
+        def binary_subscr_counter():
+            for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+                a = collections.Counter('abcdeabcdabcaba')
+                self.assertEqual(a['a'], 5)
+                self.assertEqual(a['b'], 4)
+                self.assertEqual(a['m'], 0)
+
+        binary_subscr_counter()
+        self.assert_specialized(binary_subscr_counter, "BINARY_OP_SUBSCR_DICT")
+        self.assert_no_opcode(binary_subscr_counter, "BINARY_OP")
+
+        def binary_subscr_dict_subclass_override():
+            class MyDict(dict):
+                def __getitem__(self, key):
+                    return 42
+
+            for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+                a = MyDict()
+                self.assertEqual(a['a'], 42)
+                self.assertEqual(a['b'], 42)
+
+        binary_subscr_dict_subclass_override()
+        self.assert_no_opcode(binary_subscr_dict_subclass_override, 
"BINARY_OP_SUBSCR_DICT")
 
         def binary_subscr_str_int():
             for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
@@ -1924,6 +1961,29 @@ def store_subscr_frozen_dict():
         self.assert_specialized(store_subscr_frozen_dict, "STORE_SUBSCR_DICT")
         self.assert_no_opcode(store_subscr_frozen_dict, "STORE_SUBSCR")
 
+        def store_subscr_defaultdict():
+            for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+                a = collections.defaultdict(int)
+                a[1] = 4
+                self.assertEqual(a[1], 4)
+
+        store_subscr_defaultdict()
+        self.assert_specialized(store_subscr_defaultdict, "STORE_SUBSCR_DICT")
+        self.assert_no_opcode(store_subscr_defaultdict, "STORE_SUBSCR")
+
+        def store_subscr_dict_subclass_override():
+            class MyDict(dict):
+                def __setitem__(self, key, value):
+                    super().__setitem__(key, value * 2)
+
+            for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+                a = MyDict()
+                a['x'] = 5
+                self.assertEqual(a['x'], 10)
+
+        store_subscr_dict_subclass_override()
+        self.assert_no_opcode(store_subscr_dict_subclass_override, 
"STORE_SUBSCR_DICT")
+
     @cpython_only
     @requires_specialization
     def test_compare_op(self):
diff --git a/Modules/_testinternalcapi/test_cases.c.h 
b/Modules/_testinternalcapi/test_cases.c.h
index bd69211fd22206..dac46a3e22afa9 100644
--- a/Modules/_testinternalcapi/test_cases.c.h
+++ b/Modules/_testinternalcapi/test_cases.c.h
@@ -645,11 +645,16 @@
             _PyStackRef ds;
             _PyStackRef ss;
             _PyStackRef value;
-            // _GUARD_NOS_ANY_DICT
+            // _GUARD_NOS_DICT_SUBSCRIPT
             {
                 nos = stack_pointer[-2];
                 PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-                if (!PyAnyDict_CheckExact(o)) {
+                if (!Py_TYPE(o)->tp_as_mapping) {
+                    UPDATE_MISS_STATS(BINARY_OP);
+                    assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    JUMP_TO_PREDICTED(BINARY_OP);
+                }
+                if (Py_TYPE(o)->tp_as_mapping->mp_subscript != 
_PyDict_Subscript) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
                     JUMP_TO_PREDICTED(BINARY_OP);
@@ -662,18 +667,12 @@
                 dict_st = nos;
                 PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
                 PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-                assert(PyAnyDict_CheckExact(dict));
+                assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
                 STAT_INC(BINARY_OP, hit);
-                PyObject *res_o;
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                int rc = PyDict_GetItemRef(dict, sub, &res_o);
+                PyObject *res_o = _PyDict_Subscript(dict, sub);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
-                if (rc == 0) {
-                    _PyFrame_SetStackPointer(frame, stack_pointer);
-                    _PyErr_SetKeyError(sub);
-                    stack_pointer = _PyFrame_GetStackPointer(frame);
-                }
-                if (rc <= 0) {
+                if (res_o == NULL) {
                     JUMP_TO_LABEL(error);
                 }
                 res = PyStackRef_FromPyObjectSteal(res_o);
@@ -12005,11 +12004,16 @@
             _PyStackRef dict_st;
             _PyStackRef sub;
             _PyStackRef st;
-            // _GUARD_NOS_DICT
+            // _GUARD_NOS_DICT_STORE_SUBSCRIPT
             {
                 nos = stack_pointer[-2];
                 PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-                if (!PyDict_CheckExact(o)) {
+                if (!Py_TYPE(o)->tp_as_mapping) {
+                    UPDATE_MISS_STATS(STORE_SUBSCR);
+                    assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    JUMP_TO_PREDICTED(STORE_SUBSCR);
+                }
+                if (Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
@@ -12022,7 +12026,7 @@
                 dict_st = nos;
                 value = stack_pointer[-3];
                 PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-                assert(PyDict_CheckExact(dict));
+                assert(Py_TYPE(dict)->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript);
                 STAT_INC(STORE_SUBSCR, hit);
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 int err = _PyDict_SetItem_Take2((PyDictObject *)dict,
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 5be5baf8fc4cfe..42bc63acd9049c 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -3669,19 +3669,13 @@ frozendict_length(PyObject *self)
     return _PyAnyDict_CAST(self)->ma_used;
 }
 
-static PyObject *
-dict_subscript(PyObject *self, PyObject *key)
+PyObject *
+_PyDict_SubscriptKnownHash(PyObject *self, PyObject *key, Py_hash_t hash)
 {
     PyDictObject *mp = (PyDictObject *)self;
     Py_ssize_t ix;
-    Py_hash_t hash;
     PyObject *value;
 
-    hash = _PyObject_HashFast(key);
-    if (hash == -1) {
-        dict_unhashable_type(self, key);
-        return NULL;
-    }
     ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
     if (ix == DKIX_ERROR)
         return NULL;
@@ -3705,8 +3699,19 @@ dict_subscript(PyObject *self, PyObject *key)
     return value;
 }
 
-static int
-dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w)
+PyObject *
+_PyDict_Subscript(PyObject *self, PyObject *key)
+{
+    Py_hash_t hash = _PyObject_HashFast(key);
+    if (hash == -1) {
+        dict_unhashable_type(self, key);
+        return NULL;
+    }
+    return _PyDict_SubscriptKnownHash(self, key, hash);
+}
+
+int
+_PyDict_StoreSubscript(PyObject *mp, PyObject *v, PyObject *w)
 {
     if (w == NULL)
         return PyDict_DelItem(mp, v);
@@ -3716,8 +3721,8 @@ dict_ass_sub(PyObject *mp, PyObject *v, PyObject *w)
 
 static PyMappingMethods dict_as_mapping = {
     dict_length, /*mp_length*/
-    dict_subscript, /*mp_subscript*/
-    dict_ass_sub, /*mp_ass_subscript*/
+    _PyDict_Subscript, /*mp_subscript*/
+    _PyDict_StoreSubscript, /*mp_ass_subscript*/
 };
 
 static PyObject *
@@ -5103,7 +5108,7 @@ In either case, this is followed by: for k in F:  D[k] = 
F[k]");
 
 static PyMethodDef mapp_methods[] = {
     DICT___CONTAINS___METHODDEF
-    {"__getitem__",     dict_subscript,                 METH_O | METH_COEXIST,
+    {"__getitem__",     _PyDict_Subscript,                 METH_O | 
METH_COEXIST,
      getitem__doc__},
     DICT___SIZEOF___METHODDEF
     DICT_GET_METHODDEF
@@ -8153,12 +8158,12 @@ static PyNumberMethods frozendict_as_number = {
 
 static PyMappingMethods frozendict_as_mapping = {
     .mp_length = frozendict_length,
-    .mp_subscript = dict_subscript,
+    .mp_subscript = _PyDict_Subscript,
 };
 
 static PyMethodDef frozendict_methods[] = {
     DICT___CONTAINS___METHODDEF
-    {"__getitem__", dict_subscript, METH_O | METH_COEXIST, getitem__doc__},
+    {"__getitem__", _PyDict_Subscript, METH_O | METH_COEXIST, getitem__doc__},
     DICT___SIZEOF___METHODDEF
     DICT_GET_METHODDEF
     DICT_KEYS_METHODDEF
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 963391e7598fb6..0277a94ab36632 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1277,14 +1277,16 @@ dummy_func(
             INPUTS_DEAD();
         }
 
-        op(_GUARD_NOS_DICT, (nos, unused -- nos, unused)) {
+        op(_GUARD_NOS_DICT_SUBSCRIPT, (nos, unused -- nos, unused)) {
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            EXIT_IF(!PyDict_CheckExact(o));
+            DEOPT_IF(!Py_TYPE(o)->tp_as_mapping);
+            DEOPT_IF(Py_TYPE(o)->tp_as_mapping->mp_subscript != 
_PyDict_Subscript);
         }
 
-        op(_GUARD_NOS_ANY_DICT, (nos, unused -- nos, unused)) {
+        op(_GUARD_NOS_DICT_STORE_SUBSCRIPT, (unused, nos, unused -- unused, 
nos, unused)) {
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            EXIT_IF(!PyAnyDict_CheckExact(o));
+            DEOPT_IF(!Py_TYPE(o)->tp_as_mapping);
+            DEOPT_IF(Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript);
         }
 
         op(_GUARD_TOS_ANY_DICT, (tos -- tos)) {
@@ -1303,20 +1305,16 @@ dummy_func(
         }
 
         macro(BINARY_OP_SUBSCR_DICT) =
-            _GUARD_NOS_ANY_DICT + unused/5 + _BINARY_OP_SUBSCR_DICT + POP_TOP 
+ POP_TOP;
+            _RECORD_NOS_TYPE +
+            _GUARD_NOS_DICT_SUBSCRIPT + unused/5 + _BINARY_OP_SUBSCR_DICT + 
POP_TOP + POP_TOP;
 
         tier2 op(_BINARY_OP_SUBSCR_DICT_KNOWN_HASH, (dict_st, sub_st, hash/4 
-- res, ds, ss)) {
             PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-
-            assert(PyAnyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
             STAT_INC(BINARY_OP, hit);
-            PyObject *res_o;
-            int rc = _PyDict_GetItemRef_KnownHash((PyDictObject *)dict, sub, 
(Py_hash_t)hash, &res_o);
-            if (rc == 0) {
-                _PyErr_SetKeyError(sub);
-            }
-            if (rc <= 0) {
+            PyObject *res_o = _PyDict_SubscriptKnownHash(dict, sub, 
(Py_hash_t)hash);
+            if (res_o == NULL) {
                 ERROR_NO_POP();
             }
             res = PyStackRef_FromPyObjectSteal(res_o);
@@ -1328,15 +1326,10 @@ dummy_func(
         op(_BINARY_OP_SUBSCR_DICT, (dict_st, sub_st -- res, ds, ss)) {
             PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-
-            assert(PyAnyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
             STAT_INC(BINARY_OP, hit);
-            PyObject *res_o;
-            int rc = PyDict_GetItemRef(dict, sub, &res_o);
-            if (rc == 0) {
-                _PyErr_SetKeyError(sub);
-            }
-            if (rc <= 0) {
+            PyObject *res_o = _PyDict_Subscript(dict, sub);
+            if (res_o == NULL) {
                 ERROR_NO_POP();
             }
             res = PyStackRef_FromPyObjectSteal(res_o);
@@ -1451,12 +1444,12 @@ dummy_func(
         }
 
         macro(STORE_SUBSCR_DICT) =
-            _GUARD_NOS_DICT + unused/1 + _STORE_SUBSCR_DICT + POP_TOP;
+            _RECORD_NOS_TYPE +
+            _GUARD_NOS_DICT_STORE_SUBSCRIPT + unused/1 + _STORE_SUBSCR_DICT + 
POP_TOP;
 
         op(_STORE_SUBSCR_DICT, (value, dict_st, sub -- st)) {
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-
-            assert(PyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript);
             STAT_INC(STORE_SUBSCR, hit);
             int err = _PyDict_SetItem_Take2((PyDictObject *)dict,
                                             PyStackRef_AsPyObjectSteal(sub),
@@ -1471,8 +1464,7 @@ dummy_func(
 
         tier2 op(_STORE_SUBSCR_DICT_KNOWN_HASH, (value, dict_st, sub, hash/4 
-- st)) {
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-
-            assert(PyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript);
             STAT_INC(STORE_SUBSCR, hit);
             int err = _PyDict_SetItem_Take2_KnownHash((PyDictObject *)dict,
                                                 
PyStackRef_AsPyObjectSteal(sub),
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index f8fc35de9d7957..b670ff3e766155 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -7460,13 +7460,18 @@
             break;
         }
 
-        case _GUARD_NOS_DICT_r02: {
+        case _GUARD_NOS_DICT_SUBSCRIPT_r02: {
             CHECK_CURRENT_CACHED_VALUES(0);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
             nos = stack_pointer[-2];
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
+                UOP_STAT_INC(uopcode, miss);
+                SET_CURRENT_CACHED_VALUES(0);
+                JUMP_TO_JUMP_TARGET();
+            }
+            if (Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript) {
                 UOP_STAT_INC(uopcode, miss);
                 SET_CURRENT_CACHED_VALUES(0);
                 JUMP_TO_JUMP_TARGET();
@@ -7480,14 +7485,20 @@
             break;
         }
 
-        case _GUARD_NOS_DICT_r12: {
+        case _GUARD_NOS_DICT_SUBSCRIPT_r12: {
             CHECK_CURRENT_CACHED_VALUES(1);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
             _PyStackRef _stack_item_0 = _tos_cache0;
             nos = stack_pointer[-1];
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(1);
+                JUMP_TO_JUMP_TARGET();
+            }
+            if (Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript) {
                 UOP_STAT_INC(uopcode, miss);
                 _tos_cache0 = _stack_item_0;
                 SET_CURRENT_CACHED_VALUES(1);
@@ -7502,7 +7513,7 @@
             break;
         }
 
-        case _GUARD_NOS_DICT_r22: {
+        case _GUARD_NOS_DICT_SUBSCRIPT_r22: {
             CHECK_CURRENT_CACHED_VALUES(2);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
@@ -7510,7 +7521,14 @@
             _PyStackRef _stack_item_1 = _tos_cache1;
             nos = _stack_item_0;
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache1 = _stack_item_1;
+                _tos_cache0 = nos;
+                SET_CURRENT_CACHED_VALUES(2);
+                JUMP_TO_JUMP_TARGET();
+            }
+            if (Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript) {
                 UOP_STAT_INC(uopcode, miss);
                 _tos_cache1 = _stack_item_1;
                 _tos_cache0 = nos;
@@ -7524,7 +7542,7 @@
             break;
         }
 
-        case _GUARD_NOS_DICT_r33: {
+        case _GUARD_NOS_DICT_SUBSCRIPT_r33: {
             CHECK_CURRENT_CACHED_VALUES(3);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
@@ -7533,7 +7551,15 @@
             _PyStackRef _stack_item_2 = _tos_cache2;
             nos = _stack_item_1;
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache2 = _stack_item_2;
+                _tos_cache1 = nos;
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(3);
+                JUMP_TO_JUMP_TARGET();
+            }
+            if (Py_TYPE(o)->tp_as_mapping->mp_subscript != _PyDict_Subscript) {
                 UOP_STAT_INC(uopcode, miss);
                 _tos_cache2 = _stack_item_2;
                 _tos_cache1 = nos;
@@ -7549,49 +7575,62 @@
             break;
         }
 
-        case _GUARD_NOS_ANY_DICT_r02: {
+        case _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03: {
             CHECK_CURRENT_CACHED_VALUES(0);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
             nos = stack_pointer[-2];
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyAnyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
                 UOP_STAT_INC(uopcode, miss);
                 SET_CURRENT_CACHED_VALUES(0);
                 JUMP_TO_JUMP_TARGET();
             }
-            _tos_cache1 = stack_pointer[-1];
-            _tos_cache0 = nos;
-            SET_CURRENT_CACHED_VALUES(2);
-            stack_pointer += -2;
+            if (Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript) {
+                UOP_STAT_INC(uopcode, miss);
+                SET_CURRENT_CACHED_VALUES(0);
+                JUMP_TO_JUMP_TARGET();
+            }
+            _tos_cache2 = stack_pointer[-1];
+            _tos_cache1 = nos;
+            _tos_cache0 = stack_pointer[-3];
+            SET_CURRENT_CACHED_VALUES(3);
+            stack_pointer += -3;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             break;
         }
 
-        case _GUARD_NOS_ANY_DICT_r12: {
+        case _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13: {
             CHECK_CURRENT_CACHED_VALUES(1);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
             _PyStackRef _stack_item_0 = _tos_cache0;
             nos = stack_pointer[-1];
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyAnyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
                 UOP_STAT_INC(uopcode, miss);
                 _tos_cache0 = _stack_item_0;
                 SET_CURRENT_CACHED_VALUES(1);
                 JUMP_TO_JUMP_TARGET();
             }
-            _tos_cache1 = _stack_item_0;
-            _tos_cache0 = nos;
-            SET_CURRENT_CACHED_VALUES(2);
-            stack_pointer += -1;
+            if (Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(1);
+                JUMP_TO_JUMP_TARGET();
+            }
+            _tos_cache2 = _stack_item_0;
+            _tos_cache1 = nos;
+            _tos_cache0 = stack_pointer[-2];
+            SET_CURRENT_CACHED_VALUES(3);
+            stack_pointer += -2;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             break;
         }
 
-        case _GUARD_NOS_ANY_DICT_r22: {
+        case _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23: {
             CHECK_CURRENT_CACHED_VALUES(2);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
@@ -7599,21 +7638,31 @@
             _PyStackRef _stack_item_1 = _tos_cache1;
             nos = _stack_item_0;
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyAnyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
                 UOP_STAT_INC(uopcode, miss);
                 _tos_cache1 = _stack_item_1;
                 _tos_cache0 = nos;
                 SET_CURRENT_CACHED_VALUES(2);
                 JUMP_TO_JUMP_TARGET();
             }
-            _tos_cache1 = _stack_item_1;
-            _tos_cache0 = nos;
-            SET_CURRENT_CACHED_VALUES(2);
+            if (Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache1 = _stack_item_1;
+                _tos_cache0 = nos;
+                SET_CURRENT_CACHED_VALUES(2);
+                JUMP_TO_JUMP_TARGET();
+            }
+            _tos_cache2 = _stack_item_1;
+            _tos_cache1 = nos;
+            _tos_cache0 = stack_pointer[-1];
+            SET_CURRENT_CACHED_VALUES(3);
+            stack_pointer += -1;
+            ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             break;
         }
 
-        case _GUARD_NOS_ANY_DICT_r33: {
+        case _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33: {
             CHECK_CURRENT_CACHED_VALUES(3);
             assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
             _PyStackRef nos;
@@ -7622,7 +7671,15 @@
             _PyStackRef _stack_item_2 = _tos_cache2;
             nos = _stack_item_1;
             PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-            if (!PyAnyDict_CheckExact(o)) {
+            if (!Py_TYPE(o)->tp_as_mapping) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache2 = _stack_item_2;
+                _tos_cache1 = nos;
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(3);
+                JUMP_TO_JUMP_TARGET();
+            }
+            if (Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript) {
                 UOP_STAT_INC(uopcode, miss);
                 _tos_cache2 = _stack_item_2;
                 _tos_cache1 = nos;
@@ -7908,22 +7965,16 @@
             PyObject *hash = (PyObject *)CURRENT_OPERAND0_64();
             PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-            assert(PyAnyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
             STAT_INC(BINARY_OP, hit);
-            PyObject *res_o;
             stack_pointer[0] = dict_st;
             stack_pointer[1] = sub_st;
             stack_pointer += 2;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            int rc = _PyDict_GetItemRef_KnownHash((PyDictObject *)dict, sub, 
(Py_hash_t)hash, &res_o);
+            PyObject *res_o = _PyDict_SubscriptKnownHash(dict, sub, 
(Py_hash_t)hash);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            if (rc == 0) {
-                _PyFrame_SetStackPointer(frame, stack_pointer);
-                _PyErr_SetKeyError(sub);
-                stack_pointer = _PyFrame_GetStackPointer(frame);
-            }
-            if (rc <= 0) {
+            if (res_o == NULL) {
                 SET_CURRENT_CACHED_VALUES(0);
                 JUMP_TO_ERROR();
             }
@@ -7954,22 +8005,16 @@
             dict_st = _stack_item_0;
             PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-            assert(PyAnyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
             STAT_INC(BINARY_OP, hit);
-            PyObject *res_o;
             stack_pointer[0] = dict_st;
             stack_pointer[1] = sub_st;
             stack_pointer += 2;
             ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            int rc = PyDict_GetItemRef(dict, sub, &res_o);
+            PyObject *res_o = _PyDict_Subscript(dict, sub);
             stack_pointer = _PyFrame_GetStackPointer(frame);
-            if (rc == 0) {
-                _PyFrame_SetStackPointer(frame, stack_pointer);
-                _PyErr_SetKeyError(sub);
-                stack_pointer = _PyFrame_GetStackPointer(frame);
-            }
-            if (rc <= 0) {
+            if (res_o == NULL) {
                 SET_CURRENT_CACHED_VALUES(0);
                 JUMP_TO_ERROR();
             }
@@ -8317,7 +8362,7 @@
             dict_st = _stack_item_1;
             value = _stack_item_0;
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-            assert(PyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript);
             STAT_INC(STORE_SUBSCR, hit);
             stack_pointer[0] = value;
             stack_pointer[1] = dict_st;
@@ -8364,7 +8409,7 @@
             value = _stack_item_0;
             PyObject *hash = (PyObject *)CURRENT_OPERAND0_64();
             PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-            assert(PyDict_CheckExact(dict));
+            assert(Py_TYPE(dict)->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript);
             STAT_INC(STORE_SUBSCR, hit);
             stack_pointer[0] = value;
             stack_pointer[1] = dict_st;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 105375e41e360b..bd2cf1c9cb19e5 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -645,11 +645,16 @@
             _PyStackRef ds;
             _PyStackRef ss;
             _PyStackRef value;
-            // _GUARD_NOS_ANY_DICT
+            // _GUARD_NOS_DICT_SUBSCRIPT
             {
                 nos = stack_pointer[-2];
                 PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-                if (!PyAnyDict_CheckExact(o)) {
+                if (!Py_TYPE(o)->tp_as_mapping) {
+                    UPDATE_MISS_STATS(BINARY_OP);
+                    assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
+                    JUMP_TO_PREDICTED(BINARY_OP);
+                }
+                if (Py_TYPE(o)->tp_as_mapping->mp_subscript != 
_PyDict_Subscript) {
                     UPDATE_MISS_STATS(BINARY_OP);
                     assert(_PyOpcode_Deopt[opcode] == (BINARY_OP));
                     JUMP_TO_PREDICTED(BINARY_OP);
@@ -662,18 +667,12 @@
                 dict_st = nos;
                 PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
                 PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-                assert(PyAnyDict_CheckExact(dict));
+                assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
                 STAT_INC(BINARY_OP, hit);
-                PyObject *res_o;
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                int rc = PyDict_GetItemRef(dict, sub, &res_o);
+                PyObject *res_o = _PyDict_Subscript(dict, sub);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
-                if (rc == 0) {
-                    _PyFrame_SetStackPointer(frame, stack_pointer);
-                    _PyErr_SetKeyError(sub);
-                    stack_pointer = _PyFrame_GetStackPointer(frame);
-                }
-                if (rc <= 0) {
+                if (res_o == NULL) {
                     JUMP_TO_LABEL(error);
                 }
                 res = PyStackRef_FromPyObjectSteal(res_o);
@@ -12002,11 +12001,16 @@
             _PyStackRef dict_st;
             _PyStackRef sub;
             _PyStackRef st;
-            // _GUARD_NOS_DICT
+            // _GUARD_NOS_DICT_STORE_SUBSCRIPT
             {
                 nos = stack_pointer[-2];
                 PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
-                if (!PyDict_CheckExact(o)) {
+                if (!Py_TYPE(o)->tp_as_mapping) {
+                    UPDATE_MISS_STATS(STORE_SUBSCR);
+                    assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
+                    JUMP_TO_PREDICTED(STORE_SUBSCR);
+                }
+                if (Py_TYPE(o)->tp_as_mapping->mp_ass_subscript != 
_PyDict_StoreSubscript) {
                     UPDATE_MISS_STATS(STORE_SUBSCR);
                     assert(_PyOpcode_Deopt[opcode] == (STORE_SUBSCR));
                     JUMP_TO_PREDICTED(STORE_SUBSCR);
@@ -12019,7 +12023,7 @@
                 dict_st = nos;
                 value = stack_pointer[-3];
                 PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-                assert(PyDict_CheckExact(dict));
+                assert(Py_TYPE(dict)->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript);
                 STAT_INC(STORE_SUBSCR, hit);
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 int err = _PyDict_SetItem_Take2((PyDictObject *)dict,
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index 0837d57b61b29d..2dcfbb6d3418c0 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -2166,17 +2166,45 @@ dummy_func(void) {
         }
     }
 
-    op(_GUARD_NOS_DICT, (nos, unused -- nos, unused)) {
-        if (sym_matches_type(nos, &PyDict_Type)) {
-            ADD_OP(_NOP, 0, 0);
+    op(_GUARD_NOS_DICT_SUBSCRIPT, (nos, unused -- nos, unused)) {
+        PyTypeObject *tp = sym_get_type(nos);
+        bool definite = true;
+        if (!tp) {
+            tp = sym_get_probable_type(nos);
+            definite = false;
+        }
+        if (tp && tp->tp_as_mapping &&
+            tp->tp_as_mapping->mp_subscript == _PyDict_Subscript) {
+            if (definite) {
+                ADD_OP(_NOP, 0, 0);
+            }
+            else {
+                ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+                sym_set_type(nos, tp);
+            }
+            PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
+            _Py_BloomFilter_Add(dependencies, tp);
         }
-        sym_set_type(nos, &PyDict_Type);
     }
 
-    op(_GUARD_NOS_ANY_DICT, (nos, unused -- nos, unused)) {
+    op(_GUARD_NOS_DICT_STORE_SUBSCRIPT, (unused, nos, unused -- unused, nos, 
unused)) {
         PyTypeObject *tp = sym_get_type(nos);
-        if (tp == &PyDict_Type || tp == &PyFrozenDict_Type) {
-            ADD_OP(_NOP, 0, 0);
+        bool definite = true;
+        if (!tp) {
+            tp = sym_get_probable_type(nos);
+            definite = false;
+        }
+        if (tp && tp->tp_as_mapping &&
+            tp->tp_as_mapping->mp_ass_subscript == _PyDict_StoreSubscript) {
+            if (definite) {
+                ADD_OP(_NOP, 0, 0);
+            }
+            else {
+                ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+                sym_set_type(nos, tp);
+            }
+            PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
+            _Py_BloomFilter_Add(dependencies, tp);
         }
     }
 
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 1ade86f64b2b20..0942089760f639 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -1475,22 +1475,50 @@
             break;
         }
 
-        case _GUARD_NOS_DICT: {
+        case _GUARD_NOS_DICT_SUBSCRIPT: {
             JitOptRef nos;
             nos = stack_pointer[-2];
-            if (sym_matches_type(nos, &PyDict_Type)) {
-                ADD_OP(_NOP, 0, 0);
+            PyTypeObject *tp = sym_get_type(nos);
+            bool definite = true;
+            if (!tp) {
+                tp = sym_get_probable_type(nos);
+                definite = false;
+            }
+            if (tp && tp->tp_as_mapping &&
+                tp->tp_as_mapping->mp_subscript == _PyDict_Subscript) {
+                if (definite) {
+                    ADD_OP(_NOP, 0, 0);
+                }
+                else {
+                    ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+                    sym_set_type(nos, tp);
+                }
+                PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
+                _Py_BloomFilter_Add(dependencies, tp);
             }
-            sym_set_type(nos, &PyDict_Type);
             break;
         }
 
-        case _GUARD_NOS_ANY_DICT: {
+        case _GUARD_NOS_DICT_STORE_SUBSCRIPT: {
             JitOptRef nos;
             nos = stack_pointer[-2];
             PyTypeObject *tp = sym_get_type(nos);
-            if (tp == &PyDict_Type || tp == &PyFrozenDict_Type) {
-                ADD_OP(_NOP, 0, 0);
+            bool definite = true;
+            if (!tp) {
+                tp = sym_get_probable_type(nos);
+                definite = false;
+            }
+            if (tp && tp->tp_as_mapping &&
+                tp->tp_as_mapping->mp_ass_subscript == _PyDict_StoreSubscript) 
{
+                if (definite) {
+                    ADD_OP(_NOP, 0, 0);
+                }
+                else {
+                    ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+                    sym_set_type(nos, tp);
+                }
+                PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
+                _Py_BloomFilter_Add(dependencies, tp);
             }
             break;
         }
@@ -1582,14 +1610,10 @@
                     /* Start of uop copied from bytecodes for constant 
evaluation */
                     PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st);
                     PyObject *dict = PyStackRef_AsPyObjectBorrow(dict_st);
-                    assert(PyAnyDict_CheckExact(dict));
+                    assert(Py_TYPE(dict)->tp_as_mapping->mp_subscript == 
_PyDict_Subscript);
                     STAT_INC(BINARY_OP, hit);
-                    PyObject *res_o;
-                    int rc = PyDict_GetItemRef(dict, sub, &res_o);
-                    if (rc == 0) {
-                        _PyErr_SetKeyError(sub);
-                    }
-                    if (rc <= 0) {
+                    PyObject *res_o = _PyDict_Subscript(dict, sub);
+                    if (res_o == NULL) {
                         JUMP_TO_LABEL(error);
                     }
                     res_stackref = PyStackRef_FromPyObjectSteal(res_o);
diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h
index 3163f45f4bb751..13996b30b9c03c 100644
--- a/Python/record_functions.c.h
+++ b/Python/record_functions.c.h
@@ -100,12 +100,13 @@ void _PyOpcode_RecordFunction_CODE(_PyInterpreterFrame 
*frame, _PyStackRef *stac
 
 #define _RECORD_TOS_TYPE_INDEX 1
 #define _RECORD_NOS_INDEX 2
-#define _RECORD_3OS_GEN_FUNC_INDEX 3
-#define _RECORD_TOS_INDEX 4
-#define _RECORD_NOS_GEN_FUNC_INDEX 5
-#define _RECORD_CALLABLE_INDEX 6
-#define _RECORD_CALLABLE_KW_INDEX 7
-#define _RECORD_4OS_INDEX 8
+#define _RECORD_NOS_TYPE_INDEX 3
+#define _RECORD_3OS_GEN_FUNC_INDEX 4
+#define _RECORD_TOS_INDEX 5
+#define _RECORD_NOS_GEN_FUNC_INDEX 6
+#define _RECORD_CALLABLE_INDEX 7
+#define _RECORD_CALLABLE_KW_INDEX 8
+#define _RECORD_4OS_INDEX 9
 
 const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = {
         [TO_BOOL_BOOL] = {1, {_RECORD_TOS_TYPE_INDEX}},
@@ -132,6 +133,9 @@ const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = {
         [BINARY_OP_SUBSCR_TUPLE_INT] = {2, {_RECORD_NOS_INDEX, 
_RECORD_TOS_TYPE_INDEX}},
         [BINARY_OP_SUBSCR_DICT] = {2, {_RECORD_NOS_INDEX, 
_RECORD_TOS_TYPE_INDEX}},
         [BINARY_OP_SUBSCR_GETITEM] = {2, {_RECORD_NOS_INDEX, 
_RECORD_TOS_TYPE_INDEX}},
+        [STORE_SUBSCR] = {1, {_RECORD_NOS_TYPE_INDEX}},
+        [STORE_SUBSCR_LIST_INT] = {1, {_RECORD_NOS_TYPE_INDEX}},
+        [STORE_SUBSCR_DICT] = {1, {_RECORD_NOS_TYPE_INDEX}},
         [SEND] = {1, {_RECORD_3OS_GEN_FUNC_INDEX}},
         [SEND_GEN] = {1, {_RECORD_3OS_GEN_FUNC_INDEX}},
         [STORE_ATTR] = {1, {_RECORD_TOS_TYPE_INDEX}},
@@ -197,7 +201,9 @@ const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = {
 
 const _PyOpcodeRecordSlotMap _PyOpcode_RecordSlotMaps[256] = {
         [TO_BOOL_ALWAYS_TRUE] = {1, 0, {0}},
+        [BINARY_OP_SUBSCR_DICT] = {1, 1, {0}},
         [BINARY_OP_SUBSCR_GETITEM] = {1, 0, {0}},
+        [STORE_SUBSCR_DICT] = {1, 0, {0}},
         [SEND_GEN] = {1, 0, {0}},
         [LOAD_SUPER_ATTR_METHOD] = {1, 0, {0}},
         [LOAD_ATTR_INSTANCE_VALUE] = {1, 1, {0}},
@@ -239,10 +245,11 @@ const _PyOpcodeRecordSlotMap 
_PyOpcode_RecordSlotMaps[256] = {
         [BINARY_OP] = {2, 2, {1, 0}},
 };
 
-const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[9] = {
+const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[10] = {
         [0] = NULL,
         [_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE,
         [_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS,
+        [_RECORD_NOS_TYPE_INDEX] = _PyOpcode_RecordFunction_NOS_TYPE,
         [_RECORD_3OS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_3OS_GEN_FUNC,
         [_RECORD_TOS_INDEX] = _PyOpcode_RecordFunction_TOS,
         [_RECORD_NOS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_NOS_GEN_FUNC,
diff --git a/Python/specialize.c b/Python/specialize.c
index 793bac58adf41a..b50728d4a2f3f3 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -1595,7 +1595,9 @@ _Py_Specialize_StoreSubscr(_PyStackRef container_st, 
_PyStackRef sub_st, _Py_COD
             return;
         }
     }
-    if (container_type == &PyDict_Type) {
+    if (container_type->tp_as_mapping != NULL &&
+        container_type->tp_as_mapping->mp_ass_subscript == 
_PyDict_StoreSubscript)
+    {
         specialize(instr, STORE_SUBSCR_DICT);
         return;
     }
@@ -2429,7 +2431,9 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef 
rhs_st, _Py_CODEUNIT *in
                     }
                 }
             }
-            if (PyAnyDict_CheckExact(lhs)) {
+            if (Py_TYPE(lhs)->tp_as_mapping != NULL &&
+                Py_TYPE(lhs)->tp_as_mapping->mp_subscript == _PyDict_Subscript)
+            {
                 specialize(instr, BINARY_OP_SUBSCR_DICT);
                 return;
             }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to