Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit ae8b69c

Browse files
committed
Issue python#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.
1 parent 5028938 commit ae8b69c

File tree

5 files changed

+72
-139
lines changed

5 files changed

+72
-139
lines changed

Include/abstract.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,16 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
267267
PyObject *args, PyObject *kwargs);
268268

269269
#ifndef Py_LIMITED_API
270-
PyAPI_FUNC(PyObject*) _PyStack_AsTuple(PyObject **stack,
270+
PyAPI_FUNC(PyObject*) _PyStack_AsTuple(
271+
PyObject **stack,
271272
Py_ssize_t nargs);
272273

274+
PyAPI_FUNC(PyObject *) _PyStack_AsDict(
275+
PyObject **values,
276+
Py_ssize_t nkwargs,
277+
PyObject *kwnames,
278+
PyObject *func);
279+
273280
/* Call the callable object func with the "fast call" calling convention:
274281
args is a C array for positional arguments (nargs is the number of
275282
positional arguments), kwargs is a dictionary for keyword arguments.

Include/methodobject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func,
4242
PyObject **args,
4343
Py_ssize_t nargs,
4444
PyObject *kwargs);
45+
46+
PyAPI_FUNC(PyObject *) _PyCFunction_FastCallKeywords(PyObject *func,
47+
PyObject **stack,
48+
Py_ssize_t nargs,
49+
PyObject *kwnames);
4550
#endif
4651

4752
struct PyMethodDef {

Objects/abstract.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,7 +2366,7 @@ _PyObject_Call_Prepend(PyObject *func,
23662366
return result;
23672367
}
23682368

2369-
static PyObject *
2369+
PyObject *
23702370
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
23712371
PyObject *func)
23722372
{
@@ -2415,10 +2415,13 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
24152415
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
24162416

24172417
if (PyFunction_Check(func)) {
2418-
/* Fast-path: avoid temporary tuple or dict */
24192418
return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
24202419
}
24212420

2421+
if (PyCFunction_Check(func)) {
2422+
return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames);
2423+
}
2424+
24222425
if (nkwargs > 0) {
24232426
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
24242427
if (kwdict == NULL) {

Objects/methodobject.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
155155
PyObject *result;
156156
int flags;
157157

158+
assert(PyCFunction_Check(func));
158159
assert(func != NULL);
159160
assert(nargs >= 0);
160161
assert(nargs == 0 || args != NULL);
@@ -243,6 +244,31 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
243244
return result;
244245
}
245246

247+
PyObject *
248+
_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
249+
Py_ssize_t nargs, PyObject *kwnames)
250+
{
251+
PyObject *kwdict, *result;
252+
Py_ssize_t nkwargs;
253+
254+
assert(PyCFunction_Check(func));
255+
256+
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
257+
if (nkwargs > 0) {
258+
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
259+
if (kwdict == NULL) {
260+
return NULL;
261+
}
262+
}
263+
else {
264+
kwdict = NULL;
265+
}
266+
267+
result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict);
268+
Py_XDECREF(kwdict);
269+
return result;
270+
}
271+
246272
/* Methods (the standard built-in methods, that is) */
247273

248274
static void

Python/ceval.c

Lines changed: 28 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *);
115115
#endif
116116
static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *);
117117
static PyObject * do_call_core(PyObject *, PyObject *, PyObject *);
118-
static PyObject * create_keyword_args(PyObject *, PyObject ***, PyObject *);
119-
static PyObject * load_args(PyObject ***, Py_ssize_t);
120118

121119
#ifdef LLTRACE
122120
static int lltrace;
@@ -4892,21 +4890,6 @@ PyEval_GetFuncDesc(PyObject *func)
48924890
return " object";
48934891
}
48944892

