diff options
author | Berker Peksag <berker.peksag@gmail.com> | 2017-02-01 22:37:49 +0300 |
---|---|---|
committer | Berker Peksag <berker.peksag@gmail.com> | 2017-02-01 22:37:49 +0300 |
commit | a706118dafc16edfed490c53db02c08aefe7b097 (patch) | |
tree | 6416a9ea3398ea769857b79a8036f9ffe098c95e /Objects/methodobject.c | |
parent | 1966772d17f49c740be143d9d4622be13e850f15 (diff) | |
parent | ba5a055a00d91a449a23ae14dd468e9b769a6b74 (diff) | |
download | cpython-a706118dafc16edfed490c53db02c08aefe7b097.tar.gz |
Issue #29407: Merge from 3.5
Diffstat (limited to 'Objects/methodobject.c')
-rw-r--r-- | Objects/methodobject.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 946357f24a..c2001f0169 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -97,6 +97,11 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) 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", @@ -145,6 +150,153 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) return _Py_CheckFunctionResult(func, res, NULL); } +PyObject * +_PyCFunction_FastCallDict(PyObject *func_obj, 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); + PyObject *result; + int flags; + + assert(PyCFunction_Check(func)); + assert(func != 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); + + 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) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + func->m_ml->ml_name, nargs); + return NULL; + } + + 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); + return NULL; + } + + 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; + } + + tuple = _PyStack_AsTuple(args, nargs); + if (tuple == NULL) { + return NULL; + } + + if (flags & METH_KEYWORDS) { + result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); + } + else { + result = (*meth) (self, tuple); + } + Py_DECREF(tuple); + break; + } + + case METH_FASTCALL: + { + PyObject **stack; + PyObject *kwnames; + _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; + + stack = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames, func_obj); + if (stack == NULL) { + return NULL; + } + + result = (*fastmeth) (self, stack, nargs, kwnames); + if (stack != args) { + PyMem_Free(stack); + } + Py_XDECREF(kwnames); + break; + } + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in PyCFunction_Call. " + "METH_OLDARGS is no longer supported!"); + return NULL; + } + + result = _Py_CheckFunctionResult(func_obj, result, NULL); + + return result; +} + +PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack, + Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *kwdict, *result; + Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + + assert(PyCFunction_Check(func)); + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + assert((nargs == 0 && nkwargs == 0) || stack != 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) { + return NULL; + } + } + else { + kwdict = NULL; + } + + result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict); + Py_XDECREF(kwdict); + return result; +} + /* Methods (the standard built-in methods, that is) */ static void |