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

Commit bf382f2

Browse files
author
Anselm Kruis
committed
Merge branch master into master-slp
Add _PyObject_FastCallKeywords(), cleanup call_function() and fast_function(), remove now useless do_call() The outcome of this merge is not fully functional.
2 parents f2fe5a1 + d873572 commit bf382f2

File tree

4 files changed

+130
-55
lines changed

4 files changed

+130
-55
lines changed

Include/abstract.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
271271
Py_ssize_t nargs);
272272

273273
/* Call the callable object func with the "fast call" calling convention:
274-
args is a C array for positional parameters (nargs is the number of
275-
positional paramater), kwargs is a dictionary for keyword parameters.
274+
args is a C array for positional arguments (nargs is the number of
275+
positional arguments), kwargs is a dictionary for keyword arguments.
276276
277277
If nargs is equal to zero, args can be NULL. kwargs can be NULL.
278278
nargs must be greater or equal to zero.
@@ -283,6 +283,24 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
283283
PyObject **args, Py_ssize_t nargs,
284284
PyObject *kwargs);
285285

286+
/* Call the callable object func with the "fast call" calling convention:
287+
args is a C array for positional arguments followed by values of
288+
keyword arguments. Keys of keyword arguments are stored as a tuple
289+
of strings in kwnames. nargs is the number of positional parameters at
290+
the beginning of stack. The size of kwnames gives the number of keyword
291+
values in the stack after positional arguments.
292+
293+
If nargs is equal to zero and there is no keyword argument (kwnames is
294+
NULL or its size is zero), args can be NULL.
295+
296+
Return the result on success. Raise an exception and return NULL on
297+
error. */
298+
PyAPI_FUNC(PyObject *) _PyObject_FastCallKeywords
299+
(PyObject *func,
300+
PyObject **args,
301+
Py_ssize_t nargs,
302+
PyObject *kwnames);
303+
286304
#define _PyObject_FastCall(func, args, nargs) \
287305
_PyObject_FastCallDict((func), (args), (nargs), NULL)
288306

Include/funcobject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict(
6464
PyObject **args,
6565
Py_ssize_t nargs,
6666
PyObject *kwargs);
67+
68+
PyAPI_FUNC(PyObject *) _PyFunction_FastCallKeywords(
69+
PyObject *func,
70+
PyObject **stack,
71+
Py_ssize_t nargs,
72+
PyObject *kwnames);
6773
#endif
6874

6975
/* Macros for direct access to these values. Type checks are *not*

Objects/abstract.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,74 @@ _PyObject_Call_Prepend(PyObject *func,
24002400
return result;
24012401
}
24022402

2403+
static PyObject *
2404+
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
2405+
PyObject *func)
2406+
{
2407+
PyObject *kwdict;
2408+
Py_ssize_t i;
2409+
2410+
kwdict = PyDict_New();
2411+
if (kwdict == NULL) {
2412+
return NULL;
2413+
}
2414+
2415+
for (i=0; i < nkwargs; i++) {
2416+
int err;
2417+
PyObject *key = PyTuple_GET_ITEM(kwnames, i);
2418+
PyObject *value = *values++;
2419+
2420+
if (PyDict_GetItem(kwdict, key) != NULL) {
2421+
PyErr_Format(PyExc_TypeError,
2422+
"%.200s%s got multiple values "
2423+
"for keyword argument '%U'",
2424+
PyEval_GetFuncName(func),
2425+
PyEval_GetFuncDesc(func),
2426+
key);
2427+
Py_DECREF(kwdict);
2428+
return NULL;
2429+
}
2430+
2431+
err = PyDict_SetItem(kwdict, key, value);
2432+
if (err) {
2433+
Py_DECREF(kwdict);
2434+
return NULL;
2435+
}
2436+
}
2437+
return kwdict;
2438+
}
2439+
2440+
PyObject *
2441+
_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
2442+
PyObject *kwnames)
2443+
{
2444+
PyObject *kwdict, *result;
2445+
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
2446+
2447+
assert(nargs >= 0);
2448+
assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
2449+
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
2450+
2451+
if (PyFunction_Check(func)) {
2452+
/* Fast-path: avoid temporary tuple or dict */
2453+
return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
2454+
}
2455+
2456+
if (nkwargs > 0) {
2457+
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
2458+
if (kwdict == NULL) {
2459+
return NULL;
2460+
}
2461+
}
2462+
else {
2463+
kwdict = NULL;
2464+
}
2465+
2466+
result = _PyObject_FastCallDict(func, stack, nargs, kwdict);
2467+
Py_XDECREF(kwdict);
2468+
return result;
2469+
}
2470+
24032471
static PyObject*
24042472
call_function_tail(PyObject *callable, PyObject *args)
24052473
{

Python/ceval.c

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *, uint64*, u
115115
#else
116116
static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *);
117117
#endif
118-
static PyObject * fast_function(PyObject *, PyObject ***, Py_ssize_t, PyObject *);
119-
static PyObject * do_call(PyObject *, PyObject ***, Py_ssize_t, PyObject *);
118+
static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *);
120119
static PyObject * do_call_core(PyObject *, PyObject *, PyObject *);
121120
static PyObject * create_keyword_args(PyObject *, PyObject ***, PyObject *);
122121
static PyObject * load_args(PyObject ***, Py_ssize_t);
@@ -5440,7 +5439,7 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
54405439
}
54415440

