https://github.com/python/cpython/commit/b98c065756ea336707c30885831e4afcb85aac84
commit: b98c065756ea336707c30885831e4afcb85aac84
branch: main
author: Hai Zhu <[email protected]>
committer: markshannon <[email protected]>
date: 2026-09-30T14:18:13+01:00
summary:
gh-158380: Fix the stack operand used by JIT dict access guards (GH-158381)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-09-29-07-28-20.gh-issue-158380.F0J0PO.rst
M Include/internal/pycore_uop_ids.h
M Include/internal/pycore_uop_metadata.h
M Lib/test/test_capi/test_opt.py
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
diff --git a/Include/internal/pycore_uop_ids.h
b/Include/internal/pycore_uop_ids.h
index 625c33a6640b85..840a32f0e4481f 100644
--- a/Include/internal/pycore_uop_ids.h
+++ b/Include/internal/pycore_uop_ids.h
@@ -184,6 +184,7 @@ enum {
_GUARD_NOS_NULL,
_GUARD_NOS_OVERFLOWED,
_GUARD_NOS_TUPLE,
+ _GUARD_NOS_TYPE,
_GUARD_NOS_TYPE_VERSION,
_GUARD_NOS_UNICODE,
_GUARD_NOT_EXHAUSTED_LIST,
@@ -207,7 +208,6 @@ enum {
_GUARD_TOS_TUPLE,
_GUARD_TOS_UNICODE,
_GUARD_TYPE,
- _GUARD_TYPE_ITER,
_GUARD_TYPE_VERSION,
_GUARD_TYPE_VERSION_LOCKED,
_HANDLE_PENDING_AND_DEOPT,
@@ -891,6 +891,10 @@ enum {
_GUARD_NOS_TUPLE_r12,
_GUARD_NOS_TUPLE_r22,
_GUARD_NOS_TUPLE_r33,
+ _GUARD_NOS_TYPE_r02,
+ _GUARD_NOS_TYPE_r12,
+ _GUARD_NOS_TYPE_r22,
+ _GUARD_NOS_TYPE_r33,
_GUARD_NOS_TYPE_VERSION_r02,
_GUARD_NOS_TYPE_VERSION_r12,
_GUARD_NOS_TYPE_VERSION_r22,
@@ -983,10 +987,6 @@ enum {
_GUARD_TYPE_r11,
_GUARD_TYPE_r22,
_GUARD_TYPE_r33,
- _GUARD_TYPE_ITER_r02,
- _GUARD_TYPE_ITER_r12,
- _GUARD_TYPE_ITER_r22,
- _GUARD_TYPE_ITER_r33,
_GUARD_TYPE_VERSION_r01,
_GUARD_TYPE_VERSION_r11,
_GUARD_TYPE_VERSION_r22,
diff --git a/Include/internal/pycore_uop_metadata.h
b/Include/internal/pycore_uop_metadata.h
index f464effe23bc0b..1c440fe9f1e978 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -265,7 +265,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_PUSH_TAGGED_ZERO] = 0,
[_GET_ITER_TRAD] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_FOR_ITER_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG |
HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
- [_GUARD_TYPE_ITER] = HAS_EXIT_FLAG,
+ [_GUARD_NOS_TYPE] = HAS_EXIT_FLAG,
[_ITER_NEXT_INLINE] = HAS_EXIT_FLAG | HAS_ERROR_FLAG |
HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_GUARD_NOS_ITER_VIRTUAL] = HAS_EXIT_FLAG,
[_GUARD_TOS_NOT_NULL] = HAS_EXIT_FLAG,
@@ -2515,13 +2515,13 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ -1, -1, -1 },
},
},
- [_GUARD_TYPE_ITER] = {
+ [_GUARD_NOS_TYPE] = {
.best = { 0, 1, 2, 3 },
.entries = {
- { 2, 0, _GUARD_TYPE_ITER_r02 },
- { 2, 1, _GUARD_TYPE_ITER_r12 },
- { 2, 2, _GUARD_TYPE_ITER_r22 },
- { 3, 3, _GUARD_TYPE_ITER_r33 },
+ { 2, 0, _GUARD_NOS_TYPE_r02 },
+ { 2, 1, _GUARD_NOS_TYPE_r12 },
+ { 2, 2, _GUARD_NOS_TYPE_r22 },
+ { 3, 3, _GUARD_NOS_TYPE_r33 },
},
},
[_ITER_NEXT_INLINE] = {
@@ -4446,10 +4446,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_PUSH_TAGGED_ZERO_r23] = _PUSH_TAGGED_ZERO,
[_GET_ITER_TRAD_r12] = _GET_ITER_TRAD,
[_FOR_ITER_TIER_TWO_r23] = _FOR_ITER_TIER_TWO,
- [_GUARD_TYPE_ITER_r02] = _GUARD_TYPE_ITER,
- [_GUARD_TYPE_ITER_r12] = _GUARD_TYPE_ITER,
- [_GUARD_TYPE_ITER_r22] = _GUARD_TYPE_ITER,
- [_GUARD_TYPE_ITER_r33] = _GUARD_TYPE_ITER,
+ [_GUARD_NOS_TYPE_r02] = _GUARD_NOS_TYPE,
+ [_GUARD_NOS_TYPE_r12] = _GUARD_NOS_TYPE,
+ [_GUARD_NOS_TYPE_r22] = _GUARD_NOS_TYPE,
+ [_GUARD_NOS_TYPE_r33] = _GUARD_NOS_TYPE,
[_ITER_NEXT_INLINE_r23] = _ITER_NEXT_INLINE,
[_GUARD_NOS_ITER_VIRTUAL_r02] = _GUARD_NOS_ITER_VIRTUAL,
[_GUARD_NOS_ITER_VIRTUAL_r12] = _GUARD_NOS_ITER_VIRTUAL,
@@ -5475,6 +5475,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1]
= {
[_GUARD_NOS_TUPLE_r12] = "_GUARD_NOS_TUPLE_r12",
[_GUARD_NOS_TUPLE_r22] = "_GUARD_NOS_TUPLE_r22",
[_GUARD_NOS_TUPLE_r33] = "_GUARD_NOS_TUPLE_r33",
+ [_GUARD_NOS_TYPE] = "_GUARD_NOS_TYPE",
+ [_GUARD_NOS_TYPE_r02] = "_GUARD_NOS_TYPE_r02",
+ [_GUARD_NOS_TYPE_r12] = "_GUARD_NOS_TYPE_r12",
+ [_GUARD_NOS_TYPE_r22] = "_GUARD_NOS_TYPE_r22",
+ [_GUARD_NOS_TYPE_r33] = "_GUARD_NOS_TYPE_r33",
[_GUARD_NOS_TYPE_VERSION] = "_GUARD_NOS_TYPE_VERSION",
[_GUARD_NOS_TYPE_VERSION_r02] = "_GUARD_NOS_TYPE_VERSION_r02",
[_GUARD_NOS_TYPE_VERSION_r12] = "_GUARD_NOS_TYPE_VERSION_r12",
@@ -5590,11 +5595,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1]
= {
[_GUARD_TYPE_r11] = "_GUARD_TYPE_r11",
[_GUARD_TYPE_r22] = "_GUARD_TYPE_r22",
[_GUARD_TYPE_r33] = "_GUARD_TYPE_r33",
- [_GUARD_TYPE_ITER] = "_GUARD_TYPE_ITER",
- [_GUARD_TYPE_ITER_r02] = "_GUARD_TYPE_ITER_r02",
- [_GUARD_TYPE_ITER_r12] = "_GUARD_TYPE_ITER_r12",
- [_GUARD_TYPE_ITER_r22] = "_GUARD_TYPE_ITER_r22",
- [_GUARD_TYPE_ITER_r33] = "_GUARD_TYPE_ITER_r33",
[_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION",
[_GUARD_TYPE_VERSION_r01] = "_GUARD_TYPE_VERSION_r01",
[_GUARD_TYPE_VERSION_r11] = "_GUARD_TYPE_VERSION_r11",
@@ -6626,7 +6626,7 @@ int _PyUop_num_popped(int opcode, int oparg)
return 1;
case _FOR_ITER_TIER_TWO:
return 0;
- case _GUARD_TYPE_ITER:
+ case _GUARD_NOS_TYPE:
return 0;
case _ITER_NEXT_INLINE:
return 0;
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index ca0545dba264f2..31440c8e609213 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -2445,7 +2445,18 @@ def f(n):
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)
+ self.assertEqual(uops.count("_GUARD_NOS_TYPE"), 1)
+
+ def test_dict_subscr_probable_type(self):
+ def f(d):
+ for _ in range(TIER2_THRESHOLD):
+ value = d["key"]
+ return value
+
+ res, ex = self._run_with_optimizer(f, {"key": 1})
+ self.assertEqual(res, 1)
+ self.assertIsNotNone(ex)
+ self.assertIn("_GUARD_NOS_TYPE", get_opnames(ex))
def test_dict_subclass_subscr_with_override(self):
class MyDict(dict):
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-29-07-28-20.gh-issue-158380.F0J0PO.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-29-07-28-20.gh-issue-158380.F0J0PO.rst
new file mode 100644
index 00000000000000..2b3f1d9301e733
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-29-07-28-20.gh-issue-158380.F0J0PO.rst
@@ -0,0 +1 @@
+Fix incorrect type guards for ``dict`` reads and writes in the experimental
JIT.
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index fdfd5a0e609046..2ca52766c110b9 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -3846,9 +3846,9 @@ dummy_func(
next = item;
}
- tier2 op(_GUARD_TYPE_ITER, (expected_type/4, iter, null_or_index --
iter, null_or_index)) {
- PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
- EXIT_IF(Py_TYPE(iter_o) != (PyTypeObject *)expected_type);
+ tier2 op(_GUARD_NOS_TYPE, (expected_type/4, nos, unused -- nos,
unused)) {
+ PyObject *nos_o = PyStackRef_AsPyObjectBorrow(nos);
+ EXIT_IF(Py_TYPE(nos_o) != (PyTypeObject *)expected_type);
}
tier2 op(_ITER_NEXT_INLINE, (iternext_fn/4, iter, null_or_index --
iter, null_or_index, next)) {
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index e3dc2e781a3beb..0045296f1bc868 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -14816,20 +14816,20 @@
break;
}
- case _GUARD_TYPE_ITER_r02: {
+ case _GUARD_NOS_TYPE_r02: {
CHECK_CURRENT_CACHED_VALUES(0);
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
- _PyStackRef iter;
- iter = stack_pointer[-2];
+ _PyStackRef nos;
+ nos = stack_pointer[-2];
PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64();
- PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
- if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) {
+ PyObject *nos_o = PyStackRef_AsPyObjectBorrow(nos);
+ if (Py_TYPE(nos_o) != (PyTypeObject *)expected_type) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = stack_pointer[-1];
- _tos_cache0 = iter;
+ _tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@@ -14837,22 +14837,22 @@
break;
}
- case _GUARD_TYPE_ITER_r12: {
+ case _GUARD_NOS_TYPE_r12: {
CHECK_CURRENT_CACHED_VALUES(1);
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
- _PyStackRef iter;
+ _PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
- iter = stack_pointer[-1];
+ nos = stack_pointer[-1];
PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64();
- PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
- if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) {
+ PyObject *nos_o = PyStackRef_AsPyObjectBorrow(nos);
+ if (Py_TYPE(nos_o) != (PyTypeObject *)expected_type) {
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 = iter;
+ _tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@@ -14860,49 +14860,49 @@
break;
}
- case _GUARD_TYPE_ITER_r22: {
+ case _GUARD_NOS_TYPE_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
- _PyStackRef iter;
+ _PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
- iter = _stack_item_0;
+ nos = _stack_item_0;
PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64();
- PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
- if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) {
+ PyObject *nos_o = PyStackRef_AsPyObjectBorrow(nos);
+ if (Py_TYPE(nos_o) != (PyTypeObject *)expected_type) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = _stack_item_1;
- _tos_cache0 = iter;
+ _tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = _stack_item_1;
- _tos_cache0 = iter;
+ _tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
break;
}
- case _GUARD_TYPE_ITER_r33: {
+ case _GUARD_NOS_TYPE_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
- _PyStackRef iter;
+ _PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
- iter = _stack_item_1;
+ nos = _stack_item_1;
PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64();
- PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
- if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) {
+ PyObject *nos_o = PyStackRef_AsPyObjectBorrow(nos);
+ if (Py_TYPE(nos_o) != (PyTypeObject *)expected_type) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = _stack_item_2;
- _tos_cache1 = iter;
+ _tos_cache1 = nos;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_2;
- _tos_cache1 = iter;
+ _tos_cache1 = nos;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index 5246e50633461b..54b01e1ffbd322 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -1472,7 +1472,7 @@ dummy_func(void) {
sym_set_type(iter, type);
assert((this_instr - 1)->opcode == _RECORD_NOS_TYPE);
int32_t orig_target = (this_instr - 1)->target;
- ADD_OP(_GUARD_TYPE_ITER, 0, (uintptr_t)type);
+ ADD_OP(_GUARD_NOS_TYPE, 0, (uintptr_t)type);
uop_buffer_last(&ctx->out_buffer)->target = orig_target;
}
ADD_OP(_ITER_NEXT_INLINE, 0, (uintptr_t)type->tp_iternext);
@@ -2216,7 +2216,7 @@ dummy_func(void) {
ADD_OP(_NOP, 0, 0);
}
else {
- ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+ ADD_OP(_GUARD_NOS_TYPE, 0, (uintptr_t)tp);
sym_set_type(nos, tp);
}
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
@@ -2237,7 +2237,7 @@ dummy_func(void) {
ADD_OP(_NOP, 0, 0);
}
else {
- ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+ ADD_OP(_GUARD_NOS_TYPE, 0, (uintptr_t)tp);
sym_set_type(nos, tp);
}
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 21f275f27cafe0..73a86bfe86dacd 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -1500,7 +1500,7 @@
ADD_OP(_NOP, 0, 0);
}
else {
- ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+ ADD_OP(_GUARD_NOS_TYPE, 0, (uintptr_t)tp);
sym_set_type(nos, tp);
}
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
@@ -1524,7 +1524,7 @@
ADD_OP(_NOP, 0, 0);
}
else {
- ADD_OP(_GUARD_TYPE, 0, (uintptr_t)tp);
+ ADD_OP(_GUARD_NOS_TYPE, 0, (uintptr_t)tp);
sym_set_type(nos, tp);
}
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)tp);
@@ -3705,7 +3705,7 @@
sym_set_type(iter, type);
assert((this_instr - 1)->opcode == _RECORD_NOS_TYPE);
int32_t orig_target = (this_instr - 1)->target;
- ADD_OP(_GUARD_TYPE_ITER, 0, (uintptr_t)type);
+ ADD_OP(_GUARD_NOS_TYPE, 0, (uintptr_t)type);
uop_buffer_last(&ctx->out_buffer)->target = orig_target;
}
ADD_OP(_ITER_NEXT_INLINE, 0, (uintptr_t)type->tp_iternext);
@@ -3718,7 +3718,7 @@
break;
}
- case _GUARD_TYPE_ITER: {
+ case _GUARD_NOS_TYPE: {
break;
}
_______________________________________________
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]