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

Commit 1ec09c4

Browse files
author
Anselm Kruis
committed
Merge branch master into master-slp
Issue python#27810: Add _PyCFunction_FastCallKeywords(). The outcome of this merge is not fully functional.
2 parents c436039 + ae8b69c commit 1ec09c4

File tree

5 files changed

+78
-144
lines changed

5 files changed

+78
-144
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: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,7 +2400,7 @@ _PyObject_Call_Prepend(PyObject *func,
24002400
return result;
24012401
}
24022402

2403-
static PyObject *
2403+
PyObject *
24042404
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
24052405
PyObject *func)
24062406
{
@@ -2450,13 +2450,19 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
24502450
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
24512451

24522452
if (PyFunction_Check(func)) {
2453-
/* Fast-path: avoid temporary tuple or dict */
24542453
STACKLESS_PROMOTE_ALL();
24552454
result = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
24562455
STACKLESS_ASSERT();
24572456
return result;
24582457
}
24592458

2459+
if (PyCFunction_Check(func)) {
2460+
STACKLESS_PROMOTE_ALL();
2461+
result = _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames);
2462+
STACKLESS_ASSERT();
2463+
return result;
2464+
}
2465+
24602466
if (nkwargs > 0) {
24612467
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
24622468
if (kwdict == NULL) {

Objects/methodobject.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
163163
PyObject *result;
164164
int flags;
165165

166+
assert(PyCFunction_Check(func));
166167
assert(func != NULL);
167168
assert(nargs >= 0);
168169
assert(nargs == 0 || args != NULL);
@@ -255,6 +256,31 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
255256
return result;
256257
}
257258

259+
PyObject *
260+
_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
261+
Py_ssize_t nargs, PyObject *kwnames)
262+
{
263+
PyObject *kwdict, *result;
264+
Py_ssize_t nkwargs;
265+
266+
assert(PyCFunction_Check(func));
267+
268+
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
269+
if (nkwargs > 0) {
270+
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
271+
if (kwdict == NULL) {
272+
return NULL;
273+
}
274+
}
275+
else {
276+
kwdict = NULL;
277+
}
278+
279+
result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict);
280+
Py_XDECREF(kwdict);
281+
return result;
282+
}
283+
258284
/* Methods (the standard built-in methods, that is) */
259285

260286
static void

Python/ceval.c

Lines changed: 31 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *);
117117
#endif
118118
static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *);
119119
static PyObject * do_call_core(PyObject *, PyObject *, PyObject *);
120-
static PyObject * create_keyword_args(PyObject *, PyObject ***, PyObject *);
121-
static PyObject * load_args(PyObject ***, Py_ssize_t);
122120

123121
#ifdef LLTRACE
124122
static int lltrace;
@@ -5393,21 +5391,6 @@ PyEval_GetFuncDesc(PyObject *func)
53935391
return " object";
53945392
}
53955393

