From 3a60bfef49b3324660a615a8e6d10710e5f669d9 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 15 Dec 2021 15:03:42 +0000 Subject: bpo-44525: Specialize for calls to type and other builtin classes with 1 argument. (GH-29942) --- Include/opcode.h | 50 +++++++++++----------- Lib/opcode.py | 2 + .../2021-12-07-11-04-21.bpo-44525.6OWCgr.rst | 3 ++ Python/ceval.c | 35 +++++++++++++++ Python/opcode_targets.h | 28 ++++++------ Python/specialize.c | 27 +++++++++++- 6 files changed, 105 insertions(+), 40 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-12-07-11-04-21.bpo-44525.6OWCgr.rst diff --git a/Include/opcode.h b/Include/opcode.h index bdabffd..0556526 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -142,30 +142,32 @@ extern "C" { #define CALL_NO_KW_PY_SIMPLE 45 #define CALL_NO_KW_LIST_APPEND 46 #define CALL_NO_KW_METHOD_DESCRIPTOR_O 47 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 48 -#define JUMP_ABSOLUTE_QUICK 55 -#define LOAD_ATTR_ADAPTIVE 56 -#define LOAD_ATTR_INSTANCE_VALUE 57 -#define LOAD_ATTR_WITH_HINT 58 -#define LOAD_ATTR_SLOT 59 -#define LOAD_ATTR_MODULE 62 -#define LOAD_GLOBAL_ADAPTIVE 63 -#define LOAD_GLOBAL_MODULE 64 -#define LOAD_GLOBAL_BUILTIN 65 -#define LOAD_METHOD_ADAPTIVE 66 -#define LOAD_METHOD_CACHED 67 -#define LOAD_METHOD_CLASS 72 -#define LOAD_METHOD_MODULE 75 -#define LOAD_METHOD_NO_DICT 76 -#define STORE_ATTR_ADAPTIVE 77 -#define STORE_ATTR_INSTANCE_VALUE 78 -#define STORE_ATTR_SLOT 79 -#define STORE_ATTR_WITH_HINT 80 -#define LOAD_FAST__LOAD_FAST 81 -#define STORE_FAST__LOAD_FAST 87 -#define LOAD_FAST__LOAD_CONST 128 -#define LOAD_CONST__LOAD_FAST 131 -#define STORE_FAST__STORE_FAST 134 +#define CALL_NO_KW_TYPE_1 48 +#define CALL_NO_KW_BUILTIN_CLASS_1 55 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 56 +#define JUMP_ABSOLUTE_QUICK 57 +#define LOAD_ATTR_ADAPTIVE 58 +#define LOAD_ATTR_INSTANCE_VALUE 59 +#define LOAD_ATTR_WITH_HINT 62 +#define LOAD_ATTR_SLOT 63 +#define LOAD_ATTR_MODULE 64 +#define LOAD_GLOBAL_ADAPTIVE 65 +#define LOAD_GLOBAL_MODULE 66 +#define LOAD_GLOBAL_BUILTIN 67 +#define LOAD_METHOD_ADAPTIVE 72 +#define LOAD_METHOD_CACHED 75 +#define LOAD_METHOD_CLASS 76 +#define LOAD_METHOD_MODULE 77 +#define LOAD_METHOD_NO_DICT 78 +#define STORE_ATTR_ADAPTIVE 79 +#define STORE_ATTR_INSTANCE_VALUE 80 +#define STORE_ATTR_SLOT 81 +#define STORE_ATTR_WITH_HINT 87 +#define LOAD_FAST__LOAD_FAST 128 +#define STORE_FAST__LOAD_FAST 131 +#define LOAD_FAST__LOAD_CONST 134 +#define LOAD_CONST__LOAD_FAST 140 +#define STORE_FAST__STORE_FAST 141 #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 cb16ef7..7b69988 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -259,6 +259,8 @@ _specialized_instructions = [ "CALL_NO_KW_PY_SIMPLE", "CALL_NO_KW_LIST_APPEND", "CALL_NO_KW_METHOD_DESCRIPTOR_O", + "CALL_NO_KW_TYPE_1", + "CALL_NO_KW_BUILTIN_CLASS_1", "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", "JUMP_ABSOLUTE_QUICK", "LOAD_ATTR_ADAPTIVE", diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-07-11-04-21.bpo-44525.6OWCgr.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-07-11-04-21.bpo-44525.6OWCgr.rst new file mode 100644 index 0000000..8e1533f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-07-11-04-21.bpo-44525.6OWCgr.rst @@ -0,0 +1,3 @@ +Specialize the CALL_FUNCTION instruction for calls to builtin types with a +single argument. Speeds up ``range(x)``, ``list(x)``, and specifically +``type(obj)``. diff --git a/Python/ceval.c b/Python/ceval.c index 7932433..b9444b2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4854,6 +4854,41 @@ check_eval_breaker: goto start_frame; } + TARGET(CALL_NO_KW_TYPE_1) { + assert(STACK_ADJUST_IS_RESET); + assert(GET_CACHE()->adaptive.original_oparg == 1); + PyObject *obj = TOP(); + PyObject *callable = SECOND(); + DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL_NO_KW); + PyObject *res = Py_NewRef(Py_TYPE(obj)); + STACK_SHRINK(1); + Py_DECREF(callable); + Py_DECREF(obj); + SET_TOP(res); + DISPATCH(); + } + + TARGET(CALL_NO_KW_BUILTIN_CLASS_1) { + assert(STACK_ADJUST_IS_RESET); + SpecializedCacheEntry *caches = GET_CACHE(); + _PyAdaptiveEntry *cache0 = &caches[0].adaptive; + assert(cache0->original_oparg == 1); + PyObject *callable = SECOND(); + PyObject *arg = TOP(); + DEOPT_IF(!PyType_Check(callable), CALL_NO_KW); + PyTypeObject *tp = (PyTypeObject *)callable; + DEOPT_IF(tp->tp_version_tag != cache0->version, CALL_NO_KW); + STACK_SHRINK(1); + PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, 1, NULL); + SET_TOP(res); + Py_DECREF(tp); + Py_DECREF(arg); + if (res == NULL) { + goto error; + } + DISPATCH(); + } + TARGET(CALL_NO_KW_BUILTIN_O) { assert(cframe.use_tracing == 0); assert(STACK_ADJUST_IS_RESET); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 3b2e99d..3ee0b9c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -47,46 +47,46 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_PY_SIMPLE, &&TARGET_CALL_NO_KW_LIST_APPEND, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, + &&TARGET_CALL_NO_KW_BUILTIN_CLASS_1, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_JUMP_ABSOLUTE_QUICK, &&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_LOAD_ATTR_WITH_HINT, - &&TARGET_LOAD_ATTR_SLOT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_METHOD_ADAPTIVE, - &&TARGET_LOAD_METHOD_CACHED, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_METHOD_CLASS, + &&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_GET_AWAITABLE, &&TARGET_LOAD_ASSERTION_ERROR, + &&TARGET_LOAD_METHOD_CACHED, + &&TARGET_LOAD_METHOD_CLASS, &&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_LOAD_FAST__LOAD_FAST, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, &&TARGET_YIELD_VALUE, - &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, @@ -127,20 +127,20 @@ static void *opcode_targets[256] = { &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, &&TARGET_JUMP_IF_NOT_EG_MATCH, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_GEN_START, &&TARGET_RAISE_VARARGS, - &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, - &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_MAKE_CELL, &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_CALL_FUNCTION_EX, &&_unknown_opcode, &&TARGET_EXTENDED_ARG, diff --git a/Python/specialize.c b/Python/specialize.c index bdcba46..5cf327d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -491,8 +491,10 @@ initial_counter_value(void) { #define SPEC_FAIL_PYCFUNCTION_NOARGS 16 #define SPEC_FAIL_BAD_CALL_FLAGS 17 #define SPEC_FAIL_CLASS 18 -#define SPEC_FAIL_C_METHOD_CALL 19 -#define SPEC_FAIL_METHDESCR_NON_METHOD 20 +#define SPEC_FAIL_PYTHON_CLASS 19 +#define SPEC_FAIL_C_METHOD_CALL 20 +#define SPEC_FAIL_METHDESCR_NON_METHOD 21 +#define SPEC_FAIL_METHOD_CALL_CLASS 22 /* COMPARE_OP */ #define SPEC_FAIL_STRING_COMPARE 13 @@ -1263,6 +1265,27 @@ specialize_class_call( PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache) { + assert(PyType_Check(callable)); + PyTypeObject *tp = (PyTypeObject *)callable; + if (_Py_OPCODE(instr[-1]) == PRECALL_METHOD) { + SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_METHOD_CALL_CLASS); + return -1; + } + if (tp->tp_new == PyBaseObject_Type.tp_new) { + SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_PYTHON_CLASS); + return -1; + } + if (nargs == 1) { + if (tp == &PyType_Type) { + *instr = _Py_MAKECODEUNIT(CALL_NO_KW_TYPE_1, _Py_OPARG(*instr)); + return 0; + } + if ((tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) && tp->tp_vectorcall != NULL) { + cache->adaptive.version = tp->tp_version_tag; + *instr = _Py_MAKECODEUNIT(CALL_NO_KW_BUILTIN_CLASS_1, _Py_OPARG(*instr)); + return 0; + } + } SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_CLASS); return -1; } -- cgit v0.12