Skip to content

Commit 192690e

Browse files
committed
Inline fast_cfunction() in new call_function().
Also, don't handle METH_OLDARGS on the fast path. All the interesting builtins have been converted to use METH_NOARGS, METH_O, or METH_VARARGS. Result is another 1-2% speedup. If I can cobble together 10 of these, it might make a difference.
1 parent aca139d commit 192690e

1 file changed

Lines changed: 33 additions & 55 deletions

File tree

Python/ceval.c

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
3535
static PyObject *eval_frame(PyFrameObject *);
3636
static PyObject *call_function(PyObject ***, int);
3737
static PyObject *fast_function(PyObject *, PyObject ***, int, int, int);
38-
static PyObject *fast_cfunction(PyObject *, PyObject ***, int);
3938
static PyObject *do_call(PyObject *, PyObject ***, int, int);
4039
static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int);
4140
static PyObject *update_keyword_args(PyObject *, int, PyObject ***,PyObject *);
@@ -3146,6 +3145,21 @@ PyEval_GetFuncDesc(PyObject *func)
31463145

31473146
#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER))
31483147

3148+
void
3149+
err_args(PyObject *func, int flags, int nargs)
3150+
{
3151+
if (flags & METH_NOARGS)
3152+
PyErr_Format(PyExc_TypeError,
3153+
"%.200s() takes 1 argument (%d given)",
3154+
((PyCFunctionObject *)func)->m_ml->ml_name,
3155+
nargs);
3156+
else
3157+
PyErr_Format(PyExc_TypeError,
3158+
"%.200s() takes no arguments (%d given)",
3159+
((PyCFunctionObject *)func)->m_ml->ml_name,
3160+
nargs);
3161+
}
3162+
31493163
static PyObject *
31503164
call_function(PyObject ***pp_stack, int oparg)
31513165
{
@@ -3162,13 +3176,27 @@ call_function(PyObject ***pp_stack, int oparg)
31623176
*/
31633177
if (PyCFunction_Check(func) && nk == 0) {
31643178
int flags = PyCFunction_GET_FLAGS(func);
3165-
if (flags & (METH_VARARGS | METH_KEYWORDS)) {
3179+
if (flags & (METH_NOARGS | METH_O)) {
3180+
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
3181+
PyObject *self = PyCFunction_GET_SELF(func);
3182+
if (flags & METH_NOARGS && na == 0)
3183+
x = (*meth)(self, NULL);
3184+
else if (flags & METH_O && na == 1) {
3185+
PyObject *arg = EXT_POP(*pp_stack);
3186+
x = (*meth)(self, arg);
3187+
Py_DECREF(arg);
3188+
}
3189+
else {
3190+
err_args(func, flags, na);
3191+
x = NULL;
3192+
}
3193+
}
3194+
else {
31663195
PyObject *callargs;
31673196
callargs = load_args(pp_stack, na);
31683197
x = PyCFunction_Call(func, callargs, NULL);
31693198
Py_XDECREF(callargs);
3170-
} else
3171-
x = fast_cfunction(func, pp_stack, na);
3199+
}
31723200
} else {
31733201
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
31743202
/* optimize access to bound methods */
@@ -3196,60 +3224,10 @@ call_function(PyObject ***pp_stack, int oparg)
31963224
return x;
31973225
}
31983226

3199-
/* The two fast_xxx() functions optimize calls for which no argument
3227+
/* The fast_function() function optimize calls for which no argument
32003228
tuple is necessary; the objects are passed directly from the stack.
3201-
fast_cfunction() is called for METH_OLDARGS functions.
3202-
fast_function() is for functions with no special argument handling.
32033229
*/
32043230

3205-
static PyObject *
3206-
fast_cfunction(PyObject *func, PyObject ***pp_stack, int na)
3207-
{
3208-
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
3209-
PyObject *self = PyCFunction_GET_SELF(func);
3210-
int flags = PyCFunction_GET_FLAGS(func);
3211-
3212-
switch (flags) {
3213-
case METH_OLDARGS:
3214-
if (na == 0)
3215-
return (*meth)(self, NULL);
3216-
else if (na == 1) {
3217-
PyObject *arg = EXT_POP(*pp_stack);
3218-
PyObject *result = (*meth)(self, arg);
3219-
Py_DECREF(arg);
3220-
return result;
3221-
} else {
3222-
PyObject *args = load_args(pp_stack, na);
3223-
PyObject *result = (*meth)(self, args);
3224-
Py_DECREF(args);
3225-
return result;
3226-
}
3227-
case METH_NOARGS:
3228-
if (na == 0)
3229-
return (*meth)(self, NULL);
3230-
PyErr_Format(PyExc_TypeError,
3231-
"%.200s() takes no arguments (%d given)",
3232-
((PyCFunctionObject*)func)->m_ml->ml_name, na);
3233-
return NULL;
3234-
case METH_O:
3235-
if (na == 1) {
3236-
PyObject *arg = EXT_POP(*pp_stack);
3237-
PyObject *result = (*meth)(self, arg);
3238-
Py_DECREF(arg);
3239-
return result;
3240-
}
3241-
PyErr_Format(PyExc_TypeError,
3242-
"%.200s() takes exactly one argument (%d given)",
3243-
((PyCFunctionObject*)func)->m_ml->ml_name, na);
3244-
return NULL;
3245-
default:
3246-
fprintf(stderr, "%.200s() flags = %d\n",
3247-
((PyCFunctionObject*)func)->m_ml->ml_name, flags);
3248-
PyErr_BadInternalCall();
3249-
return NULL;
3250-
}
3251-
}
3252-
32533231
static PyObject *
32543232
fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
32553233
{

0 commit comments

Comments
 (0)