cleanup _PyMethodDef_RawFastCallDict

refer python/cpython@0a2e46835d
refer python/cpython@98ccba8344
refer python/cpython@c89ef828cf
refer python/cpython@250e4b0063
This commit is contained in:
ahgamut 2021-11-05 01:45:44 +05:30
parent 9220b67b3e
commit 7fb46fb510
2 changed files with 39 additions and 97 deletions

View file

@ -2255,7 +2255,7 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
PyObject *result; PyObject *result;
/* PyObject_Call() must not be called with an exception set, /* PyObject_Call() must not be called with an exception set,
because it may 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 */
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
assert(PyTuple_Check(args)); assert(PyTuple_Check(args));
@ -2332,7 +2332,7 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs,
PyObject *result = NULL; 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 may 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 */
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
@ -2505,6 +2505,11 @@ PyObject *
_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs,
PyObject *kwnames) PyObject *kwnames)
{ {
/* _PyObject_FastCallKeywords() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
assert(nargs >= 0); assert(nargs >= 0);
assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
@ -2562,6 +2567,8 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg
Py_DECREF(argtuple); Py_DECREF(argtuple);
Py_XDECREF(kwdict); Py_XDECREF(kwdict);
result = _Py_CheckFunctionResult(callable, result, NULL);
exit: exit:
Py_LeaveRecursiveCall(); Py_LeaveRecursiveCall();
return result; return result;

View file

@ -91,77 +91,12 @@ PyCFunction_GetFlags(PyObject *op)
} }
PyObject * PyObject *
PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs)
{ {
PyCFunctionObject* f = (PyCFunctionObject*)func; return _PyCFunction_FastCallDict(func,
PyCFunction meth = PyCFunction_GET_FUNCTION(func); &PyTuple_GET_ITEM(args, 0),
PyObject *self = PyCFunction_GET_SELF(func); PyTuple_GET_SIZE(args),
PyObject *arg, *res; kwargs);
Py_ssize_t size;
int flags;
assert(kwds == NULL || PyDict_Check(kwds));
/* PyCFunction_Call() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
if (flags == (METH_VARARGS | METH_KEYWORDS)) {
res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds);
}
else if (flags == METH_FASTCALL) {
PyObject **stack = &PyTuple_GET_ITEM(args, 0);
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
res = _PyCFunction_FastCallDict(func, stack, nargs, kwds);
}
else {
if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) {
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
f->m_ml->ml_name);
return NULL;
}
switch (flags) {
case METH_VARARGS:
res = (*meth)(self, args);
break;
case METH_NOARGS:
size = PyTuple_GET_SIZE(args);
if (size != 0) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
f->m_ml->ml_name, size);
return NULL;
}
res = (*meth)(self, NULL);
break;
case METH_O:
size = PyTuple_GET_SIZE(args);
if (size != 1) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%zd given)",
f->m_ml->ml_name, size);
return NULL;
}
arg = PyTuple_GET_ITEM(args, 0);
res = (*meth)(self, arg);
break;
default:
PyErr_SetString(PyExc_SystemError,
"Bad call flags in PyCFunction_Call. "
"METH_OLDARGS is no longer supported!");
return NULL;
}
}
return _Py_CheckFunctionResult(func, res, NULL);
} }
PyObject * PyObject *
@ -171,17 +106,18 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
PyCFunction meth; PyCFunction meth;
PyObject *result; PyObject *result;
int flags; 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(!PyErr_Occurred());
assert(method != NULL); assert(method != NULL);
assert(nargs >= 0); assert(nargs >= 0);
assert(nargs == 0 || args != NULL); assert(nargs == 0 || args != NULL);
assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || PyDict_Check(kwargs));
/* _PyCFunction_FastCallDict() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
meth = method->ml_meth; meth = method->ml_meth;
flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
@ -189,13 +125,14 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
{ {
case METH_NOARGS: case METH_NOARGS:
if (nargs != 0) { if (nargs != 0) {
goto no_keyword_error; PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)",
method->ml_name, nargs);
return NULL;
} }
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", goto no_keyword_error;
method->ml_name);
return NULL;
} }
result = (*meth) (self, NULL); result = (*meth) (self, NULL);
@ -217,30 +154,27 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
break; break;
case METH_VARARGS: case METH_VARARGS:
case METH_VARARGS | METH_KEYWORDS:
{
/* Slow-path: create a temporary tuple for positional arguments */
PyObject *tuple;
if (!(flags & METH_KEYWORDS) if (!(flags & METH_KEYWORDS)
&& kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
goto no_keyword_error; goto no_keyword_error;
} }
/* fall through next case */
tuple = _PyStack_AsTuple(args, nargs); case METH_VARARGS | METH_KEYWORDS:
if (tuple == NULL) { /* Slow-path: create a temporary tuple for positional arguments */
argstuple = _PyStack_AsTuple(args, nargs);
if (argstuple == NULL) {
return NULL; return NULL;
} }
if (flags & METH_KEYWORDS) { if (flags & METH_KEYWORDS) {
result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs);
} }
else { else {
result = (*meth) (self, tuple); result = (*meth) (self, argstuple);
} }
Py_DECREF(tuple); Py_DECREF(argstuple);
break; break;
}
case METH_FASTCALL: case METH_FASTCALL:
{ {
@ -262,7 +196,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
default: default:
PyErr_SetString(PyExc_SystemError, PyErr_SetString(PyExc_SystemError,
"Bad call flags in PyCFunction_Call. " "Bad call flags in _PyMethodDef_RawFastCallDict. "
"METH_OLDARGS is no longer supported!"); "METH_OLDARGS is no longer supported!");
return NULL; return NULL;
} }
@ -271,8 +205,9 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
no_keyword_error: no_keyword_error:
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%zd given)", "%.200s() takes no keyword arguments",
method->ml_name, nargs); method->ml_name, nargs);
return NULL; return NULL;
} }