cpython: a1a29d20f52d (original) (raw)
--- a/Include/abstract.h +++ b/Include/abstract.h @@ -267,10 +267,26 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PyObject *args, PyObject *kw); #ifndef Py_LIMITED_API
/* Call the callable object func with the "fast call" calling convention:[](#l1.10)
args is a C array for positional parameters (nargs is the number of[](#l1.11)
positional paramater), kwargs is a dictionary for keyword parameters.[](#l1.12)
If nargs is equal to zero, args can be NULL. kwargs can be NULL.[](#l1.14)
nargs must be greater or equal to zero.[](#l1.15)
Return the result on success. Raise an exception on return NULL on[](#l1.17)
error. */[](#l1.18)
PyAPI_FUNC(PyObject *) _PyObject_FastCall(PyObject *func,[](#l1.19)
PyObject **args, int nargs,[](#l1.20)
PyObject *kwargs);[](#l1.21)
+ PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char where); -#endif +#endif / Py_LIMITED_API / / Call a callable Python object, callable_object, with
--- a/Include/funcobject.h +++ b/Include/funcobject.h @@ -58,6 +58,13 @@ PyAPI_FUNC(int) PyFunction_SetClosure(Py PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyFunction_FastCall(
+#endif + /* Macros for direct access to these values. Type checks are not done, so use with care. */ #define PyFunction_GET_CODE(func) [](#l2.16)
--- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -37,6 +37,12 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyO #endif PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyCFunction_FastCall(PyObject *func,
+#endif + struct PyMethodDef { const char ml_name; / The name of the built-in function/method / PyCFunction ml_meth; / The C function that implements it */
--- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2193,6 +2193,82 @@ PyObject_Call(PyObject *func, PyObject return _Py_CheckFunctionResult(func, result, NULL); } +PyObject +_PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) +{
- for (i=0; i < nargs; i++) {
PyObject *item = stack[i];[](#l4.19)
Py_INCREF(item);[](#l4.20)
PyTuple_SET_ITEM(args, i, item);[](#l4.21)
- }
+} + +PyObject * +_PyObject_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) +{
- /* _PyObject_FastCall() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the[](#l4.34)
caller loses its exception */[](#l4.35)
- assert(!PyErr_Occurred());
- assert(func != NULL);
- assert(nargs >= 0);
- assert(nargs == 0 || args != NULL);
- /* issue #27128: support for keywords will come later:
_PyFunction_FastCall() doesn't support keyword arguments yet */[](#l4.42)
- assert(kwargs == NULL);
- if (PyFunction_Check(func)) {
result = _PyFunction_FastCall(func, args, nargs, kwargs);[](#l4.50)
- }
- else if (PyCFunction_Check(func)) {
result = _PyCFunction_FastCall(func, args, nargs, kwargs);[](#l4.53)
- }
- else {
PyObject *tuple;[](#l4.56)
/* Slow-path: build a temporary tuple */[](#l4.58)
call = func->ob_type->tp_call;[](#l4.59)
if (call == NULL) {[](#l4.60)
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",[](#l4.61)
func->ob_type->tp_name);[](#l4.62)
goto exit;[](#l4.63)
}[](#l4.64)
tuple = _PyStack_AsTuple(args, nargs);[](#l4.66)
if (tuple == NULL) {[](#l4.67)
goto exit;[](#l4.68)
}[](#l4.69)
+} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) {
--- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -145,6 +145,99 @@ PyCFunction_Call(PyObject *func, PyObjec return _Py_CheckFunctionResult(func, res, NULL); } +PyObject * +_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs,
PyObject *kwargs)[](#l5.9)
- PyCFunctionObject* func = (PyCFunctionObject*)func_obj;
- PyCFunction meth = PyCFunction_GET_FUNCTION(func);
- PyObject *self = PyCFunction_GET_SELF(func);
- PyObject *result;
- int flags;
- /* _PyCFunction_FastCall() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the[](#l5.18)
caller loses its exception */[](#l5.19)
- assert(!PyErr_Occurred());
- switch (flags)
- {
- case METH_NOARGS:
if (kwargs != NULL && PyDict_Size(kwargs) != 0) {[](#l5.27)
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",[](#l5.28)
func->m_ml->ml_name);[](#l5.29)
return NULL;[](#l5.30)
}[](#l5.31)
if (nargs != 0) {[](#l5.33)
PyErr_Format(PyExc_TypeError,[](#l5.34)
"%.200s() takes no arguments (%zd given)",[](#l5.35)
func->m_ml->ml_name, nargs);[](#l5.36)
return NULL;[](#l5.37)
}[](#l5.38)
result = (*meth) (self, NULL);[](#l5.40)
break;[](#l5.41)
- case METH_O:
if (kwargs != NULL && PyDict_Size(kwargs) != 0) {[](#l5.44)
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",[](#l5.45)
func->m_ml->ml_name);[](#l5.46)
return NULL;[](#l5.47)
}[](#l5.48)
if (nargs != 1) {[](#l5.50)
PyErr_Format(PyExc_TypeError,[](#l5.51)
"%.200s() takes exactly one argument (%zd given)",[](#l5.52)
func->m_ml->ml_name, nargs);[](#l5.53)
return NULL;[](#l5.54)
}[](#l5.55)
result = (*meth) (self, args[0]);[](#l5.57)
break;[](#l5.58)
- case METH_VARARGS:
- case METH_VARARGS | METH_KEYWORDS:
- {
/* Slow-path: create a temporary tuple */[](#l5.63)
PyObject *tuple;[](#l5.64)
if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_Size(kwargs) != 0) {[](#l5.66)
PyErr_Format(PyExc_TypeError,[](#l5.67)
"%.200s() takes no keyword arguments",[](#l5.68)
func->m_ml->ml_name);[](#l5.69)
return NULL;[](#l5.70)
}[](#l5.71)
tuple = _PyStack_AsTuple(args, nargs);[](#l5.73)
if (tuple == NULL) {[](#l5.74)
return NULL;[](#l5.75)
}[](#l5.76)
if (flags & METH_KEYWORDS) {[](#l5.78)
result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs);[](#l5.79)
}[](#l5.80)
else {[](#l5.81)
result = (*meth) (self, tuple);[](#l5.82)
}[](#l5.83)
Py_DECREF(tuple);[](#l5.84)
break;[](#l5.85)
- }
- default:
PyErr_SetString(PyExc_SystemError,[](#l5.89)
"Bad call flags in PyCFunction_Call. "[](#l5.90)
"METH_OLDARGS is no longer supported!");[](#l5.91)
return NULL;[](#l5.92)
- }
+} + /* Methods (the standard built-in methods, that is) */ static void
--- a/Python/ceval.c +++ b/Python/ceval.c @@ -113,7 +113,7 @@ static PyObject * call_function(PyObject #else static PyObject * call_function(PyObject ***, int); #endif -static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); +static PyObject * fast_function(PyObject *, PyObject **, int, int, int); static PyObject * do_call(PyObject *, PyObject ***, int, int); static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); static PyObject * update_keyword_args(PyObject *, int, PyObject ***, @@ -3779,6 +3779,7 @@ too_many_positional(PyCodeObject co, in Py_DECREF(kwonly_sig); } + / This is gonna seem real weird, but if you put some other code between PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust the test in the if statements in Misc/gdbinit (pystack and pystackv). */ @@ -4068,8 +4069,10 @@ PyEval_EvalCodeEx(PyObject *_co, PyObjec PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure) { return _PyEval_EvalCodeWithName(_co, globals, locals,
args, argcount, kws, kwcount,[](#l6.24)
defs, defcount, kwdefs, closure,[](#l6.25)
args, argcount,[](#l6.26)
kws, kwcount,[](#l6.27)
defs, defcount,[](#l6.28)
kwdefs, closure,[](#l6.29) NULL, NULL);[](#l6.30)
} @@ -4757,10 +4760,12 @@ call_function(PyObject ***pp_stack, int } else Py_INCREF(func); READ_TIMESTAMP(*pintr0);
if (PyFunction_Check(func))[](#l6.37)
x = fast_function(func, pp_stack, n, na, nk);[](#l6.38)
else[](#l6.39)
if (PyFunction_Check(func)) {[](#l6.40)
x = fast_function(func, (*pp_stack) - n, n, na, nk);[](#l6.41)
}[](#l6.42)
else {[](#l6.43) x = do_call(func, pp_stack, na, nk);[](#l6.44)
}[](#l6.45) READ_TIMESTAMP(*pintr1);[](#l6.46) Py_DECREF(func);[](#l6.47)
@@ -4790,62 +4795,124 @@ call_function(PyObject ***pp_stack, int done before evaluating the frame. / +static PyObject +_PyFunction_FastCallNoKw(PyObject **args, Py_ssize_t na,
PyCodeObject *co, PyObject *globals)[](#l6.55)
- PyFrameObject *f;
- PyThreadState *tstate = PyThreadState_GET();
- PyObject **fastlocals;
- Py_ssize_t i;
- PyObject *result;
- PCALL(PCALL_FASTER_FUNCTION);
- assert(globals != NULL);
- /* XXX Perhaps we should create a specialized
PyFrame_New() that doesn't take locals, but does[](#l6.66)
take builtins without sanity checking them.[](#l6.67)
*/[](#l6.68)
- assert(tstate != NULL);
- f = PyFrame_New(tstate, co, globals, NULL);
- if (f == NULL) {
return NULL;[](#l6.72)
- }
- for (i = 0; i < na; i++) {
Py_INCREF(*args);[](#l6.78)
fastlocals[i] = *args++;[](#l6.79)
- }
- result = PyEval_EvalFrameEx(f,0);
+} + static PyObject * -fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) +fast_function(PyObject *func, PyObject **stack, int n, int na, int nk) { PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); PyObject *globals = PyFunction_GET_GLOBALS(func); PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
- PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func);
- PyObject *name = ((PyFunctionObject *)func) -> func_name;
- PyObject *qualname = ((PyFunctionObject *)func) -> func_qualname;
- PyObject **d = NULL;
- int nd = 0;
PCALL(PCALL_FUNCTION); PCALL(PCALL_FAST_FUNCTION);
- if (argdefs == NULL && co->co_argcount == n &&
co->co_kwonlyargcount == 0 && nk==0 &&[](#l6.109)
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) {[](#l6.110)
PyFrameObject *f;[](#l6.111)
PyObject *retval = NULL;[](#l6.112)
PyThreadState *tstate = PyThreadState_GET();[](#l6.113)
PyObject **fastlocals, **stack;[](#l6.114)
int i;[](#l6.115)
PCALL(PCALL_FASTER_FUNCTION);[](#l6.117)
assert(globals != NULL);[](#l6.118)
/* XXX Perhaps we should create a specialized[](#l6.119)
PyFrame_New() that doesn't take locals, but does[](#l6.120)
take builtins without sanity checking them.[](#l6.121)
*/[](#l6.122)
assert(tstate != NULL);[](#l6.123)
f = PyFrame_New(tstate, co, globals, NULL);[](#l6.124)
if (f == NULL)[](#l6.125)
return NULL;[](#l6.126)
fastlocals = f->f_localsplus;[](#l6.128)
stack = (*pp_stack) - n;[](#l6.129)
for (i = 0; i < n; i++) {[](#l6.131)
Py_INCREF(*stack);[](#l6.132)
fastlocals[i] = *stack++;[](#l6.133)
}[](#l6.134)
retval = PyEval_EvalFrameEx(f,0);[](#l6.135)
++tstate->recursion_depth;[](#l6.136)
Py_DECREF(f);[](#l6.137)
--tstate->recursion_depth;[](#l6.138)
return retval;[](#l6.139)
- if (argdefs == NULL && co->co_argcount == na &&
co->co_kwonlyargcount == 0 && nk == 0 &&[](#l6.142)
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))[](#l6.143)
- {
} +return _PyFunction_FastCallNoKw(stack, na, co, globals);[](#l6.145)
- kwdefs = PyFunction_GET_KW_DEFAULTS(func);
- closure = PyFunction_GET_CLOSURE(func);
- name = ((PyFunctionObject *)func) -> func_name;
- qualname = ((PyFunctionObject *)func) -> func_qualname;
+ if (argdefs != NULL) { d = &PyTuple_GET_ITEM(argdefs, 0); nd = Py_SIZE(argdefs); }
- return _PyEval_EvalCodeWithName((PyObject*)co, globals,
(PyObject *)NULL, (*pp_stack)-n, na,[](#l6.158)
(*pp_stack)-2*nk, nk, d, nd, kwdefs,[](#l6.159)
PyFunction_GET_CLOSURE(func),[](#l6.160)
name, qualname);[](#l6.161)
- else {
d = NULL;[](#l6.163)
nd = 0;[](#l6.164)
- }
- return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
stack, na,[](#l6.167)
stack + na, nk,[](#l6.168)
d, nd, kwdefs,[](#l6.169)
closure, name, qualname);[](#l6.170)
+} + +PyObject * +_PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) +{
- PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
- PyObject *globals = PyFunction_GET_GLOBALS(func);
- PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
- PyObject *kwdefs, *closure, *name, *qualname;
- PyObject **d;
- int nd;
- if (argdefs == NULL && co->co_argcount == nargs &&
co->co_kwonlyargcount == 0 &&[](#l6.190)
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))[](#l6.191)
- {
return _PyFunction_FastCallNoKw(args, nargs, co, globals);[](#l6.193)
- }
- kwdefs = PyFunction_GET_KW_DEFAULTS(func);
- closure = PyFunction_GET_CLOSURE(func);
- name = ((PyFunctionObject *)func) -> func_name;
- qualname = ((PyFunctionObject *)func) -> func_qualname;
- if (argdefs != NULL) {
d = &PyTuple_GET_ITEM(argdefs, 0);[](#l6.202)
nd = Py_SIZE(argdefs);[](#l6.203)
- }
- else {
d = NULL;[](#l6.206)
nd = 0;[](#l6.207)
- }
- return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
args, nargs,[](#l6.210)
NULL, 0,[](#l6.211)
d, nd, kwdefs,[](#l6.212)
closure, name, qualname);[](#l6.213)