[Python-checkins] cpython: Issue #27810: Add _PyCFunction_FastCallKeywords()
victor.stinner
python-checkins at python.org
Fri Sep 9 17:23:12 EDT 2016
https://hg.python.org/cpython/rev/a25c39873d93
changeset: 103467:a25c39873d93
user: Victor Stinner <victor.stinner at gmail.com>
date: Fri Sep 09 14:07:44 2016 -0700
summary:
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.
files:
Include/abstract.h | 9 +-
Include/methodobject.h | 5 +
Objects/abstract.c | 7 +-
Objects/methodobject.c | 26 ++++
Python/ceval.c | 170 +++++-----------------------
5 files changed, 75 insertions(+), 142 deletions(-)
diff --git a/Include/abstract.h b/Include/abstract.h
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -267,9 +267,16 @@
PyObject *args, PyObject *kwargs);
#ifndef Py_LIMITED_API
- PyAPI_FUNC(PyObject*) _PyStack_AsTuple(PyObject **stack,
+ PyAPI_FUNC(PyObject*) _PyStack_AsTuple(
+ PyObject **stack,
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:
args is a C array for positional arguments (nargs is the number of
positional arguments), kwargs is a dictionary for keyword arguments.
diff --git a/Include/methodobject.h b/Include/methodobject.h
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -42,6 +42,11 @@
PyObject **args,
Py_ssize_t nargs,
PyObject *kwargs);
+
+PyAPI_FUNC(PyObject *) _PyCFunction_FastCallKeywords(PyObject *func,
+ PyObject **stack,
+ Py_ssize_t nargs,
+ PyObject *kwnames);
#endif
struct PyMethodDef {
diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2366,7 +2366,7 @@
return result;
}
-static PyObject *
+PyObject *
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
PyObject *func)
{
@@ -2415,10 +2415,13 @@
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
if (PyFunction_Check(func)) {
- /* Fast-path: avoid temporary tuple or dict */
return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
}
+ if (PyCFunction_Check(func)) {
+ return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames);
+ }
+
if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
if (kwdict == NULL) {
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -155,6 +155,7 @@
PyObject *result;
int flags;
+ assert(PyCFunction_Check(func));
assert(func != NULL);
assert(nargs >= 0);
assert(nargs == 0 || args != NULL);
@@ -243,6 +244,31 @@
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) */
static void
diff --git a/Python/ceval.c b/Python/ceval.c
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -115,8 +115,6 @@
#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 @@
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) \
if (tstate->use_tracing && tstate->c_profilefunc) { \
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
@@ -4950,91 +4933,49 @@
PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nargs = oparg - nkwargs;
+ PyObject **stack;
/* 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);
PyThreadState *tstate = PyThreadState_GET();
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);
- }
- 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 {
- 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);
- }
+
+ stack = (*pp_stack) - nargs - nkwargs;
+ C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
else {
- Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
- PyObject **stack;
-
- if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
- /* optimize access to bound methods */
- PyObject *self = PyMethod_GET_SELF(func);
- PCALL(PCALL_METHOD);
- PCALL(PCALL_BOUND_METHOD);
- Py_INCREF(self);
- func = PyMethod_GET_FUNCTION(func);
- Py_INCREF(func);
- Py_SETREF(*pfunc, self);
- nargs++;
- }
- else {
- Py_INCREF(func);
- }
-
- stack = (*pp_stack) - nargs - nkwargs;
-
- READ_TIMESTAMP(*pintr0);
- if (PyFunction_Check(func)) {
- x = fast_function(func, stack, nargs, kwnames);
- }
- else {
- x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
- }
- READ_TIMESTAMP(*pintr1);
-
- Py_DECREF(func);
+ if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
+ /* optimize access to bound methods */
+ PyObject *self = PyMethod_GET_SELF(func);
+ PCALL(PCALL_METHOD);
+ PCALL(PCALL_BOUND_METHOD);
+ Py_INCREF(self);
+ func = PyMethod_GET_FUNCTION(func);
+ Py_INCREF(func);
+ Py_SETREF(*pfunc, self);
+ nargs++;
+ }
+ else {
+ Py_INCREF(func);
+ }
+
+ stack = (*pp_stack) - nargs - nkwargs;
+
+ READ_TIMESTAMP(*pintr0);
+ if (PyFunction_Check(func)) {
+ x = fast_function(func, stack, nargs, kwnames);
+ }
+ else {
+ x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
+ }
+ READ_TIMESTAMP(*pintr1);
+
+ Py_DECREF(func);
}
-cfuncerror:
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
/* Clear the stack of the function object. Also removes
@@ -5243,55 +5184,6 @@
}
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 *
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
{
#ifdef CALL_PROFILE
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list