diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-02-09 02:01:37 +0100 |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2017-02-09 02:01:37 +0100 |
commit | bbd3587a29510bd5a318e0a19fc8570c0cd3b622 (patch) | |
tree | bf8511fa4f52afa025c196f0dd2293dadcda932e | |
parent | 523c06aebf562b35e1fa84080bd051b608fe7d7f (diff) | |
download | cpython-bbd3587a29510bd5a318e0a19fc8570c0cd3b622.tar.gz |
Fix PyCFunction_Call() performance issue
Issue #29259, #29465: PyCFunction_Call() doesn't create anymore a redundant
tuple to pass positional arguments for METH_VARARGS.
Add a new cfunction_call() subfunction.
-rw-r--r-- | Objects/methodobject.c | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 07827775ca..d0fbefd550 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -77,13 +77,59 @@ PyCFunction_GetFlags(PyObject *op) return PyCFunction_GET_FLAGS(op); } +static PyObject * +cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs) +{ + assert(!PyErr_Occurred()); + + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + PyObject *result; + + if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) { + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + result = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs); + + Py_LeaveRecursiveCall(); + } + else { + if (kwargs != NULL && PyDict_Size(kwargs) != 0) { + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + ((PyCFunctionObject*)func)->m_ml->ml_name); + return NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + result = (*meth)(self, args); + + Py_LeaveRecursiveCall(); + } + + return _Py_CheckFunctionResult(func, result, NULL); +} + + PyObject * PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) { - return _PyCFunction_FastCallDict(func, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args), - kwargs); + /* first try METH_VARARGS to pass directly args tuple unchanged. + _PyMethodDef_RawFastCallDict() creates a new temporary tuple + for METH_VARARGS. */ + if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) { + return cfunction_call_varargs(func, args, kwargs); + } + else { + return _PyCFunction_FastCallDict(func, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); + } } PyObject * |