Issue #29306: Fix usage of Py_EnterRecursiveCall()
* *PyCFunction_*Call*() functions now call Py_EnterRecursiveCall(). * PyObject_Call() now calls directly _PyFunction_FastCallDict() and PyCFunction_Call() to avoid calling Py_EnterRecursiveCall() twice per function call
This commit is contained in:
parent
ee0ee9ae8e
commit
7399a05965
|
@ -2239,21 +2239,32 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
|
|||
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
|
||||
|
@ -2305,9 +2316,6 @@ PyObject *
|
|||
_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 */
|
||||
|
@ -2318,42 +2326,41 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
|
|||
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 = (*call)(callable, argstuple, kwargs);
|
||||
|
||||
Py_LeaveRecursiveCall();
|
||||
|
||||
Py_DECREF(argstuple);
|
||||
result = _Py_CheckFunctionResult(callable, result, NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
exit:
|
||||
Py_LeaveRecursiveCall();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Positional arguments are obj followed by args:
|
||||
|
@ -2506,49 +2513,48 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg
|
|||
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);
|
||||
if (Py_EnterRecursiveCall(" while calling a Python object")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = (*call)(callable, argstuple, kwdict);
|
||||
|
||||
Py_LeaveRecursiveCall();
|
||||
|
||||
Py_DECREF(argstuple);
|
||||
Py_XDECREF(kwdict);
|
||||
|
||||
result = _Py_CheckFunctionResult(callable, result, NULL);
|
||||
|
||||
exit:
|
||||
Py_LeaveRecursiveCall();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,11 +90,6 @@ PyObject *
|
|||
_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 */
|
||||
|
@ -105,18 +100,23 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
|||
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;
|
||||
|
@ -130,7 +130,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
|||
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) {
|
||||
|
@ -148,10 +148,11 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
|||
/* 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) {
|
||||
|
@ -162,6 +163,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
|||
}
|
||||
Py_DECREF(argstuple);
|
||||
break;
|
||||
}
|
||||
|
||||
case METH_FASTCALL:
|
||||
{
|
||||
|
@ -170,7 +172,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
|||
_PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
|
||||
|
||||
if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
|
||||
return NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
result = (*fastmeth) (self, stack, nargs, kwnames);
|
||||
|
@ -185,17 +187,19 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
|||
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 *
|
||||
|
@ -232,7 +236,11 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, 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)
|
||||
{
|
||||
|
@ -241,7 +249,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
|
|||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no arguments (%zd given)",
|
||||
method->ml_name, nargs);
|
||||
return NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nkwargs) {
|
||||
|
@ -256,7 +264,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
|
|||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes exactly one argument (%zd given)",
|
||||
method->ml_name, nargs);
|
||||
return NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nkwargs) {
|
||||
|
@ -284,7 +292,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
|
|||
|
||||
argtuple = _PyStack_AsTuple(args, nargs);
|
||||
if (argtuple == NULL) {
|
||||
return NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (flags & METH_KEYWORDS) {
|
||||
|
@ -294,7 +302,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
|
|||
kwdict = _PyStack_AsDict(args + nargs, kwnames);
|
||||
if (kwdict == NULL) {
|
||||
Py_DECREF(argtuple);
|
||||
return NULL;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -315,16 +323,19 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
|
|||
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 *
|
||||
|
|
Loading…
Reference in New Issue