5396-
static void
5397-
err_args(PyObject *func, int flags, Py_ssize_t nargs)
5398-
{
5399-
if (flags & METH_NOARGS)
5400-
PyErr_Format(PyExc_TypeError,
5401-
"%.200s() takes no arguments (%zd given)",
5402-
((PyCFunctionObject *)func)->m_ml->ml_name,
5403-
nargs);
5404-
else
5405-
PyErr_Format(PyExc_TypeError,
5406-
"%.200s() takes exactly one argument (%zd given)",
5407-
((PyCFunctionObject *)func)->m_ml->ml_name,
5408-
nargs);
5409-
}
5410-
54115394
#define C_TRACE(x, call) \
54125395
if (tstate->use_tracing && tstate->c_profilefunc) { \
54135396
STACKLESS_RETRACT(); \
@@ -5452,97 +5435,53 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames
54525435
PyObject *x, *w;
54535436
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
54545437
Py_ssize_t nargs = oparg - nkwargs;
5438+
PyObject **stack;
54555439

54565440
/* Always dispatch PyCFunction first, because these are
54575441
presumed to be the most frequent callable object.
54585442
*/
54595443
if (PyCFunction_Check(func)) {
5460-
int flags = PyCFunction_GET_FLAGS(func);
54615444
PyThreadState *tstate = PyThreadState_GET();
54625445

54635446
PCALL(PCALL_CFUNCTION);
5464-
if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) {
5465-
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
5466-
PyObject *self = PyCFunction_GET_SELF(func);
5467-
STACKLESS_PROPOSE_FLAG(flags & METH_STACKLESS);
5468-
if (flags & METH_NOARGS && nargs == 0) {
5469-
C_TRACE(x, (*meth)(self,NULL));
54705447

5471-
x = _Py_CheckFunctionResult(func, x, NULL);
5472-
}
5473-
else if (flags & METH_O && nargs == 1) {
5474-
PyObject *arg = EXT_POP(*pp_stack);
5475-
C_TRACE(x, (*meth)(self,arg));
5476-
Py_DECREF(arg);
5448+
stack = (*pp_stack) - nargs - nkwargs;
5449+
STACKLESS_PROPOSE_ALL();
5450+
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
5451+
STACKLESS_ASSERT();
5452+
}
5453+
else {
5454+
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
5455+
/* optimize access to bound methods */
5456+
PyObject *self = PyMethod_GET_SELF(func);
5457+
PCALL(PCALL_METHOD);
5458+
PCALL(PCALL_BOUND_METHOD);
5459+
Py_INCREF(self);
5460+
func = PyMethod_GET_FUNCTION(func);
5461+
Py_INCREF(func);
5462+
Py_SETREF(*pfunc, self);
5463+
nargs++;
5464+
}
5465+
else {
5466+
Py_INCREF(func);
5467+
}
54775468

5478-
x = _Py_CheckFunctionResult(func, x, NULL);
5479-
}
5480-
else {
5481-
STACKLESS_RETRACT();
5482-
err_args(func, flags, nargs);
5483-
x = NULL;
5484-
}
5469+
stack = (*pp_stack) - nargs - nkwargs;
5470+
5471+
STACKLESS_PROPOSE_ALL();
5472+
READ_TIMESTAMP(*pintr0);
5473+
if (PyFunction_Check(func)) {
5474+
x = fast_function(func, stack, nargs, kwnames);
54855475
}
54865476
else {
5487-
PyObject *callargs, *kwdict = NULL;
5488-
if (kwnames != NULL) {
5489-
kwdict = create_keyword_args(kwnames, pp_stack, func);
5490-
if (kwdict == NULL) {
5491-
x = NULL;
5492-
goto cfuncerror;
5493-
}
5494-
}
5495-
callargs = load_args(pp_stack, nargs);
5496-
if (callargs != NULL) {
5497-
READ_TIMESTAMP(*pintr0);
5498-
STACKLESS_PROPOSE_ALL();
5499-
C_TRACE(x, PyCFunction_Call(func, callargs, kwdict));
5500-
READ_TIMESTAMP(*pintr1);
5501-
Py_DECREF(callargs);
5502-
}
5503-
else {
5504-
x = NULL;
5505-
}
5506-
Py_XDECREF(kwdict);
5477+
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
55075478
}
5479+
READ_TIMESTAMP(*pintr1);
55085480
STACKLESS_ASSERT();
5509-
}
5510-
else {
5511-
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
5512-
PyObject **stack;
5513-
5514-
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
5515-
/* optimize access to bound methods */
5516-
PyObject *self = PyMethod_GET_SELF(func);
5517-
PCALL(PCALL_METHOD);
5518-
PCALL(PCALL_BOUND_METHOD);
5519-
Py_INCREF(self);
5520-
func = PyMethod_GET_FUNCTION(func);
5521-
Py_INCREF(func);
5522-
Py_SETREF(*pfunc, self);
5523-
nargs++;
5524-
}
5525-
else {
5526-
Py_INCREF(func);
5527-
}
5528-
5529-
stack = (*pp_stack) - nargs - nkwargs;
5530-
5531-
STACKLESS_PROPOSE_ALL();
5532-
READ_TIMESTAMP(*pintr0);
5533-
if (PyFunction_Check(func)) {
5534-
x = fast_function(func, stack, nargs, kwnames);
5535-
}
5536-
else {
5537-
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
5538-
}
5539-
READ_TIMESTAMP(*pintr1);
5540-
STACKLESS_ASSERT();
5541-
5542-
Py_DECREF(func);
5481+
5482+
Py_DECREF(func);
55435483
}
55445484

5545-
cfuncerror:
55465485
assert((STACKLESS_RETVAL(PyThreadState_GET(), x) != NULL) ^ (PyErr_Occurred() != NULL));
55475486

55485487
/* Clear the stack of the function object. Also removes
@@ -5783,55 +5722,6 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
57835722
return result;
57845723
}
57855724

5786-
static PyObject *
5787-
create_keyword_args(PyObject *names, PyObject ***pp_stack,
5788-
PyObject *func)
5789-
{
5790-
Py_ssize_t nk = PyTuple_GET_SIZE(names);
5791-
PyObject *kwdict = _PyDict_NewPresized(nk);
5792-
if (kwdict == NULL)
5793-
return NULL;
5794-
while (--nk >= 0) {
5795-
int err;
5796-
PyObject *key = PyTuple_GET_ITEM(names, nk);
5797-
PyObject *value = EXT_POP(*pp_stack);
5798-
if (PyDict_GetItem(kwdict, key) != NULL) {
5799-
PyErr_Format(PyExc_TypeError,
5800-
"%.200s%s got multiple values "
5801-
"for keyword argument '%U'",
5802-
PyEval_GetFuncName(func),
5803-
PyEval_GetFuncDesc(func),
5804-
key);
5805-
Py_DECREF(value);
5806-
Py_DECREF(kwdict);
5807-
return NULL;
5808-
}
5809-
err = PyDict_SetItem(kwdict, key, value);
5810-
Py_DECREF(value);
5811-
if (err) {
5812-
Py_DECREF(kwdict);
5813-
return NULL;
5814-
}
5815-
}
5816-
return kwdict;
5817-
}
5818-
5819-
static PyObject *
5820-
load_args(PyObject ***pp_stack, Py_ssize_t nargs)
5821-
{
5822-
PyObject *args = PyTuple_New(nargs);
5823-
5824-
if (args == NULL) {
5825-
return NULL;
5826-
}
5827-
5828-
while (--nargs >= 0) {
5829-
PyObject *arg= EXT_POP(*pp_stack);
5830-
PyTuple_SET_ITEM(args, nargs, arg);
5831-
}
5832-
return args;
5833-
}
5834-
58355725
static PyObject *
58365726
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
58375727
{

0 commit comments

Comments
 (0)