Commit 4d8b1675 authored by Stefan Behnel's avatar Stefan Behnel

refactoring of exception raising code, simpler/faster/correcter code for...

refactoring of exception raising code, simpler/faster/correcter code for reraising exceptions, separate implementation for Py3, minor fixes for error cases
parent d79982c1
...@@ -3459,7 +3459,6 @@ class RaiseStatNode(StatNode): ...@@ -3459,7 +3459,6 @@ class RaiseStatNode(StatNode):
self.exc_tb.analyse_types(env) self.exc_tb.analyse_types(env)
self.exc_tb = self.exc_tb.coerce_to_pyobject(env) self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
env.use_utility_code(raise_utility_code) env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
nogil_check = Node.gil_error nogil_check = Node.gil_error
gil_message = "Raising exception" gil_message = "Raising exception"
...@@ -3506,7 +3505,6 @@ class ReraiseStatNode(StatNode): ...@@ -3506,7 +3505,6 @@ class ReraiseStatNode(StatNode):
child_attrs = [] child_attrs = []
def analyse_expressions(self, env): def analyse_expressions(self, env):
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code) env.use_utility_code(restore_exception_utility_code)
nogil_check = Node.gil_error nogil_check = Node.gil_error
...@@ -3515,7 +3513,12 @@ class ReraiseStatNode(StatNode): ...@@ -3515,7 +3513,12 @@ class ReraiseStatNode(StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
vars = code.funcstate.exc_vars vars = code.funcstate.exc_vars
if vars: if vars:
code.putln("__Pyx_Raise(%s, %s, %s);" % tuple(vars)) for varname in vars:
code.put_giveref(varname)
code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars))
for varname in vars:
code.put("%s = 0; " % varname)
code.putln()
code.putln(code.error_goto(self.pos)) code.putln(code.error_goto(self.pos))
else: else:
error(self.pos, "Reraise not inside except clause") error(self.pos, "Reraise not inside except clause")
...@@ -4125,8 +4128,9 @@ class TryExceptStatNode(StatNode): ...@@ -4125,8 +4128,9 @@ class TryExceptStatNode(StatNode):
code.put_goto(try_end_label) code.put_goto(try_end_label)
if code.label_used(try_return_label): if code.label_used(try_return_label):
code.put_label(try_return_label) code.put_label(try_return_label)
for var in Naming.exc_save_vars: for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.put_xdecref_clear(var, py_object_type) code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_return_label) code.put_goto(old_return_label)
code.put_label(our_error_label) code.put_label(our_error_label)
for temp_name, type in temps_to_clean_up: for temp_name, type in temps_to_clean_up:
...@@ -4920,13 +4924,57 @@ requires=[printing_utility_code]) ...@@ -4920,13 +4924,57 @@ requires=[printing_utility_code])
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# The following function is based on do_raise() from ceval.c. # Exception raising code
#
# Exceptions are raised by __Pyx_Raise() and stored as plain
# type/value/tb in PyThreadState->curexc_*. When being caught by an
# 'except' statement, curexc_* is moved over to exc_* by
# __Pyx_GetException()
restore_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
}
""")
# The following function is based on do_raise() from ceval.c. There
# are separate versions for Python2 and Python3 as exception handling
# has changed quite a lot between the two versions.
raise_utility_code = UtilityCode( raise_utility_code = UtilityCode(
proto = """ proto = """
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""", """,
impl = """ impl = """
#if PY_MAJOR_VERSION < 3
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
Py_XINCREF(type); Py_XINCREF(type);
Py_XINCREF(value); Py_XINCREF(value);
...@@ -4982,6 +5030,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { ...@@ -4982,6 +5030,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
} }
#endif #endif
} }
__Pyx_ErrRestore(type, value, tb); __Pyx_ErrRestore(type, value, tb);
return; return;
raise_error: raise_error:
...@@ -4990,6 +5039,165 @@ raise_error: ...@@ -4990,6 +5039,165 @@ raise_error:
Py_XDECREF(tb); Py_XDECREF(tb);
return; return;
} }
#else // Python 3+
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
if (tb == Py_None) {
tb = 0;
} else if (tb && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"raise: arg 3 must be a traceback or None");
goto bad;
}
if (value == Py_None)
value = 0;
if (PyExceptionInstance_Check(type)) {
if (value) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto bad;
}
value = type;
type = (PyObject*) Py_TYPE(value);
Py_INCREF(type);
} else if (!PyExceptionClass_Check(type)) {
PyErr_SetString(PyExc_TypeError,
"raise: exception class must be a subclass of BaseException");
goto bad;
}
PyErr_SetObject(type, value);
if (tb) {
PyThreadState *tstate = PyThreadState_GET();
value = tstate->curexc_value;
type = tstate->curexc_type;
Py_INCREF(type);
Py_XINCREF(value);
Py_INCREF(tb);
if (!value || value == Py_None) {
PyErr_NormalizeException(&type, &value, &tb);
}
if (value) {
PyException_SetTraceback(value, tb);
__Pyx_ErrRestore(type, value, tb);
}
}
bad:
return;
}
#endif
""",
requires=[restore_exception_utility_code])
#------------------------------------------------------------------------------------
get_exception_utility_code = UtilityCode(
proto = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *local_type, *local_value, *local_tb;
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
local_type = tstate->curexc_type;
local_value = tstate->curexc_value;
local_tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
PyErr_NormalizeException(&local_type, &local_value, &local_tb);
if (tstate->curexc_type)
goto bad;
*type = local_type;
*value = local_value;
*tb = local_tb;
Py_INCREF(local_type);
Py_INCREF(local_value);
Py_INCREF(local_tb);
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = local_type;
tstate->exc_value = local_value;
tstate->exc_traceback = local_tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
return 0;
bad:
*type = 0;
*value = 0;
*tb = 0;
Py_XDECREF(local_type);
Py_XDECREF(local_value);
Py_XDECREF(local_tb);
return -1;
}
""")
#------------------------------------------------------------------------------------
get_exception_tuple_utility_code = UtilityCode(proto="""
static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetExceptionTuple(void) {
PyObject *type = NULL, *value = NULL, *tb = NULL;
if (__Pyx_GetException(&type, &value, &tb) == 0) {
PyObject* exc_info = PyTuple_New(3);
if (exc_info) {
Py_INCREF(type);
Py_INCREF(value);
Py_INCREF(tb);
PyTuple_SET_ITEM(exc_info, 0, type);
PyTuple_SET_ITEM(exc_info, 1, value);
PyTuple_SET_ITEM(exc_info, 2, tb);
return exc_info;
}
}
return NULL;
}
""",
requires=[get_exception_utility_code])
#------------------------------------------------------------------------------------
reset_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
}
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
""") """)
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
...@@ -5339,57 +5547,6 @@ bad: ...@@ -5339,57 +5547,6 @@ bad:
'EMPTY_BYTES' : Naming.empty_bytes, 'EMPTY_BYTES' : Naming.empty_bytes,
}) })
restore_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
#if PY_MAJOR_VERSION >= 3
/* Note: this is a temporary work-around to prevent crashes in Python 3.0 */
if ((tstate->exc_type != NULL) & (tstate->exc_type != Py_None)) {
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
PyErr_NormalizeException(&type, &value, &tb);
PyErr_NormalizeException(&tmp_type, &tmp_value, &tmp_tb);
tstate->exc_type = 0;
tstate->exc_value = 0;
tstate->exc_traceback = 0;
PyException_SetContext(value, tmp_value);
Py_DECREF(tmp_type);
Py_XDECREF(tmp_tb);
}
#endif
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
}
""")
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode( unraisable_exception_utility_code = UtilityCode(
...@@ -5508,107 +5665,6 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { ...@@ -5508,107 +5665,6 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
get_exception_utility_code = UtilityCode(
proto = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
PyErr_NormalizeException(type, value, tb);
if (PyErr_Occurred())
goto bad;
Py_INCREF(*type);
Py_INCREF(*value);
Py_INCREF(*tb);
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = *type;
tstate->exc_value = *value;
tstate->exc_traceback = *tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
return 0;
bad:
Py_XDECREF(*type);
Py_XDECREF(*value);
Py_XDECREF(*tb);
return -1;
}
""")
#------------------------------------------------------------------------------------
get_exception_tuple_utility_code = UtilityCode(proto="""
static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetExceptionTuple(void) {
PyObject *type = NULL, *value = NULL, *tb = NULL;
if (__Pyx_GetException(&type, &value, &tb) == 0) {
PyObject* exc_info = PyTuple_New(3);
if (exc_info) {
Py_INCREF(type);
Py_INCREF(value);
Py_INCREF(tb);
PyTuple_SET_ITEM(exc_info, 0, type);
PyTuple_SET_ITEM(exc_info, 1, value);
PyTuple_SET_ITEM(exc_info, 2, tb);
return exc_info;
}
}
return NULL;
}
""",
requires=[get_exception_utility_code])
#------------------------------------------------------------------------------------
reset_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
}
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
""")
#------------------------------------------------------------------------------------
force_init_threads_utility_code = UtilityCode( force_init_threads_utility_code = UtilityCode(
proto=""" proto="""
#ifndef __PYX_FORCE_INIT_THREADS #ifndef __PYX_FORCE_INIT_THREADS
......
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