assert(PyTuple_Check(args));
assert(kwargs == NULL || PyDict_Check(kwargs));
- call = callable->ob_type->tp_call;
- if (call == NULL) {
- PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
- callable->ob_type->tp_name);
- return NULL;
+ if (PyFunction_Check(callable)) {
+ return _PyFunction_FastCallDict(callable,
+ &PyTuple_GET_ITEM(args, 0),
+ PyTuple_GET_SIZE(args),
+ kwargs);
+ }
+ else if (PyCFunction_Check(callable)) {
+ return PyCFunction_Call(callable, args, kwargs);
}
+ else {
+ call = callable->ob_type->tp_call;
+ if (call == NULL) {
+ PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
+ callable->ob_type->tp_name);
+ return NULL;
+ }
- if (Py_EnterRecursiveCall(" while calling a Python object"))
- return NULL;
+ if (Py_EnterRecursiveCall(" while calling a Python object"))
+ return NULL;
- result = (*call)(callable, args, kwargs);
+ result = (*call)(callable, args, kwargs);
- Py_LeaveRecursiveCall();
+ Py_LeaveRecursiveCall();
- return _Py_CheckFunctionResult(callable, result, NULL);
+ return _Py_CheckFunctionResult(callable, result, NULL);
+ }
}
/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
PyObject *kwargs)
{
- ternaryfunc call;
- PyObject *result = NULL;
-
/* _PyObject_FastCallDict() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(nargs == 0 || args != NULL);
assert(kwargs == NULL || PyDict_Check(kwargs));
- if (Py_EnterRecursiveCall(" while calling a Python object")) {
- return NULL;
- }
-
if (PyFunction_Check(callable)) {
- result = _PyFunction_FastCallDict(callable, args, nargs, kwargs);
+ return _PyFunction_FastCallDict(callable, args, nargs, kwargs);
}
else if (PyCFunction_Check(callable)) {
- result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
+ return _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
}
else {
- PyObject *tuple;
+ PyObject *argstuple, *result;
+ ternaryfunc call;
/* Slow-path: build a temporary tuple */
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
- goto exit;
+ return NULL;
}
- tuple = _PyStack_AsTuple(args, nargs);
- if (tuple == NULL) {
- goto exit;
+ argstuple = _PyStack_AsTuple(args, nargs);
+ if (argstuple == NULL) {
+ return NULL;
}
- result = (*call)(callable, tuple, kwargs);
- Py_DECREF(tuple);
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
- result = _Py_CheckFunctionResult(callable, result, NULL);
- }
+ result = (*call)(callable, argstuple, kwargs);
-exit:
- Py_LeaveRecursiveCall();
+ Py_LeaveRecursiveCall();
- return result;
+ Py_DECREF(argstuple);
+ result = _Py_CheckFunctionResult(callable, result, NULL);
+ return result;
+ }
}
/* Positional arguments are obj followed by args:
temporary dictionary for keyword arguments (if any) */
ternaryfunc call;
- PyObject *argtuple;
+ PyObject *argstuple;
PyObject *kwdict, *result;
Py_ssize_t nkwargs;
- result = NULL;
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
- if (Py_EnterRecursiveCall(" while calling a Python object")) {
- return NULL;
- }
-
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
- goto exit;
+ return NULL;
}
- argtuple = _PyStack_AsTuple(stack, nargs);
- if (argtuple == NULL) {
- goto exit;
+ argstuple = _PyStack_AsTuple(stack, nargs);
+ if (argstuple == NULL) {
+ return NULL;
}
if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
if (kwdict == NULL) {
- Py_DECREF(argtuple);
- goto exit;
+ Py_DECREF(argstuple);
+ return NULL;
}
}
else {
kwdict = NULL;
}
- result = (*call)(callable, argtuple, kwdict);
- Py_DECREF(argtuple);
- Py_XDECREF(kwdict);
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
- result = _Py_CheckFunctionResult(callable, result, NULL);
+ result = (*call)(callable, argstuple, kwdict);
- exit:
Py_LeaveRecursiveCall();
+
+ Py_DECREF(argstuple);
+ Py_XDECREF(kwdict);
+
+ result = _Py_CheckFunctionResult(callable, result, NULL);
return result;
}
}
_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args,
Py_ssize_t nargs, PyObject *kwargs)
{
- PyCFunction meth;
- PyObject *result;
- int flags;
- PyObject *argstuple;
-
/* _PyMethodDef_RawFastCallDict() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(nargs == 0 || args != NULL);
assert(kwargs == NULL || PyDict_Check(kwargs));
- meth = method->ml_meth;
- flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
+ PyCFunction meth = method->ml_meth;
+ int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
+ PyObject *result = NULL;
+
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
switch (flags)
{
case METH_NOARGS:
- if (nargs != 0) {
+ if (nargs != 0) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
method->ml_name, nargs);
- return NULL;
- }
+ goto exit;
+ }
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
goto no_keyword_error;
PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)",
method->ml_name, nargs);
- return NULL;
+ goto exit;
}
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
/* fall through next case */
case METH_VARARGS | METH_KEYWORDS:
+ {
/* Slow-path: create a temporary tuple for positional arguments */
- argstuple = _PyStack_AsTuple(args, nargs);
+ PyObject *argstuple = _PyStack_AsTuple(args, nargs);
if (argstuple == NULL) {
- return NULL;
+ goto exit;
}
if (flags & METH_KEYWORDS) {
}
Py_DECREF(argstuple);
break;
+ }
case METH_FASTCALL:
{
_PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
- return NULL;
+ goto exit;
}
result = (*fastmeth) (self, stack, nargs, kwnames);
PyErr_SetString(PyExc_SystemError,
"Bad call flags in _PyMethodDef_RawFastCallDict. "
"METH_OLDARGS is no longer supported!");
- return NULL;
+ goto exit;
}
- return result;
+ goto exit;
no_keyword_error:
PyErr_Format(PyExc_TypeError,
"%.200s() takes no keyword arguments",
method->ml_name, nargs);
- return NULL;
+exit:
+ Py_LeaveRecursiveCall();
+ return result;
}
PyObject *
PyCFunction meth = method->ml_meth;
int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames);
- PyObject *result;
+ PyObject *result = NULL;
+
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
switch (flags)
{
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
method->ml_name, nargs);
- return NULL;
+ goto exit;
}
if (nkwargs) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)",
method->ml_name, nargs);
- return NULL;
+ goto exit;
}
if (nkwargs) {
argtuple = _PyStack_AsTuple(args, nargs);
if (argtuple == NULL) {
- return NULL;
+ goto exit;
}
if (flags & METH_KEYWORDS) {
kwdict = _PyStack_AsDict(args + nargs, kwnames);
if (kwdict == NULL) {
Py_DECREF(argtuple);
- return NULL;
+ goto exit;
}
}
else {
PyErr_SetString(PyExc_SystemError,
"Bad call flags in _PyCFunction_FastCallKeywords. "
"METH_OLDARGS is no longer supported!");
- return NULL;
+ goto exit;
}
- return result;
+ goto exit;
no_keyword_error:
PyErr_Format(PyExc_TypeError,
"%.200s() takes no keyword arguments",
method->ml_name);
- return NULL;
+
+exit:
+ Py_LeaveRecursiveCall();
+ return result;
}
PyObject *