Repository navigation
Commit 8b9f2cf
Add STORE_SUBSCR_PY_DUNDER, which enters a Python `__setitem__` directly
rather than calling it through PyObject_SetItem, following the template
pythongh-143732 asks for.
Unlike BINARY_OP_SUBSCR_GETITEM, the frame for the dunder cannot simply be
pushed. _RETURN_VALUE is `(retval -- res)`, so a returning frame always
pushes exactly one value onto the caller: BINARY_OP_SUBSCR_GETITEM is
declared pops 2 / pushes 0 and the +1 arrives on return, netting -1 to match
generic BINARY_OP. STORE_SUBSCR must net -3, so a frame-pushing member would
pop 3, declare 0 pushed and gain +1 on return, netting -2. `__setitem__`
returns a None that nothing consumes.
So a shim frame (_Py_SetItemCleanup) is pushed underneath the `__setitem__`
frame, in the same way CALL_ALLOC_AND_ENTER_INIT uses _Py_InitCleanup for
`__init__`. The dunder returns into the shim, whose sole instruction
EXIT_SETITEM discards that value and pops the shim without pushing a result,
keeping the net stack effect at -3.
The guard and the frame push are deliberately a single uop. Splitting them,
mirroring _BINARY_OP_SUBSCR_CHECK_FUNC, puts the looked-up function on the
caller's value stack as a temporary; STORE_SUBSCR already occupies three
stack slots, so that extra slot overruns co_stacksize and trips
ASSERT_WITHIN_STACK_BOUNDS. BINARY_OP_SUBSCR_GETITEM survives it because
BINARY_OP occupies only two. The tier two abstract interpreter therefore
recovers the function from the container's type via _spec_cache.setitem,
exactly as _BINARY_OP_SUBSCR_CHECK_FUNC does, rather than from a stack
symbol.
Tier two support is included: EXIT_SETITEM reuses _GUARD_IP_RETURN_VALUE and
_GUARD_CODE_VERSION_RETURN_VALUE because its post-pop state matches
_RETURN_VALUE's, the shim predicate in optimizer_analysis.c is generalised to
cover both trampolines, and _Py_SetItemCleanup is added to
has_space_for_executor() so insert_executor() cannot write ENTER_EXECUTOR
into a statically allocated const code object. Without this, a hot loop
containing `x[k] = v` would end its trace at the store, which plain
STORE_SUBSCR did not.
The function is cached on the heap type (_spec_cache.setitem, mirroring
_spec_cache.getitem) rather than in the inline cache, so STORE_SUBSCR's cache
size is unchanged. The cost is paid in heap type size instead: the pointers
in _specialization_cache are grouped ahead of the version fields so the two
uint32_t versions share one word of padding, which holds the struct at 32
bytes rather than 40, i.e. 8 bytes per heap type rather than 16.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 24e5a55 commit 8b9f2cf
26 files changed
Lines changed: 1123 additions & 272 deletions
File tree
- Include
- cpython
- internal
- Lib
- test
- Misc/NEWS.d/next/Core_and_Builtins
- Modules/_testinternalcapi
- Objects
- Programs
- Python
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
269 | 276 | | |
270 | | - | |
| 277 | + | |
271 | 278 | | |
| 279 | + | |
| 280 | + | |
272 | 281 | | |
273 | 282 | | |
274 | 283 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
549 | 549 | | |
550 | 550 | | |
551 | 551 | | |
| 552 | + | |
552 | 553 | | |
553 | 554 | | |
554 | 555 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
303 | 303 | | |
304 | 304 | | |
305 | 305 | | |
| 306 | + | |
306 | 307 | | |
307 | 308 | | |
308 | 309 | | |
| |||
312 | 313 | | |
313 | 314 | | |
314 | 315 | | |
315 | | - | |
| 316 | + | |
316 | 317 | | |
317 | 318 | | |
318 | 319 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments