diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2017-01-18 09:38:09 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2017-01-18 09:38:09 (GMT) |
commit | c52572319cbd50adff85050a54122c25239a516d (patch) | |
tree | 41e964e6b6a25c655496561a32ce97c0f14ce253 | |
parent | 35ecebe165b1f64cb94c1b947db1d0b07e6db69b (diff) | |
download | cpython-c52572319cbd50adff85050a54122c25239a516d.zip cpython-c52572319cbd50adff85050a54122c25239a516d.tar.gz cpython-c52572319cbd50adff85050a54122c25239a516d.tar.bz2 |
Optimize methoddescr_call(): avoid temporary PyCFunction
Issue #29259, #29263. methoddescr_call() creates a PyCFunction object, call it
and the destroy it. Add a new _PyMethodDef_RawFastCallDict() method to avoid
the temporary PyCFunction object.
-rw-r--r-- | Include/methodobject.h | 7 | ||||
-rw-r--r-- | Objects/descrobject.c | 20 | ||||
-rw-r--r-- | Objects/methodobject.c | 39 |
3 files changed, 40 insertions, 26 deletions
diff --git a/Include/methodobject.h b/Include/methodobject.h index 79fad82..7370419 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -95,6 +95,13 @@ typedef struct { PyObject *m_module; /* The __module__ attribute, can be anything */ PyObject *m_weakreflist; /* List of weak references */ } PyCFunctionObject; + +PyAPI_FUNC(PyObject *) _PyMethodDef_RawFastCallDict( + PyMethodDef *method, + PyObject *self, + PyObject **args, + Py_ssize_t nargs, + PyObject *kwargs); #endif PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); diff --git a/Objects/descrobject.c b/Objects/descrobject.c index ed39891..a254a2a 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -210,15 +210,15 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) } static PyObject * -methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) +methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs) { - Py_ssize_t argc; - PyObject *self, *func, *result, **stack; + Py_ssize_t nargs; + PyObject *self, *result; /* Make sure that the first argument is acceptable as 'self' */ assert(PyTuple_Check(args)); - argc = PyTuple_GET_SIZE(args); - if (argc < 1) { + nargs = PyTuple_GET_SIZE(args); + if (nargs < 1) { PyErr_Format(PyExc_TypeError, "descriptor '%V' of '%.100s' " "object needs an argument", @@ -239,12 +239,10 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) return NULL; } - func = PyCFunction_NewEx(descr->d_method, self, NULL); - if (func == NULL) - return NULL; - stack = &PyTuple_GET_ITEM(args, 1); - result = _PyObject_FastCallDict(func, stack, argc - 1, kwds); - Py_DECREF(func); + result = _PyMethodDef_RawFastCallDict(descr->d_method, self, + &PyTuple_GET_ITEM(args, 1), nargs - 1, + kwargs); + result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL); return result; } diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 1d55a0c..054cf53 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -152,17 +152,14 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) } PyObject * -_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) +_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwargs) { - PyCFunctionObject *func; PyCFunction meth; - PyObject *self; PyObject *result; int flags; - assert(func_obj != NULL); - assert(PyCFunction_Check(func_obj)); + assert(method != NULL); assert(nargs >= 0); assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -172,10 +169,8 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, caller loses its exception */ assert(!PyErr_Occurred()); - func = (PyCFunctionObject*)func_obj; - meth = PyCFunction_GET_FUNCTION(func); - self = PyCFunction_GET_SELF(func); - flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + meth = method->ml_meth; + flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); switch (flags) { @@ -186,7 +181,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - func->m_ml->ml_name); + method->ml_name); return NULL; } @@ -197,7 +192,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, if (nargs != 1) { PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } @@ -259,18 +254,32 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, return NULL; } - result = _Py_CheckFunctionResult(func_obj, result, NULL); - return result; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } PyObject * +_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwargs); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + +PyObject * _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { |