mirror of https://github.com/python/cpython.git
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.
This commit is contained in:
parent
502893896a
commit
ae8b69c410
|
@ -267,9 +267,16 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
PyObject *args, PyObject *kwargs);
|
PyObject *args, PyObject *kwargs);
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
PyAPI_FUNC(PyObject*) _PyStack_AsTuple(PyObject **stack,
|
PyAPI_FUNC(PyObject*) _PyStack_AsTuple(
|
||||||
|
PyObject **stack,
|
||||||
Py_ssize_t nargs);
|
Py_ssize_t nargs);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject *) _PyStack_AsDict(
|
||||||
|
PyObject **values,
|
||||||
|
Py_ssize_t nkwargs,
|
||||||
|
PyObject *kwnames,
|
||||||
|
PyObject *func);
|
||||||
|
|
||||||
/* Call the callable object func with the "fast call" calling convention:
|
/* Call the callable object func with the "fast call" calling convention:
|
||||||
args is a C array for positional arguments (nargs is the number of
|
args is a C array for positional arguments (nargs is the number of
|
||||||
positional arguments), kwargs is a dictionary for keyword arguments.
|
positional arguments), kwargs is a dictionary for keyword arguments.
|
||||||
|
|
|
@ -42,6 +42,11 @@ PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func,
|
||||||
PyObject **args,
|
PyObject **args,
|
||||||
Py_ssize_t nargs,
|
Py_ssize_t nargs,
|
||||||
PyObject *kwargs);
|
PyObject *kwargs);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject *) _PyCFunction_FastCallKeywords(PyObject *func,
|
||||||
|
PyObject **stack,
|
||||||
|
Py_ssize_t nargs,
|
||||||
|
PyObject *kwnames);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct PyMethodDef {
|
struct PyMethodDef {
|
||||||
|
|
|
@ -2366,7 +2366,7 @@ _PyObject_Call_Prepend(PyObject *func,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
PyObject *
|
||||||
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
|
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
|
||||||
PyObject *func)
|
PyObject *func)
|
||||||
{
|
{
|
||||||
|
@ -2415,10 +2415,13 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
|
||||||
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
|
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
|
||||||
|
|
||||||
if (PyFunction_Check(func)) {
|
if (PyFunction_Check(func)) {
|
||||||
/* Fast-path: avoid temporary tuple or dict */
|
|
||||||
return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
|
return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PyCFunction_Check(func)) {
|
||||||
|
return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames);
|
||||||
|
}
|
||||||
|
|
||||||
if (nkwargs > 0) {
|
if (nkwargs > 0) {
|
||||||
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
|
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
|
||||||
if (kwdict == NULL) {
|
if (kwdict == NULL) {
|
||||||
|
|
|
@ -155,6 +155,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
assert(PyCFunction_Check(func));
|
||||||
assert(func != NULL);
|
assert(func != NULL);
|
||||||
assert(nargs >= 0);
|
assert(nargs >= 0);
|
||||||
assert(nargs == 0 || args != NULL);
|
assert(nargs == 0 || args != NULL);
|
||||||
|
@ -243,6 +244,31 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
|
||||||
|
Py_ssize_t nargs, PyObject *kwnames)
|
||||||
|
{
|
||||||
|
PyObject *kwdict, *result;
|
||||||
|
Py_ssize_t nkwargs;
|
||||||
|
|
||||||
|
assert(PyCFunction_Check(func));
|
||||||
|
|
||||||
|
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
||||||
|
if (nkwargs > 0) {
|
||||||
|
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
|
||||||
|
if (kwdict == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kwdict = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict);
|
||||||
|
Py_XDECREF(kwdict);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Methods (the standard built-in methods, that is) */
|
/* Methods (the standard built-in methods, that is) */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
114
Python/ceval.c
114
Python/ceval.c
|
@ -115,8 +115,6 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *);
|
||||||
#endif
|
#endif
|
||||||
static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *);
|
static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *);
|
||||||
static PyObject * do_call_core(PyObject *, PyObject *, 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
|
#ifdef LLTRACE
|
||||||
static int lltrace;
|
static int lltrace;
|
||||||
|
@ -4892,21 +4890,6 @@ PyEval_GetFuncDesc(PyObject *func)
|
||||||
return " object";
|
return " object";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
err_args(PyObject *func, int flags, Py_ssize_t nargs)
|
|
||||||
{
|
|
||||||
if (flags & METH_NOARGS)
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%.200s() takes no arguments (%zd given)",
|
|
||||||
((PyCFunctionObject *)func)->m_ml->ml_name,
|
|
||||||
nargs);
|
|
||||||
else
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%.200s() takes exactly one argument (%zd given)",
|
|
||||||
((PyCFunctionObject *)func)->m_ml->ml_name,
|
|
||||||
nargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define C_TRACE(x, call) \
|
#define C_TRACE(x, call) \
|
||||||
if (tstate->use_tracing && tstate->c_profilefunc) { \
|
if (tstate->use_tracing && tstate->c_profilefunc) { \
|
||||||
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
|
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
|
||||||
|
@ -4950,61 +4933,20 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames
|
||||||
PyObject *x, *w;
|
PyObject *x, *w;
|
||||||
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
||||||
Py_ssize_t nargs = oparg - nkwargs;
|
Py_ssize_t nargs = oparg - nkwargs;
|
||||||
|
PyObject **stack;
|
||||||
|
|
||||||
/* Always dispatch PyCFunction first, because these are
|
/* Always dispatch PyCFunction first, because these are
|
||||||
presumed to be the most frequent callable object.
|
presumed to be the most frequent callable object.
|
||||||
*/
|
*/
|
||||||
if (PyCFunction_Check(func)) {
|
if (PyCFunction_Check(func)) {
|
||||||
int flags = PyCFunction_GET_FLAGS(func);
|
|
||||||
PyThreadState *tstate = PyThreadState_GET();
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
|
|
||||||
PCALL(PCALL_CFUNCTION);
|
PCALL(PCALL_CFUNCTION);
|
||||||
if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) {
|
|
||||||
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
|
|
||||||
PyObject *self = PyCFunction_GET_SELF(func);
|
|
||||||
if (flags & METH_NOARGS && nargs == 0) {
|
|
||||||
C_TRACE(x, (*meth)(self,NULL));
|
|
||||||
|
|
||||||
x = _Py_CheckFunctionResult(func, x, NULL);
|
stack = (*pp_stack) - nargs - nkwargs;
|
||||||
}
|
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
|
||||||
else if (flags & METH_O && nargs == 1) {
|
|
||||||
PyObject *arg = EXT_POP(*pp_stack);
|
|
||||||
C_TRACE(x, (*meth)(self,arg));
|
|
||||||
Py_DECREF(arg);
|
|
||||||
|
|
||||||
x = _Py_CheckFunctionResult(func, x, NULL);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err_args(func, flags, nargs);
|
|
||||||
x = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PyObject *callargs, *kwdict = NULL;
|
|
||||||
if (kwnames != NULL) {
|
|
||||||
kwdict = create_keyword_args(kwnames, pp_stack, func);
|
|
||||||
if (kwdict == NULL) {
|
|
||||||
x = NULL;
|
|
||||||
goto cfuncerror;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callargs = load_args(pp_stack, nargs);
|
|
||||||
if (callargs != NULL) {
|
|
||||||
READ_TIMESTAMP(*pintr0);
|
|
||||||
C_TRACE(x, PyCFunction_Call(func, callargs, kwdict));
|
|
||||||
READ_TIMESTAMP(*pintr1);
|
|
||||||
Py_DECREF(callargs);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
x = NULL;
|
|
||||||
}
|
|
||||||
Py_XDECREF(kwdict);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
|
||||||
PyObject **stack;
|
|
||||||
|
|
||||||
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
|
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
|
||||||
/* optimize access to bound methods */
|
/* optimize access to bound methods */
|
||||||
PyObject *self = PyMethod_GET_SELF(func);
|
PyObject *self = PyMethod_GET_SELF(func);
|
||||||
|
@ -5034,7 +4976,6 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames
|
||||||
Py_DECREF(func);
|
Py_DECREF(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
cfuncerror:
|
|
||||||
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
|
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
|
||||||
|
|
||||||
/* Clear the stack of the function object. Also removes
|
/* Clear the stack of the function object. Also removes
|
||||||
|
@ -5242,55 +5183,6 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
create_keyword_args(PyObject *names, PyObject ***pp_stack,
|
|
||||||
PyObject *func)
|
|
||||||
{
|
|
||||||
Py_ssize_t nk = PyTuple_GET_SIZE(names);
|
|
||||||
PyObject *kwdict = _PyDict_NewPresized(nk);
|
|
||||||
if (kwdict == NULL)
|
|
||||||
return NULL;
|
|
||||||
while (--nk >= 0) {
|
|
||||||
int err;
|
|
||||||
PyObject *key = PyTuple_GET_ITEM(names, nk);
|
|
||||||
PyObject *value = EXT_POP(*pp_stack);
|
|
||||||
if (PyDict_GetItem(kwdict, key) != NULL) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%.200s%s got multiple values "
|
|
||||||
"for keyword argument '%U'",
|
|
||||||
PyEval_GetFuncName(func),
|
|
||||||
PyEval_GetFuncDesc(func),
|
|
||||||
key);
|
|
||||||
Py_DECREF(value);
|
|
||||||
Py_DECREF(kwdict);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
err = PyDict_SetItem(kwdict, key, value);
|
|
||||||
Py_DECREF(value);
|
|
||||||
if (err) {
|
|
||||||
Py_DECREF(kwdict);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kwdict;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
load_args(PyObject ***pp_stack, Py_ssize_t nargs)
|
|
||||||
{
|
|
||||||
PyObject *args = PyTuple_New(nargs);
|
|
||||||
|
|
||||||
if (args == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (--nargs >= 0) {
|
|
||||||
PyObject *arg= EXT_POP(*pp_stack);
|
|
||||||
PyTuple_SET_ITEM(args, nargs, arg);
|
|
||||||
}
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
|
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue