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