From c46e369b11989edad8d6e80b4e08f8c864244c0e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 11 Jan 2019 18:04:22 +0200 Subject: [PATCH 1/3] bpo-35582: Inline arguments tuple unpacking in handwritten code. Inline PyArg_UnpackTuple() and _PyArg_UnpackStack() in performance critical code in the builtins and operator modules. --- Modules/_operator.c | 21 ++++++++++----------- Python/bltinmodule.c | 32 ++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Modules/_operator.c b/Modules/_operator.c index d6c6a18d81b449..d291ec1f920ed1 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -1011,15 +1011,12 @@ itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) Py_ssize_t i, nitems=ig->nitems; assert(PyTuple_CheckExact(args)); - if (kw == NULL && PyTuple_GET_SIZE(args) == 1) { - obj = PyTuple_GET_ITEM(args, 0); - } - else { - if (!_PyArg_NoKeywords("itemgetter", kw)) - return NULL; - if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) - return NULL; - } + if (!_PyArg_NoKeywords("itemgetter", kw)) + return NULL; + if (!_PyArg_CheckPositional("itemgetter", PyTuple_GET_SIZE(args), 1, 1)) + return NULL; + + obj = PyTuple_GET_ITEM(args, 0); if (nitems == 1) { if (ig->index >= 0 && PyTuple_CheckExact(obj) @@ -1317,8 +1314,9 @@ attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw) if (!_PyArg_NoKeywords("attrgetter", kw)) return NULL; - if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &obj)) + if (!_PyArg_CheckPositional("attrgetter", PyTuple_GET_SIZE(args), 1, 1)) return NULL; + obj = PyTuple_GET_ITEM(args, 0); if (ag->nattrs == 1) /* ag->attr is always a tuple */ return dotted_getattr(obj, PyTuple_GET_ITEM(ag->attr, 0)); @@ -1561,8 +1559,9 @@ methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw) if (!_PyArg_NoKeywords("methodcaller", kw)) return NULL; - if (!PyArg_UnpackTuple(args, "methodcaller", 1, 1, &obj)) + if (!_PyArg_CheckPositional("methodcaller", PyTuple_GET_SIZE(args), 1, 1)) return NULL; + obj = PyTuple_GET_ITEM(args, 0); method = PyObject_GetAttr(obj, mc->name); if (method == NULL) return NULL; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index e19bc5604ba109..e2f81b20928001 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1067,18 +1067,20 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, static PyObject * builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *v, *result, *dflt = NULL; - PyObject *name; + PyObject *v, *name, *result, *dflt; - if (!_PyArg_UnpackStack(args, nargs, "getattr", 2, 3, &v, &name, &dflt)) + if (!_PyArg_CheckPositional("getattr", nargs, 2, 3)) return NULL; + v = args[0]; + name = args[1]; if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_TypeError, "getattr(): attribute name must be string"); return NULL; } - if (dflt != NULL) { + if (nargs > 2) { + dflt = args[2]; if (_PyObject_LookupAttr(v, name, &result) == 0) { Py_INCREF(dflt); return dflt; @@ -1371,12 +1373,12 @@ PyTypeObject PyMap_Type = { static PyObject * builtin_next(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *it, *res; - PyObject *def = NULL; + PyObject *it, *def, *res; - if (!_PyArg_UnpackStack(args, nargs, "next", 1, 2, &it, &def)) + if (!_PyArg_CheckPositional("next", nargs, 1, 2)) return NULL; + it = args[0]; if (!PyIter_Check(it)) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not an iterator", @@ -1387,7 +1389,8 @@ builtin_next(PyObject *self, PyObject *const *args, Py_ssize_t nargs) res = (*it->ob_type->tp_iternext)(it); if (res != NULL) { return res; - } else if (def != NULL) { + } else if (nargs > 1) { + def = args[1]; if (PyErr_Occurred()) { if(!PyErr_ExceptionMatches(PyExc_StopIteration)) return NULL; @@ -1503,20 +1506,21 @@ builtin_hex(PyObject *module, PyObject *number) /* AC: cannot convert yet, as needs PEP 457 group support in inspect */ static PyObject * -builtin_iter(PyObject *self, PyObject *args) +builtin_iter(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *v, *w = NULL; + PyObject *v; - if (!PyArg_UnpackTuple(args, "iter", 1, 2, &v, &w)) + if (!_PyArg_CheckPositional("iter", nargs, 1, 2)) return NULL; - if (w == NULL) + v = args[0]; + if (nargs == 1) return PyObject_GetIter(v); if (!PyCallable_Check(v)) { PyErr_SetString(PyExc_TypeError, "iter(v, w): v must be callable"); return NULL; } - return PyCallIter_New(v, w); + return PyCallIter_New(v, args[1]); } PyDoc_STRVAR(iter_doc, @@ -2718,7 +2722,7 @@ static PyMethodDef builtin_methods[] = { BUILTIN_INPUT_METHODDEF BUILTIN_ISINSTANCE_METHODDEF BUILTIN_ISSUBCLASS_METHODDEF - {"iter", builtin_iter, METH_VARARGS, iter_doc}, + {"iter", (PyCFunction)(void(*)(void))builtin_iter, METH_FASTCALL, iter_doc}, BUILTIN_LEN_METHODDEF BUILTIN_LOCALS_METHODDEF {"max", (PyCFunction)(void(*)(void))builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc}, From 2465c1c6dccea1915961522fbd952a1b095a68f3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 11 Jan 2019 19:19:53 +0200 Subject: [PATCH 2/3] Address review comments. --- Python/bltinmodule.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index e2f81b20928001..839206b15300fa 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1067,7 +1067,7 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, static PyObject * builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *v, *name, *result, *dflt; + PyObject *v, *name, *result; if (!_PyArg_CheckPositional("getattr", nargs, 2, 3)) return NULL; @@ -1080,8 +1080,8 @@ builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return NULL; } if (nargs > 2) { - dflt = args[2]; if (_PyObject_LookupAttr(v, name, &result) == 0) { + PyObject *dflt = args[2]; Py_INCREF(dflt); return dflt; } @@ -1373,7 +1373,7 @@ PyTypeObject PyMap_Type = { static PyObject * builtin_next(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - PyObject *it, *def, *res; + PyObject *it, *res; if (!_PyArg_CheckPositional("next", nargs, 1, 2)) return NULL; @@ -1390,7 +1390,7 @@ builtin_next(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (res != NULL) { return res; } else if (nargs > 1) { - def = args[1]; + PyObject *def = args[1]; if (PyErr_Occurred()) { if(!PyErr_ExceptionMatches(PyExc_StopIteration)) return NULL; From 9e336761d36dba882b41d44aa35210bcdca6973a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 11 Jan 2019 19:26:24 +0200 Subject: [PATCH 3/3] Address review comments. --- Python/bltinmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 839206b15300fa..332142fc6ffc2a 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1520,7 +1520,8 @@ builtin_iter(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "iter(v, w): v must be callable"); return NULL; } - return PyCallIter_New(v, args[1]); + PyObject *sentinel = args[1]; + return PyCallIter_New(v, sentinel); } PyDoc_STRVAR(iter_doc,