Commit cbec2d11 authored by Stefan Behnel's avatar Stefan Behnel

speed up type checks, especially for exceptions (which are used a lot in yield/await)

parent b797b427
...@@ -2700,8 +2700,7 @@ class IteratorNode(ExprNode): ...@@ -2700,8 +2700,7 @@ class IteratorNode(ExprNode):
code.putln("if (unlikely(!%s)) {" % result_name) code.putln("if (unlikely(!%s)) {" % result_name)
code.putln("PyObject* exc_type = PyErr_Occurred();") code.putln("PyObject* exc_type = PyErr_Occurred();")
code.putln("if (exc_type) {") code.putln("if (exc_type) {")
code.putln("if (likely(exc_type == PyExc_StopIteration ||" code.putln("if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();")
" PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();")
code.putln("else %s" % code.error_goto(self.pos)) code.putln("else %s" % code.error_goto(self.pos))
code.putln("}") code.putln("}")
code.putln("break;") code.putln("break;")
...@@ -9532,8 +9531,8 @@ class _YieldDelegationExprNode(YieldExprNode): ...@@ -9532,8 +9531,8 @@ class _YieldDelegationExprNode(YieldExprNode):
def handle_iteration_exception(self, code): def handle_iteration_exception(self, code):
code.putln("PyObject* exc_type = PyErr_Occurred();") code.putln("PyObject* exc_type = PyErr_Occurred();")
code.putln("if (exc_type) {") code.putln("if (exc_type) {")
code.putln("if (likely(exc_type == PyExc_StopIteration ||" code.putln("if (likely(exc_type == PyExc_StopIteration || exc_type != PyExc_GeneratorExit &&"
" PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();") " __Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();")
code.putln("else %s" % code.error_goto(self.pos)) code.putln("else %s" % code.error_goto(self.pos))
code.putln("}") code.putln("}")
...@@ -9588,8 +9587,9 @@ class AwaitIterNextExprNode(AwaitExprNode): ...@@ -9588,8 +9587,9 @@ class AwaitIterNextExprNode(AwaitExprNode):
def _generate_break(self, code): def _generate_break(self, code):
code.globalstate.use_utility_code(UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c")) code.globalstate.use_utility_code(UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"))
code.putln("PyObject* exc_type = PyErr_Occurred();") code.putln("PyObject* exc_type = PyErr_Occurred();")
code.putln("if (exc_type && likely(exc_type == __Pyx_PyExc_StopAsyncIteration ||" code.putln("if (unlikely(exc_type && (exc_type == __Pyx_PyExc_StopAsyncIteration || ("
" PyErr_GivenExceptionMatches(exc_type, __Pyx_PyExc_StopAsyncIteration))) {") " exc_type != PyExc_StopIteration && exc_type != PyExc_GeneratorExit &&"
" __Pyx_PyErr_GivenExceptionMatches(exc_type, __Pyx_PyExc_StopAsyncIteration))))) {")
code.putln("PyErr_Clear();") code.putln("PyErr_Clear();")
code.putln("break;") code.putln("break;")
code.putln("}") code.putln("}")
......
...@@ -717,6 +717,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -717,6 +717,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln('static const char * %s= %s;' % (Naming.cfilenm_cname, Naming.file_c_macro)) code.putln('static const char * %s= %s;' % (Naming.cfilenm_cname, Naming.file_c_macro))
code.putln('static const char *%s;' % Naming.filename_cname) code.putln('static const char *%s;' % Naming.filename_cname)
env.use_utility_code(UtilityCode.load_cached("FastTypeChecks", "ModuleSetupCode.c"))
if has_np_pythran(env): if has_np_pythran(env):
env.use_utility_code(UtilityCode.load_cached("PythranConversion", "CppSupport.cpp")) env.use_utility_code(UtilityCode.load_cached("PythranConversion", "CppSupport.cpp"))
......
...@@ -432,10 +432,7 @@ __Pyx_async_gen_unwrap_value(__pyx_PyAsyncGenObject *gen, PyObject *result) ...@@ -432,10 +432,7 @@ __Pyx_async_gen_unwrap_value(__pyx_PyAsyncGenObject *gen, PyObject *result)
if (!exc_type) { if (!exc_type) {
PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration);
gen->ag_closed = 1; gen->ag_closed = 1;
} else if (exc_type == __Pyx_PyExc_StopAsyncIteration } else if (__Pyx_PyErr_GivenExceptionMatches2(exc_type, __Pyx_PyExc_StopAsyncIteration, PyExc_GeneratorExit)) {
|| exc_type == PyExc_GeneratorExit
|| PyErr_GivenExceptionMatches(exc_type, __Pyx_PyExc_StopAsyncIteration)
|| PyErr_GivenExceptionMatches(exc_type, PyExc_GeneratorExit)) {
gen->ag_closed = 1; gen->ag_closed = 1;
} }
......
...@@ -111,7 +111,7 @@ static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { ...@@ -111,7 +111,7 @@ static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
{{for type_ptr, getbuffer, releasebuffer in types}} {{for type_ptr, getbuffer, releasebuffer in types}}
{{if getbuffer}} {{if getbuffer}}
if (PyObject_TypeCheck(obj, {{type_ptr}})) return {{getbuffer}}(obj, view, flags); if (__Pyx_TypeCheck(obj, {{type_ptr}})) return {{getbuffer}}(obj, view, flags);
{{endif}} {{endif}}
{{endfor}} {{endfor}}
...@@ -130,7 +130,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) { ...@@ -130,7 +130,7 @@ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
{{for type_ptr, getbuffer, releasebuffer in types}} {{for type_ptr, getbuffer, releasebuffer in types}}
{{if releasebuffer}} {{if releasebuffer}}
if (PyObject_TypeCheck(obj, {{type_ptr}})) { {{releasebuffer}}(obj, view); return; } if (__Pyx_TypeCheck(obj, {{type_ptr}})) { {{releasebuffer}}(obj, view); return; }
{{endif}} {{endif}}
{{endfor}} {{endfor}}
......
...@@ -343,9 +343,9 @@ static void __Pyx_Generator_Replace_StopIteration(CYTHON_UNUSED int in_async_gen ...@@ -343,9 +343,9 @@ static void __Pyx_Generator_Replace_StopIteration(CYTHON_UNUSED int in_async_gen
#endif #endif
cur_exc = PyErr_Occurred(); cur_exc = PyErr_Occurred();
if (likely(!PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) { if (likely(!__Pyx_PyErr_GivenExceptionMatches(cur_exc, PyExc_StopIteration))) {
#ifdef __Pyx_StopAsyncIteration_USED #ifdef __Pyx_StopAsyncIteration_USED
if (in_async_gen && unlikely(PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) { if (in_async_gen && unlikely(__Pyx_PyErr_GivenExceptionMatches(cur_exc, __Pyx_PyExc_StopAsyncIteration))) {
is_async_stopiteration = 1; is_async_stopiteration = 1;
} else } else
#endif #endif
...@@ -509,7 +509,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) { ...@@ -509,7 +509,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
} }
Py_DECREF(ev); Py_DECREF(ev);
} }
else if (!PyObject_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) { else if (!__Pyx_TypeCheck(ev, (PyTypeObject*)PyExc_StopIteration)) {
// 'steal' reference to ev // 'steal' reference to ev
value = ev; value = ev;
} }
...@@ -519,7 +519,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) { ...@@ -519,7 +519,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue) {
*pvalue = value; *pvalue = value;
return 0; return 0;
} }
} else if (!PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) { } else if (!__Pyx_PyErr_GivenExceptionMatches(et, PyExc_StopIteration)) {
__Pyx_ErrRestore(et, ev, tb); __Pyx_ErrRestore(et, ev, tb);
return -1; return -1;
} }
...@@ -876,12 +876,7 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) { ...@@ -876,12 +876,7 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
return NULL; return NULL;
} }
raised_exception = PyErr_Occurred(); raised_exception = PyErr_Occurred();
if (!raised_exception if (!raised_exception || __Pyx_PyErr_GivenExceptionMatches2(raised_exception, PyExc_GeneratorExit, PyExc_StopIteration)) {
|| raised_exception == PyExc_StopIteration
|| raised_exception == PyExc_GeneratorExit
|| PyErr_GivenExceptionMatches(raised_exception, PyExc_GeneratorExit)
|| PyErr_GivenExceptionMatches(raised_exception, PyExc_StopIteration))
{
// ignore these errors // ignore these errors
if (raised_exception) PyErr_Clear(); if (raised_exception) PyErr_Clear();
Py_INCREF(Py_None); Py_INCREF(Py_None);
...@@ -901,7 +896,7 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject ...@@ -901,7 +896,7 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
if (yf) { if (yf) {
PyObject *ret; PyObject *ret;
Py_INCREF(yf); Py_INCREF(yf);
if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) { if (__Pyx_PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && close_on_genexit) {
// Asynchronous generators *should not* be closed right away. // Asynchronous generators *should not* be closed right away.
// We have to allow some awaits to work it through, hence the // We have to allow some awaits to work it through, hence the
// `close_on_genexit` parameter here. // `close_on_genexit` parameter here.
......
...@@ -1218,7 +1218,7 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { ...@@ -1218,7 +1218,7 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
methoddescr_type = Py_TYPE(meth); methoddescr_type = Py_TYPE(meth);
Py_DECREF(meth); Py_DECREF(meth);
} }
if (PyObject_TypeCheck(method, methoddescr_type)) { if (__Pyx_TypeCheck(method, methoddescr_type)) {
#endif #endif
// cdef classes // cdef classes
PyMethodDescrObject *descr = (PyMethodDescrObject *)method; PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
...@@ -1238,7 +1238,7 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { ...@@ -1238,7 +1238,7 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
return PyClassMethod_New(method); return PyClassMethod_New(method);
} }
#ifdef __Pyx_CyFunction_USED #ifdef __Pyx_CyFunction_USED
else if (PyObject_TypeCheck(method, __pyx_CyFunctionType)) { else if (__Pyx_TypeCheck(method, __pyx_CyFunctionType)) {
return PyClassMethod_New(method); return PyClassMethod_New(method);
} }
#endif #endif
......
...@@ -35,7 +35,7 @@ static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tsta ...@@ -35,7 +35,7 @@ static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tsta
PyObject *exc_type = tstate->curexc_type; PyObject *exc_type = tstate->curexc_type;
if (exc_type == err) return 1; if (exc_type == err) return 1;
if (unlikely(!exc_type)) return 0; if (unlikely(!exc_type)) return 0;
return PyErr_GivenExceptionMatches(exc_type, err); return __Pyx_PyErr_GivenExceptionMatches(exc_type, err);
} }
#endif #endif
......
...@@ -26,7 +26,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in ...@@ -26,7 +26,7 @@ static CYTHON_INLINE int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, in
#endif #endif
} }
else { else {
if (likely(PyObject_TypeCheck(obj, type))) return 1; if (likely(__Pyx_TypeCheck(obj, type))) return 1;
} }
__Pyx_RaiseArgumentTypeInvalid(name, obj, type); __Pyx_RaiseArgumentTypeInvalid(name, obj, type);
return 0; return 0;
......
...@@ -326,7 +326,6 @@ ...@@ -326,7 +326,6 @@
#define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type)
#endif #endif
#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) #define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
...@@ -537,6 +536,111 @@ class __Pyx_FakeReference { ...@@ -537,6 +536,111 @@ class __Pyx_FakeReference {
}; };
/////////////// FastTypeChecks.proto ///////////////
#if CYTHON_COMPILING_IN_CPYTHON
#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type)
static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b);/*proto*/
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type);/*proto*/
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2);/*proto*/
#else
#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type)
#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2))
#endif
/////////////// FastTypeChecks ///////////////
//@requires: Exceptions.c::PyThreadStateGet
//@requires: Exceptions.c::PyErrFetchRestore
#if CYTHON_COMPILING_IN_CPYTHON
static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) {
while (a) {
a = a->tp_base;
if (a == b)
return 1;
}
return b == &PyBaseObject_Type;
}
static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) {
PyObject *mro;
if (a == b) return 1;
mro = a->tp_mro;
if (likely(mro)) {
Py_ssize_t i, n;
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
return 1;
}
return 0;
}
// should only get here for incompletely initialised types, i.e. never under normal usage patterns
return __Pyx_InBases(a, b);
}
#if PY_MAJOR_VERSION == 2
static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyTypeObject *err, PyTypeObject* exc_type1, PyTypeObject* exc_type2) {
// PyObject_IsSubclass() can recurse and therefore is not safe
PyObject *exception, *value, *tb;
int res;
__Pyx_PyThreadState_declare
__Pyx_PyThreadState_assign
__Pyx_ErrFetch(&exception, &value, &tb);
res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0;
// This function must not fail, so print the error here
if (unlikely(res == -1)) {
PyErr_WriteUnraisable(err);
res = 0;
}
if (!res) {
__Pyx_ErrRestore(exception, value, tb);
res = PyObject_IsSubclass(err, exc_type2);
// This function must not fail, so print the error here
if (unlikely(res == -1)) {
PyErr_WriteUnraisable(err);
res = 0;
}
}
__Pyx_ErrRestore(exception, value, tb);
return res;
}
#else
static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyTypeObject *err, PyTypeObject* exc_type1, PyTypeObject* exc_type2) {
int res = exc_type1 ? __Pyx_IsSubtype(err, exc_type1) : 0;
if (!res) {
res = __Pyx_IsSubtype(err, exc_type2);
}
return res;
}
#endif
// so far, we only call PyErr_GivenExceptionMatches() with an exception type (not instance) as first argument
// => optimise for that case
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject* exc_type) {
if (likely(err == exc_type)) return 1;
if (likely(PyExceptionClass_Check(err))) {
return __Pyx_inner_PyErr_GivenExceptionMatches2((PyTypeObject *)err, NULL, (PyTypeObject *)exc_type);
}
return PyErr_GivenExceptionMatches(err, exc_type);
}
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *exc_type1, PyObject *exc_type2) {
if (likely(err == exc_type1 || err == exc_type2)) return 1;
if (likely(PyExceptionClass_Check(err))) {
return __Pyx_inner_PyErr_GivenExceptionMatches2((PyTypeObject *)err, (PyTypeObject *)exc_type1, (PyTypeObject *)exc_type2);
}
return (PyErr_GivenExceptionMatches(err, exc_type1) || PyErr_GivenExceptionMatches(err, exc_type2));
}
#endif
/////////////// MathInitCode /////////////// /////////////// MathInitCode ///////////////
#if defined(WIN32) || defined(MS_WINDOWS) #if defined(WIN32) || defined(MS_WINDOWS)
......
...@@ -166,8 +166,7 @@ static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* ...@@ -166,8 +166,7 @@ static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject*
if (defval) { if (defval) {
PyObject* exc_type = PyErr_Occurred(); PyObject* exc_type = PyErr_Occurred();
if (exc_type) { if (exc_type) {
if (unlikely(exc_type != PyExc_StopIteration) && if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration)))
!PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))
return NULL; return NULL;
PyErr_Clear(); PyErr_Clear();
} }
...@@ -194,7 +193,7 @@ static CYTHON_INLINE int __Pyx_IterFinish(void) { ...@@ -194,7 +193,7 @@ static CYTHON_INLINE int __Pyx_IterFinish(void) {
PyThreadState *tstate = PyThreadState_GET(); PyThreadState *tstate = PyThreadState_GET();
PyObject* exc_type = tstate->curexc_type; PyObject* exc_type = tstate->curexc_type;
if (unlikely(exc_type)) { if (unlikely(exc_type)) {
if (likely(exc_type == PyExc_StopIteration) || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration)) { if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) {
PyObject *exc_value, *exc_tb; PyObject *exc_value, *exc_tb;
exc_value = tstate->curexc_value; exc_value = tstate->curexc_value;
exc_tb = tstate->curexc_traceback; exc_tb = tstate->curexc_traceback;
...@@ -917,7 +916,7 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { ...@@ -917,7 +916,7 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
PyErr_SetString(PyExc_SystemError, "Missing type object"); PyErr_SetString(PyExc_SystemError, "Missing type object");
return 0; return 0;
} }
if (likely(PyObject_TypeCheck(obj, type))) if (likely(__Pyx_TypeCheck(obj, type)))
return 1; return 1;
PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s",
Py_TYPE(obj)->tp_name, type->tp_name); Py_TYPE(obj)->tp_name, type->tp_name);
...@@ -1123,7 +1122,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) { ...@@ -1123,7 +1122,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
// method dscriptor type isn't exported in Py2.x, cannot easily check the type there // method dscriptor type isn't exported in Py2.x, cannot easily check the type there
if (likely(PyObject_TypeCheck(method, &PyMethodDescr_Type))) if (likely(__Pyx_TypeCheck(method, &PyMethodDescr_Type)))
#endif #endif
{ {
PyMethodDescrObject *descr = (PyMethodDescrObject*) method; PyMethodDescrObject *descr = (PyMethodDescrObject*) method;
...@@ -1747,7 +1746,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { ...@@ -1747,7 +1746,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
} }
#endif #endif
#ifdef __Pyx_CyFunction_USED #ifdef __Pyx_CyFunction_USED
if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) { if (likely(PyCFunction_Check(func) || __Pyx_TypeCheck(func, __pyx_CyFunctionType))) {
#else #else
if (likely(PyCFunction_Check(func))) { if (likely(PyCFunction_Check(func))) {
#endif #endif
......
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