cpython: a25c39873d93 (original) (raw)
Mercurial > cpython
changeset 103467:a25c39873d93
Issue #27810: Add _PyCFunction_FastCallKeywords() Use _PyCFunction_FastCallKeywords() in ceval.c: it allows to remove a lot of code from ceval.c which was only used to call C functions. [#27810]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Fri, 09 Sep 2016 14:07:44 -0700 |
parents | 672c5fe7372c |
children | ef3d30cc6b4f 861ddad3e0c1 |
files | Include/abstract.h Include/methodobject.h Objects/abstract.c Objects/methodobject.c Python/ceval.c |
diffstat | 5 files changed, 76 insertions(+), 143 deletions(-)[+] [-] Include/abstract.h 9 Include/methodobject.h 5 Objects/abstract.c 7 Objects/methodobject.c 26 Python/ceval.c 172 |
line wrap: on
line diff
--- a/Include/abstract.h +++ b/Include/abstract.h @@ -267,9 +267,16 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PyObject *args, PyObject *kwargs); #ifndef Py_LIMITED_API
- PyAPI_FUNC(PyObject *) _PyStack_AsDict(
PyObject **values,[](#l1.13)
Py_ssize_t nkwargs,[](#l1.14)
PyObject *kwnames,[](#l1.15)
PyObject *func);[](#l1.16)
+ /* Call the callable object func with the "fast call" calling convention: args is a C array for positional arguments (nargs is the number of positional arguments), kwargs is a dictionary for keyword arguments.
--- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -42,6 +42,11 @@ PyAPI_FUNC(PyObject *) _PyCFunction_Fast PyObject **args, Py_ssize_t nargs, PyObject *kwargs); + +PyAPI_FUNC(PyObject *) _PyCFunction_FastCallKeywords(PyObject *func,
--- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2366,7 +2366,7 @@ PyObject * return result; } -static PyObject * +PyObject * _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, PyObject *func) { @@ -2415,10 +2415,13 @@ PyObject * assert((nargs == 0 && nkwargs == 0) || stack != NULL); if (PyFunction_Check(func)) {
}/* Fast-path: avoid temporary tuple or dict */[](#l3.16) return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);[](#l3.17)
- if (PyCFunction_Check(func)) {
return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames);[](#l3.21)
- }
+ if (nkwargs > 0) { kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); if (kwdict == NULL) {
--- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -155,6 +155,7 @@ PyObject * PyObject *result; int flags;
- assert(PyCFunction_Check(func)); assert(func != NULL); assert(nargs >= 0); assert(nargs == 0 || args != NULL); @@ -243,6 +244,31 @@ PyObject * return result; }
+PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
Py_ssize_t nargs, PyObject *kwnames)[](#l4.17)
- nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
- if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);[](#l4.26)
if (kwdict == NULL) {[](#l4.27)
return NULL;[](#l4.28)
}[](#l4.29)
- }
- else {
kwdict = NULL;[](#l4.32)
- }
+} + /* Methods (the standard built-in methods, that is) */ static void
--- a/Python/ceval.c +++ b/Python/ceval.c @@ -115,8 +115,6 @@ static PyObject * call_function(PyObject #endif static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *); static PyObject * do_call_core(PyObject *, PyObject *, PyObject *); -static PyObject * create_keyword_args(PyObject *, PyObject ***, PyObject *); -static PyObject * load_args(PyObject ***, Py_ssize_t); #ifdef LLTRACE static int lltrace; @@ -4892,21 +4890,6 @@ PyEval_GetFuncDesc(PyObject *func) return " object"; } -static void -err_args(PyObject *func, int flags, Py_ssize_t nargs) -{
- if (flags & METH_NOARGS)
PyErr_Format(PyExc_TypeError,[](#l5.20)
"%.200s() takes no arguments (%zd given)",[](#l5.21)
((PyCFunctionObject *)func)->m_ml->ml_name,[](#l5.22)
nargs);[](#l5.23)
- else
PyErr_Format(PyExc_TypeError,[](#l5.25)
"%.200s() takes exactly one argument (%zd given)",[](#l5.26)
((PyCFunctionObject *)func)->m_ml->ml_name,[](#l5.27)
nargs);[](#l5.28)
-} - #define C_TRACE(x, call) [](#l5.31) if (tstate->use_tracing && tstate->c_profilefunc) { [](#l5.32) if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, [](#l5.33) @@ -4950,91 +4933,49 @@ 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)) {
int flags = PyCFunction_GET_FLAGS(func);[](#l5.44) PyThreadState *tstate = PyThreadState_GET();[](#l5.45)
if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) {[](#l5.48)
PyCFunction meth = PyCFunction_GET_FUNCTION(func);[](#l5.49)
PyObject *self = PyCFunction_GET_SELF(func);[](#l5.50)
if (flags & METH_NOARGS && nargs == 0) {[](#l5.51)
C_TRACE(x, (*meth)(self,NULL));[](#l5.52)
x = _Py_CheckFunctionResult(func, x, NULL);[](#l5.54)
}[](#l5.55)
else if (flags & METH_O && nargs == 1) {[](#l5.56)
PyObject *arg = EXT_POP(*pp_stack);[](#l5.57)
C_TRACE(x, (*meth)(self,arg));[](#l5.58)
Py_DECREF(arg);[](#l5.59)
x = _Py_CheckFunctionResult(func, x, NULL);[](#l5.61)
}[](#l5.62)
else {[](#l5.63)
err_args(func, flags, nargs);[](#l5.64)
x = NULL;[](#l5.65)
}[](#l5.66)
stack = (*pp_stack) - nargs - nkwargs;[](#l5.68)
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));[](#l5.69)
- }
- else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {[](#l5.72)
/* optimize access to bound methods */[](#l5.73)
PyObject *self = PyMethod_GET_SELF(func);[](#l5.74)
PCALL(PCALL_METHOD);[](#l5.75)
PCALL(PCALL_BOUND_METHOD);[](#l5.76)
Py_INCREF(self);[](#l5.77)
func = PyMethod_GET_FUNCTION(func);[](#l5.78)
Py_INCREF(func);[](#l5.79)
Py_SETREF(*pfunc, self);[](#l5.80)
nargs++;[](#l5.81) }[](#l5.82) else {[](#l5.83)
PyObject *callargs, *kwdict = NULL;[](#l5.84)
if (kwnames != NULL) {[](#l5.85)
kwdict = create_keyword_args(kwnames, pp_stack, func);[](#l5.86)
if (kwdict == NULL) {[](#l5.87)
x = NULL;[](#l5.88)
goto cfuncerror;[](#l5.89)
}[](#l5.90)
}[](#l5.91)
callargs = load_args(pp_stack, nargs);[](#l5.92)
if (callargs != NULL) {[](#l5.93)
READ_TIMESTAMP(*pintr0);[](#l5.94)
C_TRACE(x, PyCFunction_Call(func, callargs, kwdict));[](#l5.95)
READ_TIMESTAMP(*pintr1);[](#l5.96)
Py_DECREF(callargs);[](#l5.97)
}[](#l5.98)
else {[](#l5.99)
x = NULL;[](#l5.100)
}[](#l5.101)
Py_XDECREF(kwdict);[](#l5.102)
}[](#l5.103)
Py_INCREF(func);[](#l5.104)
}[](#l5.105)
stack = (*pp_stack) - nargs - nkwargs;[](#l5.107)
READ_TIMESTAMP(*pintr0);[](#l5.109)
if (PyFunction_Check(func)) {[](#l5.110)
x = fast_function(func, stack, nargs, kwnames);[](#l5.111)
}[](#l5.112)
else {[](#l5.113)
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);[](#l5.114)
}[](#l5.115)
READ_TIMESTAMP(*pintr1);[](#l5.116)
- else {
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);[](#l5.121)
PyObject **stack;[](#l5.122)
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {[](#l5.124)
/* optimize access to bound methods */[](#l5.125)
PyObject *self = PyMethod_GET_SELF(func);[](#l5.126)
PCALL(PCALL_METHOD);[](#l5.127)
PCALL(PCALL_BOUND_METHOD);[](#l5.128)
Py_INCREF(self);[](#l5.129)
func = PyMethod_GET_FUNCTION(func);[](#l5.130)
Py_INCREF(func);[](#l5.131)
Py_SETREF(*pfunc, self);[](#l5.132)
nargs++;[](#l5.133)
}[](#l5.134)
else {[](#l5.135)
Py_INCREF(func);[](#l5.136)
}[](#l5.137)
stack = (*pp_stack) - nargs - nkwargs;[](#l5.139)
READ_TIMESTAMP(*pintr0);[](#l5.141)
if (PyFunction_Check(func)) {[](#l5.142)
x = fast_function(func, stack, nargs, kwnames);[](#l5.143)
}[](#l5.144)
else {[](#l5.145)
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);[](#l5.146)
}[](#l5.147)
READ_TIMESTAMP(*pintr1);[](#l5.148)
- -cfuncerror: + assert((x != NULL) ^ (PyErr_Occurred() != NULL)); /* Clear the stack of the function object. Also removes @@ -5243,55 +5184,6 @@ PyObject * } static PyObject * -create_keyword_args(PyObject *names, PyObject ***pp_stack,
PyObject *func)[](#l5.163)
- Py_ssize_t nk = PyTuple_GET_SIZE(names);
- PyObject *kwdict = _PyDict_NewPresized(nk);
- if (kwdict == NULL)
return NULL;[](#l5.168)
- while (--nk >= 0) {
int err;[](#l5.170)
PyObject *key = PyTuple_GET_ITEM(names, nk);[](#l5.171)
PyObject *value = EXT_POP(*pp_stack);[](#l5.172)
if (PyDict_GetItem(kwdict, key) != NULL) {[](#l5.173)
PyErr_Format(PyExc_TypeError,[](#l5.174)
"%.200s%s got multiple values "[](#l5.175)
"for keyword argument '%U'",[](#l5.176)
PyEval_GetFuncName(func),[](#l5.177)
PyEval_GetFuncDesc(func),[](#l5.178)
key);[](#l5.179)
Py_DECREF(value);[](#l5.180)
Py_DECREF(kwdict);[](#l5.181)
return NULL;[](#l5.182)
}[](#l5.183)
err = PyDict_SetItem(kwdict, key, value);[](#l5.184)
Py_DECREF(value);[](#l5.185)
if (err) {[](#l5.186)
Py_DECREF(kwdict);[](#l5.187)
return NULL;[](#l5.188)
}[](#l5.189)
- }
- return kwdict;
-} - -static PyObject * -load_args(PyObject ***pp_stack, Py_ssize_t nargs) -{
- while (--nargs >= 0) {
PyObject *arg= EXT_POP(*pp_stack);[](#l5.204)
PyTuple_SET_ITEM(args, nargs, arg);[](#l5.205)
- }
- return args;
-} - -static PyObject * do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) { #ifdef CALL_PROFILE