Commit 4fb1e7a0 authored by Jeroen Demeyer's avatar Jeroen Demeyer Committed by Stefan Behnel

Simplify and optimize calls, using vectorcall on Python 3.8 (GH-2999)

* Do not use unsafe _PyMethodDef_RawFastCallKeywords
* Simplify and optimize calls, using vectorcall on Python 3.8
parent b28b849b
......@@ -6039,10 +6039,8 @@ class PyMethodCallNode(SimpleCallNode):
self_arg = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
code.putln("%s = NULL;" % self_arg)
arg_offset_cname = None
if len(args) > 1:
arg_offset_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = 0;" % arg_offset_cname)
arg_offset_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = 0;" % arg_offset_cname)
def attribute_is_likely_method(attr):
obj = attr.obj
......@@ -6075,115 +6073,33 @@ class PyMethodCallNode(SimpleCallNode):
code.put_incref("function", py_object_type)
# free method object as early to possible to enable reuse from CPython's freelist
code.put_decref_set(function, "function")
if len(args) > 1:
code.putln("%s = 1;" % arg_offset_cname)
code.putln("%s = 1;" % arg_offset_cname)
code.putln("}")
code.putln("}")
if not args:
# fastest special case: try to avoid tuple creation
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectCallNoArg", "ObjectHandling.c"))
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c"))
code.putln(
"%s = (%s) ? __Pyx_PyObject_CallOneArg(%s, %s) : __Pyx_PyObject_CallNoArg(%s);" % (
self.result(), self_arg,
function, self_arg,
function))
code.put_xdecref_clear(self_arg, py_object_type)
code.funcstate.release_temp(self_arg)
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
elif len(args) == 1:
# fastest special case: try to avoid tuple creation
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectCall2Args", "ObjectHandling.c"))
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectCallOneArg", "ObjectHandling.c"))
arg = args[0]
code.putln(
"%s = (%s) ? __Pyx_PyObject_Call2Args(%s, %s, %s) : __Pyx_PyObject_CallOneArg(%s, %s);" % (
self.result(), self_arg,
function, self_arg, arg.py_result(),
function, arg.py_result()))
code.put_xdecref_clear(self_arg, py_object_type)
code.funcstate.release_temp(self_arg)
arg.generate_disposal_code(code)
arg.free_temps(code)
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
else:
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyFunctionFastCall", "ObjectHandling.c"))
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_cname,
len(args),
arg_offset_cname,
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")
# actually call the function
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectFastCall", "ObjectHandling.c"))
code.putln("{")
args_tuple = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
code.putln("%s = PyTuple_New(%d+%s); %s" % (
args_tuple, len(args), arg_offset_cname,
code.error_goto_if_null(args_tuple, self.pos)))
code.put_gotref(args_tuple)
if len(args) > 1:
code.putln("if (%s) {" % self_arg)
code.putln("__Pyx_GIVEREF(%s); PyTuple_SET_ITEM(%s, 0, %s); %s = NULL;" % (
self_arg, args_tuple, self_arg, self_arg)) # stealing owned ref in this case
code.funcstate.release_temp(self_arg)
if len(args) > 1:
code.putln("}")
for i, arg in enumerate(args):
arg.make_owned_reference(code)
code.put_giveref(arg.py_result())
code.putln("PyTuple_SET_ITEM(%s, %d+%s, %s);" % (
args_tuple, i, arg_offset_cname, arg.py_result()))
if len(args) > 1:
code.funcstate.release_temp(arg_offset_cname)
for arg in args:
arg.generate_post_assignment_code(code)
arg.free_temps(code)
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectCall", "ObjectHandling.c"))
code.putln(
"%s = __Pyx_PyObject_Call(%s, %s, NULL); %s" % (
self.result(),
function, args_tuple,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
code.put_decref_clear(args_tuple, py_object_type)
code.funcstate.release_temp(args_tuple)
code.putln("{")
code.putln("PyObject *__pyx_callargs[%d] = {%s, %s};" % (
len(args)+1,
self_arg,
', '.join(arg.py_result() for arg in args)))
code.putln("%s = __Pyx_PyObject_FastCall(%s, __pyx_callargs+1-%s, %d+%s);" % (
self.result(),
function,
arg_offset_cname,
len(args),
arg_offset_cname))
if len(args) == 1:
code.putln("}")
code.putln("}") # !CYTHON_FAST_PYCALL
code.put_xdecref_clear(self_arg, py_object_type)
code.funcstate.release_temp(self_arg)
for arg in args:
arg.generate_disposal_code(code)
arg.free_temps(code)
code.putln(code.error_goto_if_null(self.result(), self.pos))
code.put_gotref(self.py_result())
if reuse_function_temp:
self.function.generate_disposal_code(code)
......@@ -6191,6 +6107,7 @@ class PyMethodCallNode(SimpleCallNode):
else:
code.put_decref_clear(function, py_object_type)
code.funcstate.release_temp(function)
code.putln("}")
class InlinedDefNodeCallNode(CallNode):
......
......@@ -194,14 +194,6 @@ static PyObject *__Pyx__Coroutine_GetAwaitableIter(PyObject *obj) {
PyObject *method = NULL;
int is_method = __Pyx_PyObject_GetMethod(obj, PYIDENT("__await__"), &method);
if (likely(is_method)) {
#if PY_VERSION_HEX >= 0x030700A1 && CYTHON_UNPACK_METHODS && CYTHON_FAST_PYCCALL
if (Py_TYPE(method) == &PyMethodDescr_Type) {
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
res = _PyMethodDef_RawFastCallKeywords(descr->d_method, obj, NULL, 0, NULL);
if (unlikely(!res))
res = _Py_CheckFunctionResult(obj, res, NULL);
} else
#endif
res = __Pyx_PyObject_CallOneArg(method, obj);
} else if (likely(method)) {
res = __Pyx_PyObject_CallNoArg(method);
......
......@@ -198,6 +198,10 @@
#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
#endif
#if !defined(CYTHON_VECTORCALL)
#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1)
#endif
#if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h"
/* These short defines can easily conflict with other code */
......@@ -444,12 +448,6 @@ class __Pyx_FakeReference {
#define __Pyx_PyCFunctionFast _PyCFunctionFast
#define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords
#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 | METH_KEYWORDS | METH_STACKLESS)))))
#else
#define __Pyx_PyFastCFunction_Check(func) 0
#endif
#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
#define PyObject_Malloc(s) PyMem_Malloc(s)
......
......@@ -1796,6 +1796,94 @@ bad:
}
/////////////// PyObjectFastCall.proto ///////////////
static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); /*proto*/
/////////////// PyObjectFastCall ///////////////
//@requires: PyObjectCall
//@requires: PyFunctionFastCall
//@requires: PyObjectCallMethO
//@substitute: naming
static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject **args, Py_ssize_t nargs) {
PyObject *argstuple;
PyObject *result;
Py_ssize_t i;
argstuple = PyTuple_New(nargs);
if (unlikely(!argstuple)) return NULL;
for (i = 0; i < nargs; i++) {
Py_INCREF(args[i]);
PyTuple_SET_ITEM(argstuple, i, args[i]);
}
result = __Pyx_PyObject_Call(func, argstuple, NULL);
Py_DECREF(argstuple);
return result;
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) {
// Special fast paths for 0 and 1 arguments
// NOTE: in many cases, this is called with a constant value for nargs
// which is known at compile-time. So the branches below will typically
// be optimized away.
#if CYTHON_COMPILING_IN_CPYTHON
if (nargs == 0) {
#ifdef __Pyx_CyFunction_USED
if (PyCFunction_Check(func) || __Pyx_CyFunction_Check(func))
#else
if (PyCFunction_Check(func))
#endif
{
if (likely(PyCFunction_GET_FLAGS(func) & METH_NOARGS)) {
return __Pyx_PyObject_CallMethO(func, NULL);
}
}
}
else if (nargs == 1) {
if (PyCFunction_Check(func))
{
if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) {
return __Pyx_PyObject_CallMethO(func, args[0]);
}
}
}
#endif
#if PY_VERSION_HEX < 0x030800B1
#if CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030700A1
if (PyCFunction_Check(func)) {
return _PyCFunction_FastCallKeywords(func, args, nargs, NULL);
}
if (Py_TYPE(func) == &PyMethodDescr_Type) {
return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL);
}
#elif CYTHON_FAST_PYCCALL
if (PyCFunction_Check(func)) {
return _PyCFunction_FastCallDict(func, args, nargs, NULL);
}
#endif
#if CYTHON_FAST_PYCALL
if (PyFunction_Check(func)) {
return __Pyx_PyFunction_FastCall(func, args, nargs);
}
#endif
#endif
#if CYTHON_VECTORCALL
vectorcallfunc f = _PyVectorcall_Function(func);
if (f) {
return f(func, args, nargs, NULL);
}
#endif
if (nargs == 0) {
return __Pyx_PyObject_Call(func, $empty_tuple, NULL);
}
return __Pyx_PyObject_FastCall_fallback(func, args, nargs);
}
/////////////// PyObjectCallMethod0.proto ///////////////
static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); /*proto*/
......@@ -1809,14 +1897,6 @@ static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name
PyObject *method = NULL, *result = NULL;
int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
if (likely(is_method)) {
#if PY_VERSION_HEX >= 0x030700A1 && CYTHON_UNPACK_METHODS && CYTHON_FAST_PYCCALL
if (Py_TYPE(method) == &PyMethodDescr_Type) {
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
result = _PyMethodDef_RawFastCallKeywords(descr->d_method, obj, NULL, 0, NULL);
if (unlikely(!result))
result = _Py_CheckFunctionResult(obj, result, NULL);
} else
#endif
result = __Pyx_PyObject_CallOneArg(method, obj);
Py_DECREF(method);
return result;
......@@ -1849,14 +1929,6 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name
PyObject *method = NULL, *result;
int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
if (likely(is_method)) {
#if PY_VERSION_HEX >= 0x030700A1 && CYTHON_UNPACK_METHODS && CYTHON_FAST_PYCCALL
if (Py_TYPE(method) == &PyMethodDescr_Type) {
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
result = _PyMethodDef_RawFastCallKeywords(descr->d_method, obj, &arg, 1, NULL);
if (unlikely(!result))
result = _Py_CheckFunctionResult(obj, result, NULL);
} else
#endif
result = __Pyx_PyObject_Call2Args(method, obj, arg);
Py_DECREF(method);
return result;
......@@ -1866,68 +1938,6 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name
}
/////////////// PyObjectCallMethod2.proto ///////////////
static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2); /*proto*/
/////////////// PyObjectCallMethod2 ///////////////
//@requires: PyObjectCall
//@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
//@requires: PyObjectCall2Args
static PyObject* __Pyx_PyObject_Call3Args(PyObject* function, PyObject* arg1, PyObject* arg2, PyObject* arg3) {
#if CYTHON_FAST_PYCALL
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;
}
static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name, PyObject* arg1, PyObject* arg2) {
PyObject *args, *method = NULL, *result = NULL;
int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
if (likely(is_method)) {
#if PY_VERSION_HEX >= 0x030700A1 && CYTHON_UNPACK_METHODS && CYTHON_FAST_PYCCALL
if (Py_TYPE(method) == &PyMethodDescr_Type) {
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
PyObject *args[2] = {arg1, arg2};
result = _PyMethodDef_RawFastCallKeywords(descr->d_method, obj, args, 2, NULL);
if (unlikely(!result))
result = _Py_CheckFunctionResult(obj, result, NULL);
} else
#endif
result = __Pyx_PyObject_Call3Args(method, obj, arg1, arg2);
Py_DECREF(method);
return result;
}
if (unlikely(!method)) return NULL;
result = __Pyx_PyObject_Call2Args(method, arg1, arg2);
Py_DECREF(method);
return result;
}
/////////////// tp_new.proto ///////////////
#define __Pyx_tp_new(type_obj, args) __Pyx_tp_new_kwargs(type_obj, args, NULL)
......@@ -1999,14 +2009,12 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject
/////////////// PyFunctionFastCall.proto ///////////////
#if CYTHON_FAST_PYCALL
#if !CYTHON_VECTORCALL
#define __Pyx_PyFunction_FastCall(func, args, nargs) \
__Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL)
// let's assume that the non-public C-API function might still change during the 3.6 beta phase
#if 1 || PY_VERSION_HEX < 0x030600B1
static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs);
#else
#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs)
#endif
// Backport from Python 3
......@@ -2047,8 +2055,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
/////////////// PyFunctionFastCall ///////////////
// copied from CPython 3.6 ceval.c
#if CYTHON_FAST_PYCALL
#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL
static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na,
PyObject *globals) {
PyFrameObject *f;
......@@ -2084,7 +2091,6 @@ static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args
}
#if 1 || PY_VERSION_HEX < 0x030600B1
static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) {
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
PyObject *globals = PyFunction_GET_GLOBALS(func);
......@@ -2194,44 +2200,7 @@ done:
Py_LeaveRecursiveCall();
return result;
}
#endif /* CPython < 3.6 */
#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);
int flags = PyCFunction_GET_FLAGS(func);
assert(PyCFunction_Check(func));
assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS)));
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());
if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) {
return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL);
} else {
return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs);
}
}
#endif /* CYTHON_FAST_PYCCALL */
#endif /* CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL */
/////////////// PyObjectCall2Args.proto ///////////////
......@@ -2239,38 +2208,11 @@ static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, P
static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); /*proto*/
/////////////// PyObjectCall2Args ///////////////
//@requires: PyObjectCall
//@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
//@requires: PyObjectFastCall
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;
PyObject *args[2] = {arg1, arg2};
return __Pyx_PyObject_FastCall(function, args, 2);
}
......@@ -2279,90 +2221,23 @@ done:
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); /*proto*/
/////////////// PyObjectCallOneArg ///////////////
//@requires: PyObjectCallMethO
//@requires: PyObjectCall
//@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
#if CYTHON_COMPILING_IN_CPYTHON
static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
PyObject *result;
PyObject *args = PyTuple_New(1);
if (unlikely(!args)) return NULL;
Py_INCREF(arg);
PyTuple_SET_ITEM(args, 0, arg);
result = __Pyx_PyObject_Call(func, args, NULL);
Py_DECREF(args);
return result;
}
//@requires: PyObjectFastCall
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
#if CYTHON_FAST_PYCALL
if (PyFunction_Check(func)) {
return __Pyx_PyFunction_FastCall(func, &arg, 1);
}
#endif
if (likely(PyCFunction_Check(func))) {
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);
}
#else
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
PyObject *result;
PyObject *args = PyTuple_Pack(1, arg);
if (unlikely(!args)) return NULL;
result = __Pyx_PyObject_Call(func, args, NULL);
Py_DECREF(args);
return result;
return __Pyx_PyObject_FastCall(func, &arg, 1);
}
#endif
/////////////// PyObjectCallNoArg.proto ///////////////
//@requires: PyObjectCall
//@substitute: naming
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); /*proto*/
#else
#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, $empty_tuple, NULL)
#endif
/////////////// PyObjectCallNoArg ///////////////
//@requires: PyObjectCallMethO
//@requires: PyObjectCall
//@requires: PyFunctionFastCall
//@substitute: naming
//@requires: PyObjectFastCall
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
#if CYTHON_FAST_PYCALL
if (PyFunction_Check(func)) {
return __Pyx_PyFunction_FastCall(func, NULL, 0);
}
#endif
#ifdef __Pyx_CyFunction_USED
if (likely(PyCFunction_Check(func) || __Pyx_CyFunction_Check(func)))
#else
if (likely(PyCFunction_Check(func)))
#endif
{
if (likely(PyCFunction_GET_FLAGS(func) & METH_NOARGS)) {
// fast and simple case that we are optimising for
return __Pyx_PyObject_CallMethO(func, NULL);
}
}
return __Pyx_PyObject_Call(func, $empty_tuple, NULL);
return __Pyx_PyObject_FastCall(func, NULL, 0);
}
#endif
/////////////// MatrixMultiply.proto ///////////////
......@@ -2379,8 +2254,7 @@ static PyObject* __Pyx_PyNumber_InPlaceMatrixMultiply(PyObject* x, PyObject* y);
/////////////// MatrixMultiply ///////////////
//@requires: PyObjectGetAttrStrNoError
//@requires: PyObjectCallOneArg
//@requires: PyFunctionFastCall
//@requires: PyCFunctionFastCall
//@requires: PyObjectCall2Args
#if PY_VERSION_HEX < 0x03050000
static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg) {
......@@ -2390,34 +2264,9 @@ static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg
if (likely(PyMethod_Check(method))) {
PyObject *self = PyMethod_GET_SELF(method);
if (likely(self)) {
PyObject *args;
PyObject *function = PyMethod_GET_FUNCTION(method);
#if CYTHON_FAST_PYCALL
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);
Py_DECREF(method); method = NULL;
result = __Pyx_PyObject_Call(function, args, NULL);
Py_DECREF(args);
Py_DECREF(function);
return result;
result = __Pyx_PyObject_Call2Args(function, self, arg);
goto done;
}
}
#endif
......
......@@ -555,3 +555,19 @@ def for_in_iteritems_of_expression(*args, **kwargs):
for k, v in dict(*args, **kwargs).iteritems():
result.append((k, v))
return result
cdef class NotADict:
"""
>>> NotADict().listvalues() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError: descriptor 'values' for 'mappingproxy' objects doesn't apply to a 'iterdict.NotADict' object
"""
cdef long v
def __cinit__(self):
self.v = 1
itervalues = type(object.__dict__).values
def listvalues(self):
return [v for v in self.itervalues()]
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