Repository navigation
Commit 7817364
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 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.
Tier 1 only; tier 2 / JIT support is left for a follow-up.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 24e5a55 commit 7817364
19 files changed
Lines changed: 814 additions & 266 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 | | |
| |||
0 commit comments