diff options
Diffstat (limited to 'Objects/methodobject.c')
-rw-r--r-- | Objects/methodobject.c | 107 |
1 files changed, 57 insertions, 50 deletions
diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 9b6e5e4..1817722 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -37,6 +37,7 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) if (op == NULL) return NULL; } + op->m_weakreflist = NULL; op->m_ml = ml; Py_XINCREF(self); op->m_self = self; @@ -77,68 +78,71 @@ PyCFunction_GetFlags(PyObject *op) } PyObject * -PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) +PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) { -#define CHECK_RESULT(res) assert(res != NULL || PyErr_Occurred()) - PyCFunctionObject* f = (PyCFunctionObject*)func; PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); - PyObject *res; + PyObject *arg, *res; Py_ssize_t size; + int flags; - switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) { - case METH_VARARGS: - if (kw == NULL || PyDict_Size(kw) == 0) { - res = (*meth)(self, arg); - CHECK_RESULT(res); - return res; - } - break; - case METH_VARARGS | METH_KEYWORDS: - res = (*(PyCFunctionWithKeywords)meth)(self, arg, kw); - CHECK_RESULT(res); - return res; - case METH_NOARGS: - if (kw == NULL || PyDict_Size(kw) == 0) { - size = PyTuple_GET_SIZE(arg); - if (size == 0) { - res = (*meth)(self, NULL); - CHECK_RESULT(res); - return res; - } - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - f->m_ml->ml_name, size); + /* PyCFunction_Call() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller looses 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 (kwds != NULL && PyDict_Size(kwds) != 0) { + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); return NULL; } - break; - case METH_O: - if (kw == NULL || PyDict_Size(kw) == 0) { - size = PyTuple_GET_SIZE(arg); - if (size == 1) { - res = (*meth)(self, PyTuple_GET_ITEM(arg, 0)); - CHECK_RESULT(res); - return res; + + 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; } - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - f->m_ml->ml_name, size); + + 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; } - break; - default: - PyErr_SetString(PyExc_SystemError, "Bad call flags in " - "PyCFunction_Call. METH_OLDARGS is no " - "longer supported!"); - - return NULL; } - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - f->m_ml->ml_name); - return NULL; -#undef CHECK_RESULT + return _Py_CheckFunctionResult(func, res, NULL); } /* Methods (the standard built-in methods, that is) */ @@ -147,6 +151,9 @@ static void meth_dealloc(PyCFunctionObject *m) { _PyObject_GC_UNTRACK(m); + if (m->m_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject*) m); + } Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); if (numfree < PyCFunction_MAXFREELIST) { @@ -352,7 +359,7 @@ PyTypeObject PyCFunction_Type = { (traverseproc)meth_traverse, /* tp_traverse */ 0, /* tp_clear */ meth_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ + offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ meth_methods, /* tp_methods */ |