8000 bpo-45829: Specialize BINARY_SUBSCR for __getitem__ implemented in Py… · python/cpython@21fa7a3 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 21fa7a3

Browse files
authored
bpo-45829: Specialize BINARY_SUBSCR for __getitem__ implemented in Python. (GH-29592)
1 parent 5275e59 commit 21fa7a3

File tree

7 files changed

+145
-89
lines changed

7 files changed

+145
-89
lines changed

Include/internal/pycore_code.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ typedef struct {
1717
uint8_t original_oparg;
1818
uint8_t counter;
1919
uint16_t index;
20+
uint32_t version;
2021
} _PyAdaptiveEntry;
2122

2223

@@ -266,7 +267,7 @@ int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name
266267
int _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
267268
int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
268269
int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
269-
int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr);
270+
int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache);
270271
int _Py_Specialize_CallFunction(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins);
271272
void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
272273
SpecializedCacheEntry *cache);

Include/opcode.h

Lines changed: 33 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ def jabs_op(name, op):
234234
"BINARY_OP_SUBTRACT_INT",
235235
"BINARY_OP_SUBTRACT_FLOAT",
236236
"BINARY_SUBSCR_ADAPTIVE",
237+
"BINARY_SUBSCR_GETITEM",
237238
"BINARY_SUBSCR_LIST_INT",
238239
"BINARY_SUBSCR_TUPLE_INT",
239240
"BINARY_SUBSCR_DICT",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Specialize :opcode:`BINARY_SUBSCR` for classes with a ``__getitem__`` method
2+
implemented in Python

Python/ceval.c

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,21 +2140,21 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
21402140
}
21412141

21422142
TARGET(BINARY_SUBSCR_ADAPTIVE) {
2143-
if (oparg == 0) {
2143+
SpecializedCacheEntry *cache = GET_CACHE();
2144+
if (cache->adaptive.counter == 0) {
21442145
PyObject *sub = TOP();
21452146
PyObject *container = SECOND();
21462147
next_instr--;
2147-
if (_Py_Specialize_BinarySubscr(container, sub, next_instr) < 0) {
2148+
if (_Py_Specialize_BinarySubscr(container, sub, next_instr, cache) < 0) {
21482149
goto error;
21492150
}
21502151
DISPATCH();
21512152
}
21522153
else {
21532154
STAT_INC(BINARY_SUBSCR, deferred);
2154-
// oparg is the adaptive cache counter
2155-
UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
2156-
assert(_Py_OPCODE(next_instr[-1]) == BINARY_SUBSCR_ADAPTIVE);
2157-
assert(_Py_OPARG(next_instr[-1]) == oparg - 1);
2155+
cache->adaptive.counter--;
2156+
assert(cache->adaptive.original_oparg == 0);
2157+
/* No need to set oparg here; it isn't used by BINARY_SUBSCR */
21582158
STAT_DEC(BINARY_SUBSCR, unquickened);
21592159
JUMP_TO_INSTRUCTION(BINARY_SUBSCR);
21602160
}
@@ -2223,6 +2223,37 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
22232223
DISPATCH();
22242224
}
22252225

2226+
TARGET(BINARY_SUBSCR_GETITEM) {
2227+
PyObject *sub = TOP();
2228+
PyObject *container = SECOND();
2229+
SpecializedCacheEntry *caches = GET_CACHE();
2230+
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
2231+
_PyObjectCache *cache1 = &caches[-1].obj;
2232+
PyFunctionObject *getitem = (PyFunctionObject *)cache1->obj;
2233+
DEOPT_IF(Py_TYPE(container)->tp_version_tag != cache0->version, BINARY_SUBSCR);
2234+
DEOPT_IF(getitem->func_version != cache0->index, BINARY_SUBSCR);
2235+
PyCodeObject *code = (PyCodeObject *)getitem->func_code;
2236+
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
2237+
assert(code->co_argcount == 2);
2238+
InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
2239+
if (new_frame == NULL) {
2240+
goto error;
2241+
}
2242+
_PyFrame_InitializeSpecials(new_frame, PyFunction_AS_FRAME_CONSTRUCTOR(getitem),
2243+
NULL, code->co_nlocalsplus);
2244+
STACK_SHRINK(2);
2245+
new_frame->localsplus[0] = container;
2246+
new_frame->localsplus[1] = sub;
2247+
for (int i = 2; i < code->co_nlocalsplus; i++) {
2248+
new_frame->localsplus[i] = NULL;
2249+
}
2250+
_PyFrame_SetStackPointer(frame, stack_pointer);
2251+
new_frame->previous = frame;
2252+
frame = cframe.current_frame = new_frame;
2253+
new_frame->depth = frame->depth + 1;
2254+
goto start_frame;
2255+
}
2256+
22262257
TARGET(LIST_APPEND) {
22272258
PyObject *v = POP();
22282259
PyObject *list = PEEK(oparg);
@@ -4878,29 +4909,13 @@ opname ## _miss: \
48784909
JUMP_TO_INSTRUCTION(opname); \
48794910
}
48804911

4881-
#define MISS_WITH_OPARG_COUNTER(opname) \
4882-
opname ## _miss: \
4883-
{ \
4884-
STAT_INC(opname, miss); \
4885-
uint8_t oparg = _Py_OPARG(next_instr[-1])-1; \
4886-
UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \
4887-
assert(_Py_OPARG(next_instr[-1]) == oparg); \
4888-
if (oparg == 0) /* too many cache misses */ { \
4889-
oparg = ADAPTIVE_CACHE_BACKOFF; \
4890-
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
4891-
STAT_INC(opname, deopt); \
4892-
} \
4893-
STAT_DEC(opname, unquickened); \
4894-
JUMP_TO_INSTRUCTION(opname); \
4895-
}
4896-
48974912
MISS_WITH_CACHE(LOAD_ATTR)
48984913
MISS_WITH_CACHE(STORE_ATTR)
48994914
MISS_WITH_CACHE(LOAD_GLOBAL)
49004915
MISS_WITH_CACHE(LOAD_METHOD)
49014916
MISS_WITH_CACHE(CALL_FUNCTION)
49024917
MISS_WITH_CACHE(BINARY_OP)
4903-
MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR)
4918+
MISS_WITH_CACHE(BINARY_SUBSCR)
49044919

49054920
binary_subscr_dict_error:
49064921
{

Python/opcode_targets.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0