cpython: 135a9a0c09f9 (original) (raw)
Mercurial > cpython
changeset 106396:135a9a0c09f9
Issue #29263: LOAD_METHOD support for C methods Calling builtin method is at most 10% faster. [#29263]
INADA Naoki songofacandy@gmail.com | |
---|---|
date | Fri, 03 Feb 2017 07:43:03 +0900 |
parents | c23224ebc9e5 |
children | b382206aeb2b |
files | Include/descrobject.h Include/methodobject.h Lib/test/test_gdb.py Objects/descrobject.c Objects/methodobject.c Objects/object.c Python/ceval.c Tools/gdb/libpython.py |
diffstat | 8 files changed, 88 insertions(+), 36 deletions(-)[+] [-] Include/descrobject.h 3 Include/methodobject.h 7 Lib/test/test_gdb.py 2 Objects/descrobject.c 38 Objects/methodobject.c 53 Objects/object.c 4 Python/ceval.c 12 Tools/gdb/libpython.py 5 |
line wrap: on
line diff
--- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -90,6 +90,9 @@ PyAPI_FUNC(PyObject *) PyDescr_NewMember PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, struct PyGetSetDef *); #ifndef Py_LIMITED_API + +PyAPI_FUNC(PyObject *) _PyMethodDescr_FastCallKeywords(
PyObject *descrobj, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames);[](#l1.9)
PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *, struct wrapperbase *, void *); #define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
--- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -102,6 +102,13 @@ PyAPI_FUNC(PyObject *) _PyMethodDef_RawF PyObject **args, Py_ssize_t nargs, PyObject *kwargs); + +PyAPI_FUNC(PyObject *) _PyMethodDef_RawFastCallKeywords(
#endif PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
--- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -846,7 +846,7 @@ id(42) breakpoint='time_gmtime', cmds_after_breakpoint=['py-bt-full'], )
self.assertIn('#1 <built-in method gmtime', gdb_output)[](#l3.7)
self.assertIn('#2 <built-in method gmtime', gdb_output)[](#l3.8)
@unittest.skipIf(python_is_optimized(), "Python was compiled with optimizations")
--- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -246,6 +246,44 @@ methoddescr_call(PyMethodDescrObject *de return result; } +// same to methoddescr_call(), but use FASTCALL convention. +PyObject * +_PyMethodDescr_FastCallKeywords(PyObject *descrobj,
PyObject **args, Py_ssize_t nargs,[](#l4.10)
PyObject *kwnames)[](#l4.11)
- assert(Py_TYPE(descrobj) == &PyMethodDescr_Type);
- PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj;
- PyObject *self, *result;
- /* Make sure that the first argument is acceptable as 'self' */
- if (nargs < 1) {
PyErr_Format(PyExc_TypeError,[](#l4.19)
"descriptor '%V' of '%.100s' "[](#l4.20)
"object needs an argument",[](#l4.21)
descr_name((PyDescrObject *)descr), "?",[](#l4.22)
PyDescr_TYPE(descr)->tp_name);[](#l4.23)
return NULL;[](#l4.24)
- }
- self = args[0];
- if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
(PyObject *)PyDescr_TYPE(descr))) {[](#l4.28)
PyErr_Format(PyExc_TypeError,[](#l4.29)
"descriptor '%V' "[](#l4.30)
"requires a '%.100s' object "[](#l4.31)
"but received a '%.100s'",[](#l4.32)
descr_name((PyDescrObject *)descr), "?",[](#l4.33)
PyDescr_TYPE(descr)->tp_name,[](#l4.34)
self->ob_type->tp_name);[](#l4.35)
return NULL;[](#l4.36)
- }
- result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self,
args+1, nargs-1, kwnames);[](#l4.40)
- result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
- return result;
+} + static PyObject * classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
--- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -215,32 +215,24 @@ PyObject * } PyObject * -_PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
Py_ssize_t nargs, PyObject *kwnames)[](#l5.8)
+_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject **args,
Py_ssize_t nargs, PyObject *kwnames)[](#l5.10)
- PyCFunctionObject *func;
- PyCFunction meth;
- PyObject *self, *result;
- Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
- int flags;
- /* _PyMethodDef_RawFastCallKeywords() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the[](#l5.18)
caller loses its exception */[](#l5.19)
- assert(!PyErr_Occurred());
- assert((nargs == 0 && nkwargs == 0) || args != NULL); /* kwnames must only contains str strings, no subclass, and all keys must be unique */
- /* _PyCFunction_FastCallKeywords() must not be called with an exception
set, because it can clear it (directly or indirectly) and so the caller[](#l5.32)
loses its exception */[](#l5.33)
- 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);
- PyCFunction meth = method->ml_meth;
- int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
- Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames);
- PyObject *result;
switch (flags) { @@ -248,7 +240,7 @@ PyObject * if (nargs != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)",
func->m_ml->ml_name, nargs);[](#l5.51)
method->ml_name, nargs);[](#l5.52) return NULL;[](#l5.53) }[](#l5.54)
@@ -263,7 +255,7 @@ PyObject * if (nargs != 1) { PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)",
func->m_ml->ml_name, nargs);[](#l5.60)
method->ml_name, nargs);[](#l5.61) return NULL;[](#l5.62) }[](#l5.63)
@@ -326,16 +318,31 @@ PyObject * return NULL; }
- result = _Py_CheckFunctionResult(func_obj, result, NULL); return result; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
func->m_ml->ml_name);[](#l5.75)
return NULL; } +PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args,method->ml_name);[](#l5.76)
Py_ssize_t nargs, PyObject *kwnames)[](#l5.82)
- result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml,
PyCFunction_GET_SELF(func),[](#l5.90)
args, nargs, kwnames);[](#l5.91)
- result = _Py_CheckFunctionResult(func, result, NULL);
- return result;
+} + /* Methods (the standard built-in methods, that is) */ static void
--- a/Objects/object.c +++ b/Objects/object.c @@ -1060,8 +1060,8 @@ int descr = _PyType_Lookup(tp, name); if (descr != NULL) { Py_INCREF(descr);
if (PyFunction_Check(descr)) {[](#l6.7)
/* A python method. */[](#l6.8)
if (PyFunction_Check(descr) ||[](#l6.9)
(Py_TYPE(descr) == &PyMethodDescr_Type)) {[](#l6.10) meth_found = 1;[](#l6.11) } else {[](#l6.12) f = descr->ob_type->tp_descr_get;[](#l6.13)
--- a/Python/ceval.c +++ b/Python/ceval.c @@ -4832,17 +4832,19 @@ call_function(PyObject ***pp_stack, Py_s PyObject *x, *w; Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); Py_ssize_t nargs = oparg - nkwargs;
/* Always dispatch PyCFunction first, because these are presumed to be the most frequent callable object. */ if (PyCFunction_Check(func)) { PyThreadState *tstate = PyThreadState_GET(); -
}stack = (*pp_stack) - nargs - nkwargs;[](#l7.16) C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));[](#l7.17)
- else if (Py_TYPE(func) == &PyMethodDescr_Type) {
PyThreadState *tstate = PyThreadState_GET();[](#l7.20)
C_TRACE(x, _PyMethodDescr_FastCallKeywords(func, stack, nargs, kwnames));[](#l7.21)
- } else { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { /* Optimize access to bound methods. Reuse the Python stack
@@ -4856,20 +4858,18 @@ call_function(PyObject ***pp_stack, Py_s Py_INCREF(func); Py_SETREF(*pfunc, self); nargs++;
stack--;[](#l7.30) }[](#l7.31) else {[](#l7.32) Py_INCREF(func);[](#l7.33) }[](#l7.34)
stack = (*pp_stack) - nargs - nkwargs;[](#l7.36)
- if (PyFunction_Check(func)) { x = fast_function(func, stack, nargs, kwnames); } else { x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames); } - Py_DECREF(func); }
--- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1540,10 +1540,7 @@ class Frame(object): if caller in ('_PyCFunction_FastCallDict', '_PyCFunction_FastCallKeywords'):
if caller == '_PyCFunction_FastCallKeywords':[](#l8.7)
arg_name = 'func_obj'[](#l8.8)
else:[](#l8.9)
arg_name = 'func'[](#l8.10)
arg_name = 'func'[](#l8.11) # Within that frame:[](#l8.12) # "func" is the local containing the PyObject* of the[](#l8.13) # PyCFunctionObject instance[](#l8.14)