Commit 460f6801 authored by Stefan Behnel's avatar Stefan Behnel

special case METH_FASTCALL signatures of PyCFunctions in Py3.6+

parent 3f346d27
...@@ -5580,27 +5580,31 @@ class PyMethodCallNode(SimpleCallNode): ...@@ -5580,27 +5580,31 @@ class PyMethodCallNode(SimpleCallNode):
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c")) UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c"))
code.putln("#if CYTHON_FAST_PYCALL") code.globalstate.use_utility_code(
code.putln("if (PyFunction_Check(%s)) {" % function) UtilityCode.load_cached("PyCFunctionFastCall", "ObjectHandling.c"))
code.putln("PyObject *%s[%d] = {%s, %s};" % ( for test_func, call_prefix in [('PyFunction_Check', 'Py'), ('__Pyx_PyFastCFunction_Check', 'PyC')]:
Naming.quick_temp_cname, code.putln("#if CYTHON_FAST_%sCALL" % call_prefix.upper())
len(args)+1, code.putln("if (%s(%s)) {" % (test_func, function))
self_arg, code.putln("PyObject *%s[%d] = {%s, %s};" % (
', '.join(arg.py_result() for arg in args))) Naming.quick_temp_cname,
code.putln("%s = __Pyx_PyFunction_FastCall(%s, %s+1-%s, %d+%s); %s" % ( len(args)+1,
self.result(), self_arg,
function, ', '.join(arg.py_result() for arg in args)))
Naming.quick_temp_cname, code.putln("%s = __Pyx_%sFunction_FastCall(%s, %s+1-%s, %d+%s); %s" % (
arg_offset, self.result(),
len(args), call_prefix,
arg_offset, function,
code.error_goto_if_null(self.result(), self.pos))) Naming.quick_temp_cname,
code.put_xdecref_clear(self_arg, py_object_type) arg_offset,
code.put_gotref(self.py_result()) len(args),
for arg in args: arg_offset,
arg.generate_disposal_code(code) code.error_goto_if_null(self.result(), self.pos)))
code.putln("} else") code.put_xdecref_clear(self_arg, py_object_type)
code.putln("#endif") code.put_gotref(self.py_result())
for arg in args:
arg.generate_disposal_code(code)
code.putln("} else")
code.putln("#endif")
code.putln("{") code.putln("{")
args_tuple = code.funcstate.allocate_temp(py_object_type, manage_ref=True) args_tuple = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
......
...@@ -149,6 +149,10 @@ ...@@ -149,6 +149,10 @@
#endif #endif
#endif #endif
#if !defined(CYTHON_FAST_PYCCALL)
#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
#endif
#if CYTHON_USE_PYLONG_INTERNALS #if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h" #include "longintrepr.h"
/* These short defines can easily conflict with other code */ /* These short defines can easily conflict with other code */
...@@ -188,12 +192,19 @@ ...@@ -188,12 +192,19 @@
#ifndef Py_TPFLAGS_HAVE_FINALIZE #ifndef Py_TPFLAGS_HAVE_FINALIZE
#define Py_TPFLAGS_HAVE_FINALIZE 0 #define Py_TPFLAGS_HAVE_FINALIZE 0
#endif #endif
#ifndef METH_FASTCALL #ifndef METH_FASTCALL
// new in CPython 3.6 // new in CPython 3.6
#define METH_FASTCALL 0x80 #define METH_FASTCALL 0x80
typedef PyObject *(*_PyCFunctionFast) (PyObject *self, PyObject **args, typedef PyObject *(*_PyCFunctionFast) (PyObject *self, PyObject **args,
Py_ssize_t nargs, PyObject *kwnames); Py_ssize_t nargs, PyObject *kwnames);
#endif #endif
#if CYTHON_FAST_PYCCALL
#define __Pyx_PyFastCFunction_Check(func) \
((PyCFunction_Check(func) && METH_FASTCALL == PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)))
#else
#define __Pyx_PyFastCFunction_Check(func) 0
#endif
/* new Py3.3 unicode type (PEP 393) */ /* new Py3.3 unicode type (PEP 393) */
#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) #if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
......
...@@ -1263,6 +1263,7 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name ...@@ -1263,6 +1263,7 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name
//@requires: PyObjectGetAttrStr //@requires: PyObjectGetAttrStr
//@requires: PyObjectCallOneArg //@requires: PyObjectCallOneArg
//@requires: PyFunctionFastCall //@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
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 = NULL; PyObject *method, *result = NULL;
...@@ -1281,6 +1282,13 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name ...@@ -1281,6 +1282,13 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name
goto done; goto done;
} }
#endif #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); args = PyTuple_New(2);
if (unlikely(!args)) goto done; if (unlikely(!args)) goto done;
Py_INCREF(self); Py_INCREF(self);
...@@ -1311,6 +1319,7 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name ...@@ -1311,6 +1319,7 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name
//@requires: PyObjectGetAttrStr //@requires: PyObjectGetAttrStr
//@requires: PyObjectCall //@requires: PyObjectCall
//@requires: PyFunctionFastCall //@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2) { static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2) {
PyObject *args, *method, *result = NULL; PyObject *args, *method, *result = NULL;
...@@ -1328,6 +1337,13 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name ...@@ -1328,6 +1337,13 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name
goto done; goto done;
} }
#endif #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); args = PyTuple_New(3);
if (unlikely(!args)) goto done; if (unlikely(!args)) goto done;
Py_INCREF(self); Py_INCREF(self);
...@@ -1347,6 +1363,13 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name ...@@ -1347,6 +1363,13 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name
result = __Pyx_PyFunction_FastCall(method, args, 2); result = __Pyx_PyFunction_FastCall(method, args, 2);
goto done; goto done;
} else } 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
{ {
args = PyTuple_New(2); args = PyTuple_New(2);
...@@ -1601,6 +1624,39 @@ done: ...@@ -1601,6 +1624,39 @@ done:
#endif // CYTHON_FAST_PYCALL #endif // CYTHON_FAST_PYCALL
/////////////// PyCFunctionFastCall.proto ///////////////
#if CYTHON_FAST_PYCCALL
static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs);
#else
#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL)
#endif
/////////////// PyCFunctionFastCall ///////////////
#if CYTHON_FAST_PYCCALL
static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) {
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(METH_FASTCALL == PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST));
assert(nargs >= 0);
assert(nargs == 0 || args != NULL);
/* _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());
return (*((_PyCFunctionFast)meth)) (self, args, nargs, NULL);
}
#endif // CYTHON_FAST_PYCCALL
/////////////// 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*/
...@@ -1609,6 +1665,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec ...@@ -1609,6 +1665,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
//@requires: PyObjectCallMethO //@requires: PyObjectCallMethO
//@requires: PyObjectCall //@requires: PyObjectCall
//@requires: PyFunctionFastCall //@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
...@@ -1636,6 +1693,10 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec ...@@ -1636,6 +1693,10 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObjec
if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) {
// fast and simple case that we are optimising for // fast and simple case that we are optimising for
return __Pyx_PyObject_CallMethO(func, arg); return __Pyx_PyObject_CallMethO(func, arg);
#if CYTHON_FAST_PYCCALL
} else if (PyCFunction_GET_FLAGS(func) & METH_FASTCALL) {
return __Pyx_PyCFunction_FastCall(func, &arg, 1);
#endif
} }
} }
return __Pyx__PyObject_CallOneArg(func, arg); return __Pyx__PyObject_CallOneArg(func, arg);
...@@ -1705,6 +1766,7 @@ static PyObject* __Pyx_PyNumber_InPlaceMatrixMultiply(PyObject* x, PyObject* y); ...@@ -1705,6 +1766,7 @@ static PyObject* __Pyx_PyNumber_InPlaceMatrixMultiply(PyObject* x, PyObject* y);
//@requires: PyObjectGetAttrStr //@requires: PyObjectGetAttrStr
//@requires: PyObjectCallOneArg //@requires: PyObjectCallOneArg
//@requires: PyFunctionFastCall //@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
#if PY_VERSION_HEX < 0x03050000 #if PY_VERSION_HEX < 0x03050000
static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg) { static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg) {
...@@ -1723,6 +1785,13 @@ static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg ...@@ -1723,6 +1785,13 @@ static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg
goto done; goto done;
} }
#endif #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); args = PyTuple_New(2);
if (unlikely(!args)) goto done; if (unlikely(!args)) goto done;
Py_INCREF(self); Py_INCREF(self);
......
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