aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George2019-08-21 16:08:43 +1000
committerDamien George2019-08-28 12:31:53 +1000
commit08c1fe556915c912598d5a5d5db0f5942f3a333d (patch)
tree454282f0dc4875632c9d3e3881b257e5918736dd
parent16f6169c88a5fd93b151149e561d177557fcc760 (diff)
py/vm: Don't add traceback info for exceptions that are re-raised.
With this patch exceptions that are re-raised have improved tracebacks (less confusing, match CPython), and it makes re-raise slightly more efficient (in time and RAM) because they no longer need to add a traceback. Also general VM performance is not measurably affected. Partially fixes issue #2928.
-rw-r--r--py/vm.c4
-rw-r--r--tests/misc/print_exception.py12
2 files changed, 15 insertions, 1 deletions
diff --git a/py/vm.c b/py/vm.c
index 64bddd6b5..84296b463 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1362,8 +1362,10 @@ unwind_loop:
// Set traceback info (file and line number) where the exception occurred, but not for:
// - constant GeneratorExit object, because it's const
// - exceptions re-raised by END_FINALLY
+ // - exceptions re-raised explicitly by "raise"
if (nlr.ret_val != &mp_const_GeneratorExit_obj
- && *code_state->ip != MP_BC_END_FINALLY) {
+ && *code_state->ip != MP_BC_END_FINALLY
+ && !(*code_state->ip == MP_BC_RAISE_VARARGS && code_state->ip[1] == 0)) {
const byte *ip = code_state->fun_bc->bytecode;
ip = mp_decode_uint_skip(ip); // skip n_state
ip = mp_decode_uint_skip(ip); // skip n_exc_stack
diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py
index 08b2e4bc4..2067030bf 100644
--- a/tests/misc/print_exception.py
+++ b/tests/misc/print_exception.py
@@ -57,6 +57,18 @@ except Exception as e:
print('caught')
print_exc(e)
+# Test that re-raising an exception doesn't add traceback info
+try:
+ try:
+ f()
+ except Exception as e:
+ print('reraise')
+ print_exc(e)
+ raise
+except Exception as e:
+ print('caught')
+ print_exc(e)
+
# Here we have a function with lots of bytecode generated for a single source-line, and
# there is an error right at the end of the bytecode. It should report the correct line.
def f():