vm: Save current active exception on opening new try block.

Required to reraise correct exceptions in except block, regardless if more
try blocks with active exceptions happen in the same except block.

P.S. This "automagic reraise" appears to be quite wasteful feature of Python
- we need to save pending exception just in case it *might* be reraised.
Instead, programmer could explcitly capture exception to a variable using
"except ... as var", and reraise that. So, consider disabling argless raise
support as an optimization.
This commit is contained in:
Paul Sokolovsky 2014-03-30 00:48:21 +02:00
parent 69975df3ff
commit 0c904df8e6
3 changed files with 27 additions and 0 deletions

View File

@ -9,6 +9,8 @@ typedef struct _mp_exc_stack {
const byte *handler; const byte *handler;
// bit 0 is saved currently_in_except_block value // bit 0 is saved currently_in_except_block value
mp_obj_t *val_sp; mp_obj_t *val_sp;
// Saved exception, valid if currently_in_except_block bit is 1
mp_obj_t prev_exc;
// We might only have 2 interesting cases here: SETUP_EXCEPT & SETUP_FINALLY, // We might only have 2 interesting cases here: SETUP_EXCEPT & SETUP_FINALLY,
// consider storing it in bit 1 of val_sp. TODO: SETUP_WITH? // consider storing it in bit 1 of val_sp. TODO: SETUP_WITH?
byte opcode; byte opcode;

View File

@ -51,10 +51,12 @@ typedef enum {
exc_sp->opcode = op; \ exc_sp->opcode = op; \
exc_sp->handler = ip + unum; \ exc_sp->handler = ip + unum; \
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \ exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
exc_sp->prev_exc = nlr.ret_val; \
currently_in_except_block = 0; /* in a try block now */ currently_in_except_block = 0; /* in a try block now */
#define POP_EXC_BLOCK() \ #define POP_EXC_BLOCK() \
currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \ currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \
if (currently_in_except_block) { nlr.ret_val = exc_sp->prev_exc; } \
exc_sp--; /* pop back to previous exception handler */ exc_sp--; /* pop back to previous exception handler */
mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret) { mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret) {

View File

@ -0,0 +1,23 @@
# Reraise not the latest occured exception
def f():
try:
raise ValueError("val", 3)
except:
try:
raise TypeError
except:
try:
try:
raise AttributeError
except:
pass
raise
except TypeError:
pass
# This should raise original ValueError, not the most recently occurred AttributeError
raise
try:
f()
except ValueError as e:
print(repr(e))