Skip to content

Commit 3a60bfe

Browse files
authored
bpo-44525: Specialize for calls to type and other builtin classes with 1 argument. (GH-29942)
1 parent f025ae6 commit 3a60bfe

File tree

6 files changed

+105
-40
lines changed

6 files changed

+105
-40
lines changed

Include/opcode.h

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

Lib/opcode.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ def jabs_op(name, op):
259259
"CALL_NO_KW_PY_SIMPLE",
260260
"CALL_NO_KW_LIST_APPEND",
261261
"CALL_NO_KW_METHOD_DESCRIPTOR_O",
262+
"CALL_NO_KW_TYPE_1",
263+
"CALL_NO_KW_BUILTIN_CLASS_1",
262264
"CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
263265
"JUMP_ABSOLUTE_QUICK",
264266
"LOAD_ATTR_ADAPTIVE",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Specialize the CALL_FUNCTION instruction for calls to builtin types with a
2+
single argument. Speeds up ``range(x)``, ``list(x)``, and specifically
3+
``type(obj)``.

Python/ceval.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4854,6 +4854,41 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
48544854
goto start_frame;
48554855
}
48564856

4857+
TARGET(CALL_NO_KW_TYPE_1) {
4858+
assert(STACK_ADJUST_IS_RESET);
4859+
assert(GET_CACHE()->adaptive.original_oparg == 1);
4860+
PyObject *obj = TOP();
4861+
PyObject *callable = SECOND();
4862+
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL_NO_KW);
4863+
PyObject *res = Py_NewRef(Py_TYPE(obj));
4864+
STACK_SHRINK(1);
4865+
Py_DECREF(callable);
4866+
Py_DECREF(obj);
4867+
SET_TOP(res);
4868+
DISPATCH();
4869+
}
4870+
4871+
TARGET(CALL_NO_KW_BUILTIN_CLASS_1) {
4872+
assert(STACK_ADJUST_IS_RESET);
4873+
SpecializedCacheEntry *caches = GET_CACHE();
4874+
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
4875+
assert(cache0->original_oparg == 1);
4876+
PyObject *callable = SECOND();
4877+
PyObject *arg = TOP();
4878+
DEOPT_IF(!PyType_Check(callable), CALL_NO_KW);
4879+
PyTypeObject *tp = (PyTypeObject *)callable;
4880+
DEOPT_IF(tp->tp_version_tag != cache0->version, CALL_NO_KW);
4881+
STACK_SHRINK(1);
4882+
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, 1, NULL);
4883+
SET_TOP(res);
4884+
Py_DECREF(tp);
4885+
Py_DECREF(arg);
4886+
if (res == NULL) {
4887+
goto error;
4888+
}
4889+
DISPATCH();
4890+
}
4891+
48574892
TARGET(CALL_NO_KW_BUILTIN_O) {
48584893
assert(cframe.use_tracing == 0);
48594894
assert(STACK_ADJUST_IS_RESET);

Python/opcode_targets.h

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

Python/specialize.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,10 @@ initial_counter_value(void) {
491491
#define SPEC_FAIL_PYCFUNCTION_NOARGS 16
492492
#define SPEC_FAIL_BAD_CALL_FLAGS 17
493493
#define SPEC_FAIL_CLASS 18
494-
#define SPEC_FAIL_C_METHOD_CALL 19
495-
#define SPEC_FAIL_METHDESCR_NON_METHOD 20
494+
#define SPEC_FAIL_PYTHON_CLASS 19
495+
#define SPEC_FAIL_C_METHOD_CALL 20
496+
#define SPEC_FAIL_METHDESCR_NON_METHOD 21
497+
#define SPEC_FAIL_METHOD_CALL_CLASS 22
496498

497499
/* COMPARE_OP */
498500
#define SPEC_FAIL_STRING_COMPARE 13
@@ -1263,6 +1265,27 @@ specialize_class_call(
12631265
PyObject *callable, _Py_CODEUNIT *instr,
12641266
int nargs, SpecializedCacheEntry *cache)
12651267
{
1268+
assert(PyType_Check(callable));
1269+
PyTypeObject *tp = (PyTypeObject *)callable;
1270+
if (_Py_OPCODE(instr[-1]) == PRECALL_METHOD) {
1271+
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_METHOD_CALL_CLASS);
1272+
return -1;
1273+
}
1274+
if (tp->tp_new == PyBaseObject_Type.tp_new) {
1275+
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_PYTHON_CLASS);
1276+
return -1;
1277+
}
1278+
if (nargs == 1) {
1279+
if (tp == &PyType_Type) {
1280+
*instr = _Py_MAKECODEUNIT(CALL_NO_KW_TYPE_1, _Py_OPARG(*instr));
1281+
return 0;
1282+
}
1283+
if ((tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) && tp->tp_vectorcall != NULL) {
1284+
cache->adaptive.version = tp->tp_version_tag;
1285+
*instr = _Py_MAKECODEUNIT(CALL_NO_KW_BUILTIN_CLASS_1, _Py_OPARG(*instr));
1286+
return 0;
1287+
}
1288+
}
12661289
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_CLASS);
12671290
return -1;
12681291
}

0 commit comments

Comments
 (0)