4895-
static void
4896-
err_args(PyObject *func, int flags, Py_ssize_t nargs)
4897-
{
4898-
if (flags & METH_NOARGS)
4899-
PyErr_Format(PyExc_TypeError,
4900-
"%.200s() takes no arguments (%zd given)",
4901-
((PyCFunctionObject *)func)->m_ml->ml_name,
4902-
nargs);
4903-
else
4904-
PyErr_Format(PyExc_TypeError,
4905-
"%.200s() takes exactly one argument (%zd given)",
4906-
((PyCFunctionObject *)func)->m_ml->ml_name,
4907-
nargs);
4908-
}
4909-
49104893
#define C_TRACE(x, call) \
49114894
if (tstate->use_tracing && tstate->c_profilefunc) { \
49124895
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
@@ -4950,91 +4933,49 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames
49504933
PyObject *x, *w;
49514934
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
49524935
Py_ssize_t nargs = oparg - nkwargs;
4936+
PyObject **stack;
49534937

49544938
/* Always dispatch PyCFunction first, because these are
49554939
presumed to be the most frequent callable object.
49564940
*/
49574941
if (PyCFunction_Check(func)) {
4958-
int flags = PyCFunction_GET_FLAGS(func);
49594942
PyThreadState *tstate = PyThreadState_GET();
49604943

49614944
PCALL(PCALL_CFUNCTION);
4962-
if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) {
4963-
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
4964-
PyObject *self = PyCFunction_GET_SELF(func);
4965-
if (flags & METH_NOARGS && nargs == 0) {
4966-
C_TRACE(x, (*meth)(self,NULL));
49674945

4968-
x = _Py_CheckFunctionResult(func, x, NULL);
4969-
}
4970-
else if (flags & METH_O && nargs == 1) {
4971-
PyObject *arg = EXT_POP(*pp_stack);
4972-
C_TRACE(x, (*meth)(self,arg));
4973-
Py_DECREF(arg);
4946+
stack = (*pp_stack) - nargs - nkwargs;
4947+
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
4948+
}
4949+
else {
4950+
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
4951+
/* optimize access to bound methods */
4952+
PyObject *self = PyMethod_GET_SELF(func);
4953+
PCALL(PCALL_METHOD);
4954+
PCALL(PCALL_BOUND_METHOD);
4955+
Py_INCREF(self);
4956+
func = PyMethod_GET_FUNCTION(func);
4957+
Py_INCREF(func);
4958+
Py_SETREF(*pfunc, self);
4959+
nargs++;
4960+
}
4961+
else {
4962+
Py_INCREF(func);
4963+
}
49744964

4975-
x = _Py_CheckFunctionResult(func, x, NULL);
4976-
}
4977-
else {
4978-
err_args(func, flags, nargs);
4979-
x = NULL;
4980-
}
4965+
stack = (*pp_stack) - nargs - nkwargs;
4966+
4967+
READ_TIMESTAMP(*pintr0);
4968+
if (PyFunction_Check(func)) {
4969+
x = fast_function(func, stack, nargs, kwnames);
49814970
}
49824971
else {
4983-
PyObject *callargs, *kwdict = NULL;
4984-
if (kwnames != NULL) {
4985-
kwdict = create_keyword_args(kwnames, pp_stack, func);
4986-
if (kwdict == NULL) {
4987-
x = NULL;
4988-
goto cfuncerror;
4989-
}
4990-
}
4991-
callargs = load_args(pp_stack, nargs);
4992-
if (callargs != NULL) {
4993-
READ_TIMESTAMP(*pintr0);
4994-
C_TRACE(x, PyCFunction_Call(func, callargs, kwdict));
4995-
READ_TIMESTAMP(*pintr1);
4996-
Py_DECREF(callargs);
4997-
}
4998-
else {
4999-
x = NULL;
5000-
}
5001-
Py_XDECREF(kwdict);
4972+
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
50024973
}
5003-
}
5004-
else {
5005-
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
5006-
PyObject **stack;
5007-
5008-
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
5009-
/* optimize access to bound methods */
5010-
PyObject *self = PyMethod_GET_SELF(func);
5011-
PCALL(PCALL_METHOD);
5012-
PCALL(PCALL_BOUND_METHOD);
5013-
Py_INCREF(self);
5014-
func = PyMethod_GET_FUNCTION(func);
5015-
Py_INCREF(func);
5016-
Py_SETREF(*pfunc, self);
5017-
nargs++;
5018-
}
5019-
else {
5020-
Py_INCREF(func);
5021-
}
5022-
5023-
stack = (*pp_stack) - nargs - nkwargs;
5024-
5025-
READ_TIMESTAMP(*pintr0);
5026-
if (PyFunction_Check(func)) {
5027-
x = fast_function(func, stack, nargs, kwnames);
5028-
}
5029-
else {
5030-
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
5031-
}
5032-
READ_TIMESTAMP(*pintr1);
5033-
5034-
Py_DECREF(func);
4974+
READ_TIMESTAMP(*pintr1);
4975+
4976+
Py_DECREF(func);
50354977
}
50364978

5037-
cfuncerror:
50384979
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
50394980

50404981
/* Clear the stack of the function object. Also removes
@@ -5242,55 +5183,6 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
52425183
return result;
52435184
}
52445185

5245-
static PyObject *
5246-
create_keyword_args(PyObject *names, PyObject ***pp_stack,
5247-
PyObject *func)
5248-
{
5249-
Py_ssize_t nk = PyTuple_GET_SIZE(names);
5250-
PyObject *kwdict = _PyDict_NewPresized(nk);
5251-
if (kwdict == NULL)
5252-
return NULL;
5253-
while (--nk >= 0) {
5254-
int err;
5255-
PyObject *key = PyTuple_GET_ITEM(names, nk);
5256-
PyObject *value = EXT_POP(*pp_stack);
5257-
if (PyDict_GetItem(kwdict, key) != NULL) {
5258-
PyErr_Format(PyExc_TypeError,
5259-
"%.200s%s got multiple values "
5260-
"for keyword argument '%U'",
5261-
PyEval_GetFuncName(func),
5262-
PyEval_GetFuncDesc(func),
5263-
key);
5264-
Py_DECREF(value);
5265-
Py_DECREF(kwdict);
5266-
return NULL;
5267-
}
5268-
err = PyDict_SetItem(kwdict, key, value);
5269-
Py_DECREF(value);
5270-
if (err) {
5271-
Py_DECREF(kwdict);
5272-
return NULL;
5273-
}
5274-
}
5275-
return kwdict;
5276-
}
5277-
5278-
static PyObject *
5279-
load_args(PyObject ***pp_stack, Py_ssize_t nargs)
5280-
{
5281-
PyObject *args = PyTuple_New(nargs);
5282-
5283-
if (args == NULL) {
5284-
return NULL;
5285-
}
5286-
5287-
while (--nargs >= 0) {
5288-
PyObject *arg= EXT_POP(*pp_stack);
5289-
PyTuple_SET_ITEM(args, nargs, arg);
5290-
}
5291-
return args;
5292-
}
5293-
52945186
static PyObject *
52955187
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
52965188
{

0 commit comments

Comments
 (0)