diff options
Diffstat (limited to 'Objects/methodobject.c')
-rw-r--r-- | Objects/methodobject.c | 295 |
1 files changed, 167 insertions, 128 deletions
diff --git a/Objects/methodobject.c b/Objects/methodobject.c index c2001f0169..35a827e164 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -78,164 +78,90 @@ PyCFunction_GetFlags(PyObject *op) } PyObject * -PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) +PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) { - PyCFunctionObject* f = (PyCFunctionObject*)func; - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - PyObject *arg, *res; - Py_ssize_t size; - int flags; - - /* PyCFunction_Call() 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()); - - 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_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); + return _PyCFunction_FastCallDict(func, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); } PyObject * -_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) +_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwargs) { - PyCFunctionObject *func = (PyCFunctionObject*)func_obj; - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); + PyCFunction meth; PyObject *result; int flags; + PyObject *argstuple; - assert(PyCFunction_Check(func)); - assert(func != NULL); + /* _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(nargs >= 0); assert(nargs == 0 || args != NULL); 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()); - - flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + meth = method->ml_meth; + flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); switch (flags) { case METH_NOARGS: - if (kwargs != NULL && PyDict_Size(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - func->m_ml->ml_name); - return NULL; - } - - if (nargs != 0) { + if (nargs != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; + } + + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; } result = (*meth) (self, NULL); break; case METH_O: - if (kwargs != NULL && PyDict_Size(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - func->m_ml->ml_name); - return NULL; - } - if (nargs != 1) { PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + result = (*meth) (self, args[0]); break; case METH_VARARGS: - case METH_VARARGS | METH_KEYWORDS: - { - /* Slow-path: create a temporary tuple */ - PyObject *tuple; - - if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_Size(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - func->m_ml->ml_name); - return NULL; + if (!(flags & METH_KEYWORDS) + && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; } + /* fall through next case */ - tuple = _PyStack_AsTuple(args, nargs); - if (tuple == NULL) { + case METH_VARARGS | METH_KEYWORDS: + /* Slow-path: create a temporary tuple for positional arguments */ + argstuple = _PyStack_AsTuple(args, nargs); + if (argstuple == NULL) { return NULL; } if (flags & METH_KEYWORDS) { - result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); + result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); } else { - result = (*meth) (self, tuple); + result = (*meth) (self, argstuple); } - Py_DECREF(tuple); + Py_DECREF(argstuple); break; - } case METH_FASTCALL: { @@ -243,8 +169,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames; _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; - stack = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames, func_obj); - if (stack == NULL) { + if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { return NULL; } @@ -258,43 +183,157 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, default: PyErr_SetString(PyExc_SystemError, - "Bad call flags in PyCFunction_Call. " + "Bad call flags in _PyMethodDef_RawFastCallDict. " "METH_OLDARGS is no longer supported!"); return NULL; } - result = _Py_CheckFunctionResult(func_obj, result, NULL); + return result; +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + method->ml_name, nargs); + + return NULL; +} + +PyObject * +_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwargs); + result = _Py_CheckFunctionResult(func, result, NULL); return result; } PyObject * -_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack, +_PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { - PyObject *kwdict, *result; + PyCFunctionObject *func; + PyCFunction meth; + PyObject *self, *result; Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + int flags; - assert(PyCFunction_Check(func)); + assert(func_obj != NULL); + assert(PyCFunction_Check(func_obj)); assert(nargs >= 0); assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); + assert((nargs == 0 && nkwargs == 0) || args != NULL); /* kwnames must only contains str strings, no subclass, and all keys must be unique */ - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { + /* _PyCFunction_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()); + + func = (PyCFunctionObject*)func_obj; + meth = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); + flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + func->m_ml->ml_name, nargs); + return NULL; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + func->m_ml->ml_name, nargs); + return NULL; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, args[0]); + break; + + case METH_FASTCALL: + /* Fast-path: avoid temporary dict to pass keyword arguments */ + result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); + break; + + case METH_VARARGS: + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments + and a temporary dict for keyword arguments */ + PyObject *argtuple; + + if (!(flags & METH_KEYWORDS) && nkwargs) { + goto no_keyword_error; + } + + argtuple = _PyStack_AsTuple(args, nargs); + if (argtuple == NULL) { return NULL; } + + if (flags & METH_KEYWORDS) { + PyObject *kwdict; + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(args + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + return NULL; + } + } + else { + kwdict = NULL; + } + + result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict); + Py_XDECREF(kwdict); + } + else { + result = (*meth) (self, argtuple); + } + Py_DECREF(argtuple); + break; } - else { - kwdict = NULL; + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyCFunction_FastCallKeywords. " + "METH_OLDARGS is no longer supported!"); + return NULL; } - result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict); - Py_XDECREF(kwdict); + result = _Py_CheckFunctionResult(func_obj, result, NULL); return result; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + func->m_ml->ml_name); + return NULL; } /* Methods (the standard built-in methods, that is) */ |