From 4cbbeeeeaa08bf3cd587e99f25eafcc30459c3b2 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 16 Nov 2021 14:22:06 +0000 Subject: [PATCH 1/6] Experimental specialization of BINARY_SUBSCR for __getitem__ implemented in Python. --- Include/internal/pycore_code.h | 3 +- Include/opcode.h | 65 +++++++++++++------------- Lib/opcode.py | 1 + Python/ceval.c | 45 +++++++++++++++--- Python/opcode_targets.h | 14 +++--- Python/specialize.c | 84 ++++++++++++++++++++++++---------- 6 files changed, 140 insertions(+), 72 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 7fe9e74b21cfeb..6563f7b87b3601 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -17,6 +17,7 @@ typedef struct { uint8_t original_oparg; uint8_t counter; uint16_t index; + uint32_t version; } _PyAdaptiveEntry; @@ -266,7 +267,7 @@ int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name int _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); -int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr); +int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); int _Py_Specialize_CallFunction(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins); void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); diff --git a/Include/opcode.h b/Include/opcode.h index c7354de9a0687c..7097d1efc31862 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -119,38 +119,39 @@ extern "C" { #define BINARY_OP_MULTIPLY_INT 17 #define BINARY_OP_MULTIPLY_FLOAT 18 #define BINARY_SUBSCR_ADAPTIVE 19 -#define BINARY_SUBSCR_LIST_INT 20 -#define BINARY_SUBSCR_TUPLE_INT 21 -#define BINARY_SUBSCR_DICT 22 -#define CALL_FUNCTION_ADAPTIVE 23 -#define CALL_FUNCTION_BUILTIN_O 24 -#define CALL_FUNCTION_BUILTIN_FAST 26 -#define CALL_FUNCTION_LEN 27 -#define CALL_FUNCTION_ISINSTANCE 28 -#define CALL_FUNCTION_PY_SIMPLE 29 -#define JUMP_ABSOLUTE_QUICK 34 -#define LOAD_ATTR_ADAPTIVE 36 -#define LOAD_ATTR_INSTANCE_VALUE 38 -#define LOAD_ATTR_WITH_HINT 39 -#define LOAD_ATTR_SLOT 40 -#define LOAD_ATTR_MODULE 41 -#define LOAD_GLOBAL_ADAPTIVE 42 -#define LOAD_GLOBAL_MODULE 43 -#define LOAD_GLOBAL_BUILTIN 44 -#define LOAD_METHOD_ADAPTIVE 45 -#define LOAD_METHOD_CACHED 46 -#define LOAD_METHOD_CLASS 47 -#define LOAD_METHOD_MODULE 48 -#define LOAD_METHOD_NO_DICT 55 -#define STORE_ATTR_ADAPTIVE 56 -#define STORE_ATTR_INSTANCE_VALUE 57 -#define STORE_ATTR_SLOT 58 -#define STORE_ATTR_WITH_HINT 59 -#define LOAD_FAST__LOAD_FAST 62 -#define STORE_FAST__LOAD_FAST 63 -#define LOAD_FAST__LOAD_CONST 64 -#define LOAD_CONST__LOAD_FAST 65 -#define STORE_FAST__STORE_FAST 66 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define BINARY_SUBSCR_DICT 23 +#define CALL_FUNCTION_ADAPTIVE 24 +#define CALL_FUNCTION_BUILTIN_O 26 +#define CALL_FUNCTION_BUILTIN_FAST 27 +#define CALL_FUNCTION_LEN 28 +#define CALL_FUNCTION_ISINSTANCE 29 +#define CALL_FUNCTION_PY_SIMPLE 34 +#define JUMP_ABSOLUTE_QUICK 36 +#define LOAD_ATTR_ADAPTIVE 38 +#define LOAD_ATTR_INSTANCE_VALUE 39 +#define LOAD_ATTR_WITH_HINT 40 +#define LOAD_ATTR_SLOT 41 +#define LOAD_ATTR_MODULE 42 +#define LOAD_GLOBAL_ADAPTIVE 43 +#define LOAD_GLOBAL_MODULE 44 +#define LOAD_GLOBAL_BUILTIN 45 +#define LOAD_METHOD_ADAPTIVE 46 +#define LOAD_METHOD_CACHED 47 +#define LOAD_METHOD_CLASS 48 +#define LOAD_METHOD_MODULE 55 +#define LOAD_METHOD_NO_DICT 56 +#define STORE_ATTR_ADAPTIVE 57 +#define STORE_ATTR_INSTANCE_VALUE 58 +#define STORE_ATTR_SLOT 59 +#define STORE_ATTR_WITH_HINT 62 +#define LOAD_FAST__LOAD_FAST 63 +#define STORE_FAST__LOAD_FAST 64 +#define LOAD_FAST__LOAD_CONST 65 +#define LOAD_CONST__LOAD_FAST 66 +#define STORE_FAST__STORE_FAST 67 #define DO_TRACING 255 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { diff --git a/Lib/opcode.py b/Lib/opcode.py index 940e169d5597d7..93631e4e588919 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -232,6 +232,7 @@ def jabs_op(name, op): "BINARY_OP_MULTIPLY_INT", "BINARY_OP_MULTIPLY_FLOAT", "BINARY_SUBSCR_ADAPTIVE", + "BINARY_SUBSCR_GETITEM", "BINARY_SUBSCR_LIST_INT", "BINARY_SUBSCR_TUPLE_INT", "BINARY_SUBSCR_DICT", diff --git a/Python/ceval.c b/Python/ceval.c index bf4e22dc6fec46..14071294da0359 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2075,21 +2075,21 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr } TARGET(BINARY_SUBSCR_ADAPTIVE) { - if (oparg == 0) { + SpecializedCacheEntry *cache = GET_CACHE(); + if (cache->adaptive.counter == 0) { PyObject *sub = TOP(); PyObject *container = SECOND(); next_instr--; - if (_Py_Specialize_BinarySubscr(container, sub, next_instr) < 0) { + if (_Py_Specialize_BinarySubscr(container, sub, next_instr, cache) < 0) { goto error; } DISPATCH(); } else { STAT_INC(BINARY_SUBSCR, deferred); - // oparg is the adaptive cache counter - UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1); - assert(_Py_OPCODE(next_instr[-1]) == BINARY_SUBSCR_ADAPTIVE); - assert(_Py_OPARG(next_instr[-1]) == oparg - 1); + cache->adaptive.counter--; + assert(cache->adaptive.original_oparg == 0); + oparg = 0; STAT_DEC(BINARY_SUBSCR, unquickened); JUMP_TO_INSTRUCTION(BINARY_SUBSCR); } @@ -2158,6 +2158,37 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr DISPATCH(); } + TARGET(BINARY_SUBSCR_GETITEM) { + PyObject *sub = TOP(); + PyObject *container = SECOND(); + SpecializedCacheEntry *caches = GET_CACHE(); + _PyAdaptiveEntry *cache0 = &caches[0].adaptive; + _PyObjectCache *cache1 = &caches[-1].obj; + PyFunctionObject *getitem = (PyFunctionObject *)cache1->obj; + DEOPT_IF(getitem->func_version != cache0->index, BINARY_SUBSCR); + DEOPT_IF(Py_TYPE(container)->tp_version_tag != cache0->version, BINARY_SUBSCR); + PyCodeObject *code = (PyCodeObject *)getitem->func_code; + size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; + assert(code->co_argcount == 2); + InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size); + if (new_frame == NULL) { + goto error; + } + _PyFrame_InitializeSpecials(new_frame, PyFunction_AS_FRAME_CONSTRUCTOR(getitem), + NULL, code->co_nlocalsplus); + STACK_SHRINK(2); + new_frame->localsplus[0] = container; + new_frame->localsplus[1] = sub; + for (int i = 2; i < code->co_nlocalsplus; i++) { + new_frame->localsplus[i] = NULL; + } + _PyFrame_SetStackPointer(frame, stack_pointer); + new_frame->previous = frame; + frame = cframe.current_frame = new_frame; + new_frame->depth = frame->depth + 1; + goto start_frame; + } + TARGET(LIST_APPEND) { PyObject *v = POP(); PyObject *list = PEEK(oparg); @@ -4914,7 +4945,7 @@ MISS_WITH_CACHE(LOAD_GLOBAL) MISS_WITH_CACHE(LOAD_METHOD) MISS_WITH_CACHE(CALL_FUNCTION) MISS_WITH_CACHE(BINARY_OP) -MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR) +MISS_WITH_CACHE(BINARY_SUBSCR) binary_subscr_dict_error: { diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index a57617e022e1db..6a1bfa26866dd9 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -19,24 +19,25 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_BINARY_SUBSCR_ADAPTIVE, + &&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_CALL_FUNCTION_ADAPTIVE, - &&TARGET_CALL_FUNCTION_BUILTIN_O, &&TARGET_BINARY_SUBSCR, + &&TARGET_CALL_FUNCTION_BUILTIN_O, &&TARGET_CALL_FUNCTION_BUILTIN_FAST, &&TARGET_CALL_FUNCTION_LEN, &&TARGET_CALL_FUNCTION_ISINSTANCE, - &&TARGET_CALL_FUNCTION_PY_SIMPLE, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_JUMP_ABSOLUTE_QUICK, + &&TARGET_CALL_FUNCTION_PY_SIMPLE, &&TARGET_PUSH_EXC_INFO, - &&TARGET_LOAD_ATTR_ADAPTIVE, + &&TARGET_JUMP_ABSOLUTE_QUICK, &&TARGET_POP_EXCEPT_AND_RERAISE, + &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_SLOT, @@ -47,26 +48,25 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_LOAD_METHOD_CACHED, &&TARGET_LOAD_METHOD_CLASS, - &&TARGET_LOAD_METHOD_MODULE, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, + &&TARGET_LOAD_METHOD_MODULE, &&TARGET_LOAD_METHOD_NO_DICT, &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, - &&_unknown_opcode, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, diff --git a/Python/specialize.c b/Python/specialize.c index cfc21bf70ad6be..d7c8a318d2db88 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -243,7 +243,7 @@ static uint8_t cache_requirements[256] = { [LOAD_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */ [LOAD_GLOBAL] = 2, /* _PyAdaptiveEntry and _PyLoadGlobalCache */ [LOAD_METHOD] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache */ - [BINARY_SUBSCR] = 0, + [BINARY_SUBSCR] = 2, /* _PyAdaptiveEntry, _PyObjectCache */ [CALL_FUNCTION] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */ [STORE_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */ [BINARY_OP] = 1, // _PyAdaptiveEntry @@ -1100,7 +1100,7 @@ _Py_Specialize_LoadGlobal( #if COLLECT_SPECIALIZATION_STATS_DETAILED static int -binary_subscr_faiL_kind(PyTypeObject *container_type, PyObject *sub) +binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) { if (container_type == &PyUnicode_Type) { if (PyLong_CheckExact(sub)) { @@ -1138,14 +1138,35 @@ binary_subscr_faiL_kind(PyTypeObject *container_type, PyObject *sub) } #endif +_Py_IDENTIFIER(__getitem__); + +int function_kind(PyCodeObject *code) { + int flags = code->co_flags; + if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { + return SPEC_FAIL_GENERATOR; + return -1; + } + if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) { + return SPEC_FAIL_COMPLEX_PARAMETERS; + } + if ((flags & CO_OPTIMIZED) == 0) { + return SPEC_FAIL_CO_NOT_OPTIMIZED; + } + if (code->co_nfreevars) { + return SPEC_FAIL_FREE_VARS; + } + return 0; +} + int _Py_Specialize_BinarySubscr( - PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) + PyObject *container, PyObject *sub, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache) { + _PyAdaptiveEntry *cache0 = &cache->adaptive; PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_LIST_INT, initial_counter_value()); + *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_LIST_INT, _Py_OPARG(*instr)); goto success; } SPECIALIZATION_FAIL(BINARY_SUBSCR, @@ -1154,7 +1175,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_TUPLE_INT, initial_counter_value()); + *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_TUPLE_INT, _Py_OPARG(*instr)); goto success; } SPECIALIZATION_FAIL(BINARY_SUBSCR, @@ -1162,20 +1183,46 @@ _Py_Specialize_BinarySubscr( goto fail; } if (container_type == &PyDict_Type) { - *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_DICT, initial_counter_value()); + *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_DICT, _Py_OPARG(*instr)); + goto success; + } + PyTypeObject *cls = Py_TYPE(container); + PyObject *descriptor = _PyType_LookupId(cls, &PyId___getitem__); + if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { + PyFunctionObject *func = (PyFunctionObject *)descriptor; + PyCodeObject *code = (PyCodeObject *)func->func_code; + int kind = function_kind(code); + if (kind) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, kind); + goto fail; + } + if (code->co_argcount != 2) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); + goto fail; + } + assert(cls->tp_version_tag != 0); + cache0->version = cls->tp_version_tag; + int version = _PyFunction_GetVersionForCurrentState(func); + if (version == 0) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); + goto fail; + } + cache0->index = version; + cache[-1].obj.obj = descriptor; + *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_GETITEM, _Py_OPARG(*instr)); goto success; } SPECIALIZATION_FAIL(BINARY_SUBSCR, - binary_subscr_faiL_kind(container_type, sub)); - goto fail; + binary_subscr_fail_kind(container_type, sub)); fail: STAT_INC(BINARY_SUBSCR, specialization_failure); assert(!PyErr_Occurred()); - *instr = _Py_MAKECODEUNIT(_Py_OPCODE(*instr), ADAPTIVE_CACHE_BACKOFF); + cache_backoff(cache0); return 0; success: STAT_INC(BINARY_SUBSCR, specialization_success); assert(!PyErr_Occurred()); + cache0->counter = initial_counter_value(); return 0; } @@ -1194,23 +1241,10 @@ specialize_py_call( int nargs, SpecializedCacheEntry *cache) { _PyCallCache *cache1 = &cache[-1].call; - /* Exclude generator or coroutines for now */ PyCodeObject *code = (PyCodeObject *)func->func_code; - int flags = code->co_flags; - if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_GENERATOR); - return -1; - } - if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) { - SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_COMPLEX_PARAMETERS); - return -1; - } - if ((flags & CO_OPTIMIZED) == 0) { - SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_CO_NOT_OPTIMIZED); - return -1; - } - if (code->co_nfreevars) { - SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_FREE_VARS); + int kind = function_kind(code); + if (kind) { + SPECIALIZATION_FAIL(CALL_FUNCTION, kind); return -1; } int argcount = code->co_argcount; From 1c5a9c018b16366b0c71adccaaee35510834179d Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 17 Nov 2021 10:14:50 +0000 Subject: [PATCH 2/6] Add NEWS --- .../Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst new file mode 100644 index 00000000000000..7947bf9753b472 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst @@ -0,0 +1,2 @@ +Specialize BINARY_SUBSCR for classes with a ``__getitem__`` method +implemented in Python From 2ad803bd3ff340e26fb7600e1997d3449f14783c Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 17 Nov 2021 15:42:18 +0000 Subject: [PATCH 3/6] Make function static. --- Python/specialize.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index d7c8a318d2db88..62090ab3211e18 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1140,7 +1140,8 @@ binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) _Py_IDENTIFIER(__getitem__); -int function_kind(PyCodeObject *code) { +static int +function_kind(PyCodeObject *code) { int flags = code->co_flags; if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { return SPEC_FAIL_GENERATOR; From 4eda0e827db5cfb435f3922ac446175ba0d92e6e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 17 Nov 2021 18:30:31 +0000 Subject: [PATCH 4/6] Make sure we check type version *before* accessing the function. --- Python/ceval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/ceval.c b/Python/ceval.c index 14071294da0359..2aafe19bd605c2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2165,8 +2165,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr _PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyObjectCache *cache1 = &caches[-1].obj; PyFunctionObject *getitem = (PyFunctionObject *)cache1->obj; - DEOPT_IF(getitem->func_version != cache0->index, BINARY_SUBSCR); DEOPT_IF(Py_TYPE(container)->tp_version_tag != cache0->version, BINARY_SUBSCR); + DEOPT_IF(getitem->func_version != cache0->index, BINARY_SUBSCR); PyCodeObject *code = (PyCodeObject *)getitem->func_code; size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; assert(code->co_argcount == 2); From 02f736c611c57f6d1350999ff416254e0e8cea3c Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 18 Nov 2021 09:11:12 +0000 Subject: [PATCH 5/6] Fix formatting in news item, and clarify code a bit. --- .../2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst | 2 +- Python/ceval.c | 2 +- Python/specialize.c | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst index 7947bf9753b472..ed8bfb99f85914 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-17-10-14-35.bpo-45829.5Cf6fY.rst @@ -1,2 +1,2 @@ -Specialize BINARY_SUBSCR for classes with a ``__getitem__`` method +Specialize :opcode:`BINARY_SUBSCR` for classes with a ``__getitem__`` method implemented in Python diff --git a/Python/ceval.c b/Python/ceval.c index 2aafe19bd605c2..4e2911f18eda8b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2089,7 +2089,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr STAT_INC(BINARY_SUBSCR, deferred); cache->adaptive.counter--; assert(cache->adaptive.original_oparg == 0); - oparg = 0; + /* No need to set oparg here; it isn't used by BINARY_SUBSCR */ STAT_DEC(BINARY_SUBSCR, unquickened); JUMP_TO_INSTRUCTION(BINARY_SUBSCR); } diff --git a/Python/specialize.c b/Python/specialize.c index 62090ab3211e18..f44103f4710622 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1140,12 +1140,13 @@ binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) _Py_IDENTIFIER(__getitem__); +#define SIMPLE_FUNCTION 0 + static int function_kind(PyCodeObject *code) { int flags = code->co_flags; if (flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { return SPEC_FAIL_GENERATOR; - return -1; } if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) { return SPEC_FAIL_COMPLEX_PARAMETERS; @@ -1156,7 +1157,7 @@ function_kind(PyCodeObject *code) { if (code->co_nfreevars) { return SPEC_FAIL_FREE_VARS; } - return 0; + return SIMPLE_FUNCTION; } int @@ -1193,7 +1194,7 @@ _Py_Specialize_BinarySubscr( PyFunctionObject *func = (PyFunctionObject *)descriptor; PyCodeObject *code = (PyCodeObject *)func->func_code; int kind = function_kind(code); - if (kind) { + if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(BINARY_SUBSCR, kind); goto fail; } @@ -1244,7 +1245,7 @@ specialize_py_call( _PyCallCache *cache1 = &cache[-1].call; PyCodeObject *code = (PyCodeObject *)func->func_code; int kind = function_kind(code); - if (kind) { + if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(CALL_FUNCTION, kind); return -1; } From d76c386c26aeb1e39e86b3d080f78cc072f6d1d1 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 18 Nov 2021 10:03:25 +0000 Subject: [PATCH 6/6] Delete unused code. --- Python/ceval.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 4e2911f18eda8b..ce329b186afd5e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4923,22 +4923,6 @@ opname ## _miss: \ JUMP_TO_INSTRUCTION(opname); \ } -#define MISS_WITH_OPARG_COUNTER(opname) \ -opname ## _miss: \ - { \ - STAT_INC(opname, miss); \ - uint8_t oparg = _Py_OPARG(next_instr[-1])-1; \ - UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \ - assert(_Py_OPARG(next_instr[-1]) == oparg); \ - if (oparg == 0) /* too many cache misses */ { \ - oparg = ADAPTIVE_CACHE_BACKOFF; \ - next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \ - STAT_INC(opname, deopt); \ - } \ - STAT_DEC(opname, unquickened); \ - JUMP_TO_INSTRUCTION(opname); \ - } - MISS_WITH_CACHE(LOAD_ATTR) MISS_WITH_CACHE(STORE_ATTR) MISS_WITH_CACHE(LOAD_GLOBAL)