Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract __Pyx_PyMethodDescr_Check #5225

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
78 changes: 43 additions & 35 deletions Cython/Utility/CythonFunction.c
Expand Up @@ -1605,54 +1605,62 @@ static int __pyx_FusedFunction_init(PyObject *module) {
return 0;
}

//////////////////// ClassMethod.proto ////////////////////

#include "descrobject.h"
CYTHON_UNUSED static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
//////////////////// PyMethodDescr.proto ////////////////////

//////////////////// ClassMethod ////////////////////
static CYTHON_INLINE int __Pyx_PyMethodDescr_Check(PyObject *method); /*proto*/
static CYTHON_INLINE PyTypeObject *__Pyx_PyMethodDescr_GetType(PyObject *method); /*proto*/

static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
//////////////////// PyMethodDescr ////////////////////

static CYTHON_INLINE int __Pyx_PyMethodDescr_Check(PyObject *method) {
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM <= 0x05080000
if (PyObject_TypeCheck(method, &PyWrapperDescr_Type)) {
// cdef classes
return PyClassMethod_New(method);
}
#else
#if CYTHON_COMPILING_IN_PYPY
return PyObject_TypeCheck(method, &PyWrapperDescr_Type);
#elif CYTHON_COMPILING_IN_PYPY
// special C-API function only in PyPy >= 5.9
if (PyMethodDescr_Check(method))
#else
#if PY_MAJOR_VERSION == 2
return PyMethodDescr_Check(method);
#elif PY_MAJOR_VERSION == 2
// PyMethodDescr_Type is not exposed in the CPython C-API in Py2.
static PyTypeObject *methoddescr_type = NULL;
if (unlikely(methoddescr_type == NULL)) {
PyObject *meth = PyObject_GetAttrString((PyObject*)&PyList_Type, "append");
if (unlikely(!meth)) return NULL;
if (unlikely(!meth)) return 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be an error case, not just false/0.

methoddescr_type = Py_TYPE(meth);
Py_DECREF(meth);
}
#else
PyTypeObject *methoddescr_type = &PyMethodDescr_Type;
#endif
if (__Pyx_TypeCheck(method, methoddescr_type))
return __Pyx_TypeCheck(method, methoddescr_type);
#else
return __Pyx_TypeCheck(method, &PyMethodDescr_Type);
#endif
{
// cdef classes
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
#if PY_VERSION_HEX < 0x03020000
PyTypeObject *d_type = descr->d_type;
#else
PyTypeObject *d_type = descr->d_common.d_type;
#endif
return PyDescr_NewClassMethod(d_type, descr->d_method);
}
}

static CYTHON_INLINE PyTypeObject *__Pyx_PyMethodDescr_GetType(PyObject *method) {
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
#if PY_VERSION_HEX < 0x03020000
return descr->d_type;
#else
return descr->d_common.d_type;
#endif
else if (PyMethod_Check(method)) {
// python classes
return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
}
else {
}


//////////////////// ClassMethod.proto ////////////////////

#include "descrobject.h"
CYTHON_UNUSED static PyObject *__Pyx_Method_ClassMethod(PyObject *method); /*proto*/

//////////////////// ClassMethod ////////////////////
//@requires: PyMethodDescr

static PyObject *__Pyx_Method_ClassMethod(PyObject *method) {
if (__Pyx_PyMethodDescr_Check(method)) // cdef classes
0dminnimda marked this conversation as resolved.
Show resolved Hide resolved
#if CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM <= 0x05080000
return PyClassMethod_New(method);
}
#else
return PyDescr_NewClassMethod(__Pyx_PyMethodDescr_GetType(method),
((PyMethodDescrObject *)method)->d_method);
#endif
if (PyMethod_Check(method)) // python classes
0dminnimda marked this conversation as resolved.
Show resolved Hide resolved
return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
return PyClassMethod_New(method);
}
35 changes: 9 additions & 26 deletions Cython/Utility/ObjectHandling.c
Expand Up @@ -1991,6 +1991,7 @@ typedef struct {

/////////////// UnpackUnboundCMethod ///////////////
//@requires: PyObjectGetAttrStr
//@requires: CythonFunction.c::PyMethodDescr

static PyObject *__Pyx_SelflessCall(PyObject *method, PyObject *args, PyObject *kwargs) {
// NOTE: possible optimization - use vectorcall
Expand All @@ -2015,32 +2016,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
if (unlikely(!method))
return -1;
target->method = method;
// FIXME: use functionality from CythonFunction.c/ClassMethod
#if CYTHON_COMPILING_IN_CPYTHON
#if PY_MAJOR_VERSION >= 3
if (likely(__Pyx_TypeCheck(method, &PyMethodDescr_Type)))
#else
// method descriptor type isn't exported in Py2.x, cannot easily check the type there.
// Therefore, reverse the check to the most likely alternative
// (which is returned for class methods)
if (likely(!PyCFunction_Check(method)))
#endif
{
PyMethodDescrObject *descr = (PyMethodDescrObject*) method;
target->func = descr->d_method->ml_meth;
target->flag = descr->d_method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_STACKLESS);
} else
#endif
// bound classmethods need special treatment
#if defined(CYTHON_COMPILING_IN_PYPY)
// In PyPy functions are regular methods, so just do
// the self check
#elif PY_VERSION_HEX >= 0x03090000
if (PyCFunction_CheckExact(method))
#else
if (PyCFunction_Check(method))
#endif
{
if (__Pyx_PyMethodDescr_Check(method)) {
PyObject *self;
int self_found;
#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_PYPY
Expand All @@ -2063,6 +2039,13 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
target->method = unbound_method;
}
}
#if CYTHON_COMPILING_IN_CPYTHON
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a little bit confused about whether this should remain in the code or not

else {
PyMethodDescrObject *descr = (PyMethodDescrObject*) method;
target->func = descr->d_method->ml_meth;
target->flag = descr->d_method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_STACKLESS);
}
#endif
return 0;
}

Expand Down