54425441
static PyObject *
5443-
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
5442+
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames
54445443
#ifdef WITH_TSC
54455444
, uint64* pintr0, uint64* pintr1
54465445
#endif
@@ -5449,8 +5448,8 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
54495448
PyObject **pfunc = (*pp_stack) - oparg - 1;
54505449
PyObject *func = *pfunc;
54515450
PyObject *x, *w;
5452-
Py_ssize_t nk = names == NULL ? 0 : PyTuple_GET_SIZE(names);
5453-
Py_ssize_t nargs = oparg - nk;
5451+
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
5452+
Py_ssize_t nargs = oparg - nkwargs;
54545453

54555454
/* Always dispatch PyCFunction first, because these are
54565455
presumed to be the most frequent callable object.
@@ -5460,7 +5459,7 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
54605459
PyThreadState *tstate = PyThreadState_GET();
54615460

54625461
PCALL(PCALL_CFUNCTION);
5463-
if (names == NULL && flags & (METH_NOARGS | METH_O)) {
5462+
if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) {
54645463
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
54655464
PyObject *self = PyCFunction_GET_SELF(func);
54665465
STACKLESS_PROPOSE_FLAG(flags & METH_STACKLESS);
@@ -5484,8 +5483,8 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
54845483
}
54855484
else {
54865485
PyObject *callargs, *kwdict = NULL;
5487-
if (names != NULL) {
5488-
kwdict = create_keyword_args(names, pp_stack, func);
5486+
if (kwnames != NULL) {
5487+
kwdict = create_keyword_args(kwnames, pp_stack, func);
54895488
if (kwdict == NULL) {
54905489
x = NULL;
54915490
goto cfuncerror;
@@ -5507,6 +5506,9 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
55075506
STACKLESS_ASSERT();
55085507
}
55095508
else {
5509+
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
5510+
PyObject **stack;
5511+
55105512
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
55115513
/* optimize access to bound methods */
55125514
PyObject *self = PyMethod_GET_SELF(func);
@@ -5522,13 +5524,16 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
55225524
Py_INCREF(func);
55235525
}
55245526

5527+
stack = (*pp_stack) - nargs - nkwargs;
5528+
55255529
READ_TIMESTAMP(*pintr0);
55265530
if (PyFunction_Check(func)) {
55275531
STACKLESS_PROPOSE_ALL();
5528-
x = fast_function(func, pp_stack, nargs, names);
5532+
x = fast_function(func, stack, nargs, kwnames);
55295533
STACKLESS_ASSERT();
5530-
} else {
5531-
x = do_call(func, pp_stack, nargs, names);
5534+
}
5535+
else {
5536+
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
55325537
}
55335538
READ_TIMESTAMP(*pintr1);
55345539

@@ -5561,8 +5566,8 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
55615566
*/
55625567

55635568
static PyObject*
5564-
_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
5565-
PyObject *globals)
5569+
_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
5570+
PyObject *globals)
55665571
{
55675572
STACKLESS_GETARG();
55685573
PyFrameObject *f;
@@ -5621,19 +5626,19 @@ _PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
56215626
return result;
56225627
}
56235628

