mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-07 02:10:27 +00:00
recursive calls in PyObject_Call
refer python/cpython@7399a05965 only partially ported, because RawFastCallKeywords hasn't been ported
This commit is contained in:
parent
4959ac1497
commit
4eb67fa2c5
2 changed files with 75 additions and 65 deletions
78
third_party/python/Objects/abstract.c
vendored
78
third_party/python/Objects/abstract.c
vendored
|
@ -2261,6 +2261,16 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
|
||||||
assert(PyTuple_Check(args));
|
assert(PyTuple_Check(args));
|
||||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||||
|
|
||||||
|
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;
|
call = callable->ob_type->tp_call;
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
|
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
|
||||||
|
@ -2277,6 +2287,7 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
|
||||||
|
|
||||||
return _Py_CheckFunctionResult(callable, result, NULL);
|
return _Py_CheckFunctionResult(callable, result, NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
|
/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
|
||||||
stack consumption, Disable inlining to optimize the stack consumption. */
|
stack consumption, Disable inlining to optimize the stack consumption. */
|
||||||
|
@ -2328,9 +2339,6 @@ PyObject *
|
||||||
_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
|
_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
|
||||||
PyObject *kwargs)
|
PyObject *kwargs)
|
||||||
{
|
{
|
||||||
ternaryfunc call;
|
|
||||||
PyObject *result = NULL;
|
|
||||||
|
|
||||||
/* _PyObject_FastCallDict() must not be called with an exception set,
|
/* _PyObject_FastCallDict() must not be called with an exception set,
|
||||||
because it can clear it (directly or indirectly) and so the
|
because it can clear it (directly or indirectly) and so the
|
||||||
caller loses its exception */
|
caller loses its exception */
|
||||||
|
@ -2341,43 +2349,42 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
|
||||||
assert(nargs == 0 || args != NULL);
|
assert(nargs == 0 || args != NULL);
|
||||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||||
|
|
||||||
if (Py_EnterRecursiveCall(" while calling a Python object")) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyFunction_Check(callable)) {
|
if (PyFunction_Check(callable)) {
|
||||||
result = _PyFunction_FastCallDict(callable, args, nargs, kwargs);
|
return _PyFunction_FastCallDict(callable, args, nargs, kwargs);
|
||||||
}
|
}
|
||||||
else if (PyCFunction_Check(callable)) {
|
else if (PyCFunction_Check(callable)) {
|
||||||
result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
|
return _PyCFunction_FastCallDict(callable, args, nargs, kwargs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *tuple;
|
PyObject *argstuple, *result;
|
||||||
|
ternaryfunc call;
|
||||||
|
|
||||||
/* Slow-path: build a temporary tuple */
|
/* Slow-path: build a temporary tuple */
|
||||||
call = callable->ob_type->tp_call;
|
call = callable->ob_type->tp_call;
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
|
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
|
||||||
callable->ob_type->tp_name);
|
callable->ob_type->tp_name);
|
||||||
goto exit;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple = _PyStack_AsTuple(args, nargs);
|
argstuple = _PyStack_AsTuple(args, nargs);
|
||||||
if (tuple == NULL) {
|
if (argstuple == NULL) {
|
||||||
goto exit;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (*call)(callable, tuple, kwargs);
|
if (Py_EnterRecursiveCall(" while calling a Python object")) {
|
||||||
Py_DECREF(tuple);
|
return NULL;
|
||||||
|
|
||||||
result = _Py_CheckFunctionResult(callable, result, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
result = (*call)(callable, argstuple, kwargs);
|
||||||
|
|
||||||
Py_LeaveRecursiveCall();
|
Py_LeaveRecursiveCall();
|
||||||
|
|
||||||
|
Py_DECREF(argstuple);
|
||||||
|
result = _Py_CheckFunctionResult(callable, result, NULL);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Positional arguments are obj followed by args:
|
/* Positional arguments are obj followed by args:
|
||||||
call callable(obj, *args, **kwargs) */
|
call callable(obj, *args, **kwargs) */
|
||||||
|
@ -2528,49 +2535,48 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg
|
||||||
temporary dictionary for keyword arguments (if any) */
|
temporary dictionary for keyword arguments (if any) */
|
||||||
|
|
||||||
ternaryfunc call;
|
ternaryfunc call;
|
||||||
PyObject *argtuple;
|
PyObject *argstuple;
|
||||||
PyObject *kwdict, *result;
|
PyObject *kwdict, *result;
|
||||||
Py_ssize_t nkwargs;
|
Py_ssize_t nkwargs;
|
||||||
|
|
||||||
result = NULL;
|
|
||||||
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
||||||
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
|
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
|
||||||
|
|
||||||
if (Py_EnterRecursiveCall(" while calling a Python object")) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
call = callable->ob_type->tp_call;
|
call = callable->ob_type->tp_call;
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
|
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
|
||||||
callable->ob_type->tp_name);
|
callable->ob_type->tp_name);
|
||||||
goto exit;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
argtuple = _PyStack_AsTuple(stack, nargs);
|
argstuple = _PyStack_AsTuple(stack, nargs);
|
||||||
if (argtuple == NULL) {
|
if (argstuple == NULL) {
|
||||||
goto exit;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nkwargs > 0) {
|
if (nkwargs > 0) {
|
||||||
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
|
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
|
||||||
if (kwdict == NULL) {
|
if (kwdict == NULL) {
|
||||||
Py_DECREF(argtuple);
|
Py_DECREF(argstuple);
|
||||||
goto exit;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
kwdict = NULL;
|
kwdict = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (*call)(callable, argtuple, kwdict);
|
if (Py_EnterRecursiveCall(" while calling a Python object")) {
|
||||||
Py_DECREF(argtuple);
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = (*call)(callable, argstuple, kwdict);
|
||||||
|
|
||||||
|
Py_LeaveRecursiveCall();
|
||||||
|
|
||||||
|
Py_DECREF(argstuple);
|
||||||
Py_XDECREF(kwdict);
|
Py_XDECREF(kwdict);
|
||||||
|
|
||||||
result = _Py_CheckFunctionResult(callable, result, NULL);
|
result = _Py_CheckFunctionResult(callable, result, NULL);
|
||||||
|
|
||||||
exit:
|
|
||||||
Py_LeaveRecursiveCall();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
third_party/python/Objects/methodobject.c
vendored
34
third_party/python/Objects/methodobject.c
vendored
|
@ -103,11 +103,6 @@ PyObject *
|
||||||
_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args,
|
_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args,
|
||||||
Py_ssize_t nargs, PyObject *kwargs)
|
Py_ssize_t nargs, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
PyCFunction meth;
|
|
||||||
PyObject *result;
|
|
||||||
int flags;
|
|
||||||
PyObject *argstuple;
|
|
||||||
|
|
||||||
/* _PyMethodDef_RawFastCallDict() must not be called with an exception set,
|
/* _PyMethodDef_RawFastCallDict() must not be called with an exception set,
|
||||||
because it can clear it (directly or indirectly) and so the
|
because it can clear it (directly or indirectly) and so the
|
||||||
caller loses its exception */
|
caller loses its exception */
|
||||||
|
@ -118,8 +113,13 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
assert(nargs == 0 || args != NULL);
|
assert(nargs == 0 || args != NULL);
|
||||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||||
|
|
||||||
meth = method->ml_meth;
|
PyCFunction meth = method->ml_meth;
|
||||||
flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
|
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)
|
switch (flags)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +128,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s() takes no arguments (%zd given)",
|
"%.200s() takes no arguments (%zd given)",
|
||||||
method->ml_name, nargs);
|
method->ml_name, nargs);
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
|
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
|
||||||
|
@ -143,7 +143,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s() takes exactly one argument (%zd given)",
|
"%.200s() takes exactly one argument (%zd given)",
|
||||||
method->ml_name, nargs);
|
method->ml_name, nargs);
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
|
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
|
||||||
|
@ -161,10 +161,11 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
/* fall through next case */
|
/* fall through next case */
|
||||||
|
|
||||||
case METH_VARARGS | METH_KEYWORDS:
|
case METH_VARARGS | METH_KEYWORDS:
|
||||||
|
{
|
||||||
/* Slow-path: create a temporary tuple for positional arguments */
|
/* Slow-path: create a temporary tuple for positional arguments */
|
||||||
argstuple = _PyStack_AsTuple(args, nargs);
|
PyObject *argstuple = _PyStack_AsTuple(args, nargs);
|
||||||
if (argstuple == NULL) {
|
if (argstuple == NULL) {
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & METH_KEYWORDS) {
|
if (flags & METH_KEYWORDS) {
|
||||||
|
@ -175,6 +176,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
}
|
}
|
||||||
Py_DECREF(argstuple);
|
Py_DECREF(argstuple);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case METH_FASTCALL:
|
case METH_FASTCALL:
|
||||||
{
|
{
|
||||||
|
@ -183,7 +185,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
_PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
|
_PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
|
||||||
|
|
||||||
if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
|
if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (*fastmeth) (self, stack, nargs, kwnames);
|
result = (*fastmeth) (self, stack, nargs, kwnames);
|
||||||
|
@ -198,17 +200,19 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
"Bad call flags in _PyMethodDef_RawFastCallDict. "
|
"Bad call flags in _PyMethodDef_RawFastCallDict. "
|
||||||
"METH_OLDARGS is no longer supported!");
|
"METH_OLDARGS is no longer supported!");
|
||||||
return NULL;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
goto exit;
|
||||||
|
|
||||||
no_keyword_error:
|
no_keyword_error:
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s() takes no keyword arguments",
|
"%.200s() takes no keyword arguments",
|
||||||
method->ml_name, nargs);
|
method->ml_name, nargs);
|
||||||
|
|
||||||
return NULL;
|
exit:
|
||||||
|
Py_LeaveRecursiveCall();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue