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]