5624-
/* Similar to _PyFunction_FastCall() but keywords are passed a (key, value)
5625-
pairs in stack */
56265629
static PyObject *
5627-
fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *names)
5630+
fast_function(PyObject *func, PyObject **stack,
5631+
Py_ssize_t nargs, PyObject *kwnames)
56285632
{
56295633
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
56305634
PyObject *globals = PyFunction_GET_GLOBALS(func);
56315635
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
56325636
PyObject *kwdefs, *closure, *name, *qualname;
56335637
PyObject **d;
5634-
Py_ssize_t nkwargs = names == NULL ? 0 : PyTuple_GET_SIZE(names);
5638+
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
56355639
Py_ssize_t nd;
5636-
PyObject **stack = (*pp_stack)-nargs-nkwargs;
5640+
5641+
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
56375642

56385643
PCALL(PCALL_FUNCTION);
56395644
PCALL(PCALL_FAST_FUNCTION);
@@ -5642,15 +5647,14 @@ fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *
56425647
(co->co_flags & (~PyCF_MASK)) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
56435648
{
56445649
if (argdefs == NULL && co->co_argcount == nargs) {
5645-
return _PyFunction_FastCallNoKw(co, stack, nargs, globals);
5650+
return _PyFunction_FastCall(co, stack, nargs, globals);
56465651
}
56475652
else if (nargs == 0 && argdefs != NULL
56485653
&& co->co_argcount == Py_SIZE(argdefs)) {
56495654
/* function called with no arguments, but all parameters have
56505655
a default value: use default values as arguments .*/
56515656
stack = &PyTuple_GET_ITEM(argdefs, 0);
5652-
return _PyFunction_FastCallNoKw(co, stack, Py_SIZE(argdefs),
5653-
globals);
5657+
return _PyFunction_FastCall(co, stack, Py_SIZE(argdefs), globals);
56545658
}
56555659
}
56565660

@@ -5670,11 +5674,18 @@ fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *
56705674
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
56715675
stack, nargs,
56725676
NULL, 0,
5673-
names, stack + nargs,
5677+
kwnames, stack + nargs,
56745678
d, (int)nd, kwdefs,
56755679
closure, name, qualname);
56765680
}
56775681

5682+
PyObject *
5683+
_PyFunction_FastCallKeywords(PyObject *func, PyObject **stack,
5684+
Py_ssize_t nargs, PyObject *kwnames)
5685+
{
5686+
return fast_function(func, stack, nargs, kwnames);
5687+
}
5688+
56785689
PyObject *
56795690
_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
56805691
PyObject *kwargs)
@@ -5704,7 +5715,7 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
57045715
/* Fast paths */
57055716
if (argdefs == NULL && co->co_argcount == nargs) {
57065717
STACKLESS_PROMOTE_ALL();
5707-
result = _PyFunction_FastCallNoKw(co, args, nargs, globals);
5718+
result = _PyFunction_FastCall(co, args, nargs, globals);
57085719
STACKLESS_ASSERT();
57095720
return result;
57105721
}
@@ -5714,8 +5725,7 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
57145725
a default value: use default values as arguments .*/
57155726
args = &PyTuple_GET_ITEM(argdefs, 0);
57165727
STACKLESS_PROMOTE_ALL();
5717-
result = _PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs),
5718-
globals);
5728+
result = _PyFunction_FastCall(co, args, Py_SIZE(argdefs), globals);
57195729
STACKLESS_ASSERT();
57205730
return result;
57215731
}
@@ -5781,8 +5791,8 @@ create_keyword_args(PyObject *names, PyObject ***pp_stack,
57815791
return NULL;
57825792
while (--nk >= 0) {
57835793
int err;
5784-
PyObject *value = EXT_POP(*pp_stack);
57855794
PyObject *key = PyTuple_GET_ITEM(names, nk);
5795+
PyObject *value = EXT_POP(*pp_stack);
57865796
if (PyDict_GetItem(kwdict, key) != NULL) {
57875797
PyErr_Format(PyExc_TypeError,
57885798
"%.200s%s got multiple values "
@@ -5820,33 +5830,6 @@ load_args(PyObject ***pp_stack, Py_ssize_t nargs)
58205830
return args;
58215831
}
58225832

5823-
static PyObject *
5824-
do_call(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *kwnames)
5825-
{
5826-
PyObject *callargs, *kwdict, *result;
5827-
5828-
if (kwnames != NULL) {
5829-
kwdict = create_keyword_args(kwnames, pp_stack, func);
5830-
if (kwdict == NULL) {
5831-
return NULL;
5832-
}
5833-
}
5834-
else {
5835-
kwdict = NULL;
5836-
}
5837-
5838-
callargs = load_args(pp_stack, nargs);
5839-
if (callargs == NULL) {
5840-
Py_XDECREF(kwdict);
5841-
return NULL;
5842-
}
5843-
5844-
result = do_call_core(func, callargs, kwdict);
5845-
Py_XDECREF(callargs);
5846-
Py_XDECREF(kwdict);
5847-
return result;
5848-
}
5849-
58505833
static PyObject *
58515834
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
58525835
{

0 commit comments

Comments
 (0)