Commit 3e8d6a04 authored by Stefan Behnel's avatar Stefan Behnel

Reimplement specialised method call helpers to avoid instantiating a bound method object.

parent 8f2c9f88
...@@ -1402,6 +1402,105 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr ...@@ -1402,6 +1402,105 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr
#endif #endif
/////////////// PyObjectGetMethod.proto ///////////////
#if CYTHON_UNPACK_METHODS
static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method);/*proto*/
#endif
/////////////// PyObjectGetMethod ///////////////
//@requires: PyObjectGetAttrStr
#if CYTHON_UNPACK_METHODS
static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) {
#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP
// Copied from _PyObject_GetMethod() in CPython 3.7
PyTypeObject *tp = Py_TYPE(obj);
PyObject *descr;
descrgetfunc f = NULL;
PyObject **dictptr, *dict;
PyObject *attr;
int meth_found = 0;
assert (*method == NULL);
if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) {
*method = __Pyx_PyObject_GetAttrStr(obj, name);
return 0;
}
if (unlikely(tp->tp_dict == NULL && PyType_Ready(tp) < 0)) {
return 0;
}
descr = _PyType_Lookup(tp, name);
if (likely(descr != NULL)) {
Py_INCREF(descr);
if (likely(PyFunction_Check(descr)
#if PY_MAJOR_VERSION >= 3
// "PyMethodDescr_Type" is not part of the C-API in Py2.
|| (Py_TYPE(descr) == &PyMethodDescr_Type)
#endif
)) {
meth_found = 1;
} else {
f = Py_TYPE(descr)->tp_descr_get;
if (f != NULL && PyDescr_IsData(descr)) {
*method = f(descr, obj, (PyObject *)Py_TYPE(obj));
Py_DECREF(descr);
return 0;
}
}
}
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr != NULL && (dict = *dictptr) != NULL) {
Py_INCREF(dict);
attr = __Pyx_PyDict_GetItemStr(dict, name);
if (attr != NULL) {
Py_INCREF(attr);
*method = attr;
Py_DECREF(dict);
Py_XDECREF(descr);
return 0;
}
Py_DECREF(dict);
}
if (meth_found) {
*method = descr;
return 1;
}
if (f != NULL) {
*method = f(descr, obj, (PyObject *)Py_TYPE(obj));
Py_DECREF(descr);
return 0;
}
if (descr != NULL) {
*method = descr;
return 0;
}
PyErr_Format(PyExc_AttributeError,
#if PY_MAJOR_VERSION >= 3
"'%.50s' object has no attribute '%U'",
tp->tp_name, name);
#else
"'%.50s' object has no attribute '%.400s'",
tp->tp_name, PyString_AS_STRING(name));
#endif
return 0;
// Generic fallback implementation using normal attribute lookup.
#else
*method = __Pyx_PyObject_GetAttrStr(obj, name);
return 0;
#endif
}
#endif
/////////////// UnpackUnboundCMethod.proto /////////////// /////////////// UnpackUnboundCMethod.proto ///////////////
typedef struct { typedef struct {
...@@ -1628,25 +1727,24 @@ bad: ...@@ -1628,25 +1727,24 @@ bad:
static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); /*proto*/ static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); /*proto*/
/////////////// PyObjectCallMethod0 /////////////// /////////////// PyObjectCallMethod0 ///////////////
//@requires: PyObjectGetMethod
//@requires: PyObjectGetAttrStr //@requires: PyObjectGetAttrStr
//@requires: PyObjectCallOneArg //@requires: PyObjectCallOneArg
//@requires: PyObjectCallNoArg //@requires: PyObjectCallNoArg
static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) { static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) {
PyObject *method, *result = NULL; PyObject *method = NULL, *result = NULL;
method = __Pyx_PyObject_GetAttrStr(obj, method_name);
if (unlikely(!method)) goto bad;
#if CYTHON_UNPACK_METHODS #if CYTHON_UNPACK_METHODS
if (likely(PyMethod_Check(method))) { int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
PyObject *self = PyMethod_GET_SELF(method); if (likely(is_method)) {
if (likely(self)) { result = __Pyx_PyObject_CallOneArg(method, obj);
PyObject *function = PyMethod_GET_FUNCTION(method); Py_DECREF(method);
result = __Pyx_PyObject_CallOneArg(function, self); return result;
Py_DECREF(method);
return result;
}
} }
#else
method = __Pyx_PyObject_GetAttrStr(obj, method_name);
#endif #endif
if (unlikely(!method)) goto bad;
result = __Pyx_PyObject_CallNoArg(method); result = __Pyx_PyObject_CallNoArg(method);
Py_DECREF(method); Py_DECREF(method);
bad: bad:
...@@ -1660,10 +1758,10 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name ...@@ -1660,10 +1758,10 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name
static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg); /*proto*/ static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg); /*proto*/
/////////////// PyObjectCallMethod1 /////////////// /////////////// PyObjectCallMethod1 ///////////////
//@requires: PyObjectGetMethod
//@requires: PyObjectGetAttrStr //@requires: PyObjectGetAttrStr
//@requires: PyObjectCallOneArg //@requires: PyObjectCallOneArg
//@requires: PyFunctionFastCall //@requires: PyObjectCall2Args
//@requires: PyCFunctionFastCall
static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) {
PyObject *result = NULL; PyObject *result = NULL;
...@@ -1671,46 +1769,27 @@ static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { ...@@ -1671,46 +1769,27 @@ static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) {
if (likely(PyMethod_Check(method))) { if (likely(PyMethod_Check(method))) {
PyObject *self = PyMethod_GET_SELF(method); PyObject *self = PyMethod_GET_SELF(method);
if (likely(self)) { if (likely(self)) {
PyObject *args;
PyObject *function = PyMethod_GET_FUNCTION(method); PyObject *function = PyMethod_GET_FUNCTION(method);
#if CYTHON_FAST_PYCALL return __Pyx_PyObject_Call2Args(function, self, arg);
if (PyFunction_Check(function)) {
PyObject *args[2] = {self, arg};
result = __Pyx_PyFunction_FastCall(function, args, 2);
goto done;
}
#endif
#if CYTHON_FAST_PYCCALL
if (__Pyx_PyFastCFunction_Check(function)) {
PyObject *args[2] = {self, arg};
result = __Pyx_PyCFunction_FastCall(function, args, 2);
goto done;
}
#endif
args = PyTuple_New(2);
if (unlikely(!args)) goto done;
Py_INCREF(self);
PyTuple_SET_ITEM(args, 0, self);
Py_INCREF(arg);
PyTuple_SET_ITEM(args, 1, arg);
Py_INCREF(function);
result = __Pyx_PyObject_Call(function, args, NULL);
Py_DECREF(args);
Py_DECREF(function);
return result;
} }
} }
#endif #endif
result = __Pyx_PyObject_CallOneArg(method, arg); result = __Pyx_PyObject_CallOneArg(method, arg);
// avoid "unused label" warning
goto done;
done:
return result; return result;
} }
static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
PyObject *method, *result; PyObject *method = NULL, *result;
#if CYTHON_UNPACK_METHODS
int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
if (likely(is_method)) {
result = __Pyx_PyObject_Call2Args(method, obj, arg);
Py_DECREF(method);
return result;
}
#else
method = __Pyx_PyObject_GetAttrStr(obj, method_name); method = __Pyx_PyObject_GetAttrStr(obj, method_name);
#endif
if (unlikely(!method)) return NULL; if (unlikely(!method)) return NULL;
result = __Pyx__PyObject_CallMethod1(method, arg); result = __Pyx__PyObject_CallMethod1(method, arg);
Py_DECREF(method); Py_DECREF(method);
...@@ -1727,68 +1806,64 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name ...@@ -1727,68 +1806,64 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name
//@requires: PyObjectCall //@requires: PyObjectCall
//@requires: PyFunctionFastCall //@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall //@requires: PyCFunctionFastCall
//@requires: PyObjectCall2Args
static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2) { #if CYTHON_UNPACK_METHODS
PyObject *args, *method, *result = NULL; static PyObject* __Pyx_PyObject_Call3Args(PyObject* function, PyObject* arg1, PyObject* arg2, PyObject* arg3) {
method = __Pyx_PyObject_GetAttrStr(obj, method_name); #if CYTHON_FAST_PYCALL
if (unlikely(!method)) return NULL; if (PyFunction_Check(function)) {
PyObject *args[3] = {arg1, arg2, arg3};
return __Pyx_PyFunction_FastCall(function, args, 3);
}
#endif
#if CYTHON_FAST_PYCCALL
if (__Pyx_PyFastCFunction_Check(function)) {
PyObject *args[3] = {arg1, arg2, arg3};
return __Pyx_PyFunction_FastCall(function, args, 3);
}
#endif
args = PyTuple_New(3);
if (unlikely(!args)) goto done;
Py_INCREF(arg1);
PyTuple_SET_ITEM(args, 0, arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(args, 1, arg2);
Py_INCREF(arg3);
PyTuple_SET_ITEM(args, 2, arg3);
result = __Pyx_PyObject_Call(function, args, NULL);
Py_DECREF(args);
return result;
}
#endif
static PyObject* __Pyx__PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2) {
#if CYTHON_UNPACK_METHODS #if CYTHON_UNPACK_METHODS
if (likely(PyMethod_Check(method)) && likely(PyMethod_GET_SELF(method))) { if (likely(PyMethod_Check(method)) && likely(PyMethod_GET_SELF(method))) {
PyObject *self, *function; PyObject *self, *function;
self = PyMethod_GET_SELF(method); self = PyMethod_GET_SELF(method);
function = PyMethod_GET_FUNCTION(method); function = PyMethod_GET_FUNCTION(method);
#if CYTHON_FAST_PYCALL return __Pyx_PyObject_Call3Args(method, obj, arg1, arg2);
if (PyFunction_Check(function)) { }
PyObject *args[3] = {self, arg1, arg2};
result = __Pyx_PyFunction_FastCall(function, args, 3);
goto done;
}
#endif
#if CYTHON_FAST_PYCCALL
if (__Pyx_PyFastCFunction_Check(function)) {
PyObject *args[3] = {self, arg1, arg2};
result = __Pyx_PyFunction_FastCall(function, args, 3);
goto done;
}
#endif
args = PyTuple_New(3);
if (unlikely(!args)) goto done;
Py_INCREF(self);
PyTuple_SET_ITEM(args, 0, self);
Py_INCREF(arg1);
PyTuple_SET_ITEM(args, 1, arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(args, 2, arg2);
Py_INCREF(function);
Py_DECREF(method);
method = function;
} else
#endif
#if CYTHON_FAST_PYCALL
if (PyFunction_Check(method)) {
PyObject *args[2] = {arg1, arg2};
result = __Pyx_PyFunction_FastCall(method, args, 2);
goto done;
} else
#endif
#if CYTHON_FAST_PYCCALL
if (__Pyx_PyFastCFunction_Check(method)) {
PyObject *args[2] = {arg1, arg2};
result = __Pyx_PyCFunction_FastCall(method, args, 2);
goto done;
} else
#endif #endif
{ return __Pyx_PyObject_Call2Args(method, arg1, arg2);
args = PyTuple_New(2); }
if (unlikely(!args)) goto done;
Py_INCREF(arg1); static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2) {
PyTuple_SET_ITEM(args, 0, arg1); PyObject *args, *method = NULL, *result = NULL;
Py_INCREF(arg2); #if CYTHON_UNPACK_METHODS
PyTuple_SET_ITEM(args, 1, arg2); int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
if (likely(is_method)) {
result = __Pyx_PyObject_Call3Args(method, obj, arg1, arg2);
Py_DECREF(method);
return result;
} }
result = __Pyx_PyObject_Call(method, args, NULL); #else
Py_DECREF(args); method = __Pyx_PyObject_GetAttrStr(obj, method_name);
done: #endif
if (unlikely(!method)) return NULL;
result = __Pyx__PyObject_CallMethod2(method, arg1, arg2);
Py_DECREF(method); Py_DECREF(method);
return result; return result;
} }
...@@ -2067,6 +2142,46 @@ static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, P ...@@ -2067,6 +2142,46 @@ static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, P
#endif /* CYTHON_FAST_PYCCALL */ #endif /* CYTHON_FAST_PYCCALL */
/////////////// PyObjectCall2Args ///////////////
static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); /*proto*/
/////////////// PyObjectCall2Args ///////////////
//@requires: PyObjectCall
//@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) {
PyObject *args, *result = NULL;
#if CYTHON_FAST_PYCALL
if (PyFunction_Check(function)) {
PyObject *args[2] = {arg1, arg2};
return __Pyx_PyFunction_FastCall(function, args, 2);
}
#endif
#if CYTHON_FAST_PYCCALL
if (__Pyx_PyFastCFunction_Check(function)) {
PyObject *args[2] = {arg1, arg2};
return __Pyx_PyCFunction_FastCall(function, args, 2);
}
#endif
args = PyTuple_New(2);
if (unlikely(!args)) goto done;
Py_INCREF(arg1);
PyTuple_SET_ITEM(args, 0, arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(args, 1, arg2);
Py_INCREF(function);
result = __Pyx_PyObject_Call(function, args, NULL);
Py_DECREF(args);
Py_DECREF(function);
done:
return result;
}
/////////////// PyObjectCallOneArg.proto /////////////// /////////////// PyObjectCallOneArg.proto ///////////////
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); /*proto*/ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); /*proto*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment