summaryrefslogtreecommitdiffstatshomepage
path: root/py/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/vm.c')
-rw-r--r--py/vm.c51
1 files changed, 19 insertions, 32 deletions
diff --git a/py/vm.c b/py/vm.c
index da8697fad2..93766bd116 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -587,6 +587,8 @@ dispatch_loop:
// and __exit__ method (with self) underneath it. Bytecode calls __exit__,
// and "deletes" it off stack, shifting "exception control block"
// to its place.
+ // The bytecode emitter ensures that there is enough space on the Python
+ // value stack to hold the __exit__ method plus an additional 4 entries.
if (TOP() == mp_const_none) {
// stack: (..., __exit__, ctx_mgr, None)
sp[1] = mp_const_none;
@@ -620,31 +622,26 @@ dispatch_loop:
}
sp -= 2; // we removed (__exit__, ctx_mgr)
} else {
- assert(mp_obj_is_exception_type(TOP()));
- // stack: (..., __exit__, ctx_mgr, traceback, exc_val, exc_type)
- // Need to pass (sp[0], sp[-1], sp[-2]) as arguments so must reverse the
- // order of these on the value stack (don't want to create a temporary
- // array because it increases stack footprint of the VM).
- mp_obj_t obj = sp[-2];
- sp[-2] = sp[0];
- sp[0] = obj;
- mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp - 4);
+ assert(mp_obj_is_exception_instance(TOP()));
+ // stack: (..., __exit__, ctx_mgr, exc_instance)
+ // Need to pass (exc_type, exc_instance, None) as arguments to __exit__.
+ sp[1] = sp[0];
+ sp[0] = mp_obj_get_type(sp[0]);
+ sp[2] = mp_const_none;
+ sp -= 2;
+ mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp);
if (mp_obj_is_true(ret_value)) {
// We need to silence/swallow the exception. This is done
// by popping the exception and the __exit__ handler and
// replacing it with None, which signals END_FINALLY to just
// execute the finally handler normally.
- sp -= 4;
SET_TOP(mp_const_none);
assert(exc_sp >= exc_stack);
POP_EXC_BLOCK();
} else {
// We need to re-raise the exception. We pop __exit__ handler
- // and copy the 3 exception values down (remembering that they
- // are reversed due to above code).
- sp[-4] = sp[0];
- sp[-3] = sp[-1];
- sp -= 2;
+ // by copying the exception instance down to the new top-of-stack.
+ sp[0] = sp[3];
}
}
DISPATCH();
@@ -698,18 +695,12 @@ unwind_jump:;
ENTRY(MP_BC_END_FINALLY):
MARK_EXC_IP_SELECTIVE();
- // not fully implemented
- // if TOS is an exception, reraises the exception (3 values on TOS)
// if TOS is None, just pops it and continues
- // if TOS is an integer, does something else
- // else error
- if (mp_obj_is_exception_type(TOP())) {
- RAISE(sp[-1]);
- }
+ // if TOS is an integer, finishes coroutine and returns control to caller
+ // if TOS is an exception, reraises the exception
if (TOP() == mp_const_none) {
sp--;
- } else {
- assert(MP_OBJ_IS_SMALL_INT(TOP()));
+ } else if (MP_OBJ_IS_SMALL_INT(TOP())) {
// We finished "finally" coroutine and now dispatch back
// to our caller, based on TOS value
mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP());
@@ -719,6 +710,9 @@ unwind_jump:;
assert(reason == UNWIND_JUMP);
goto unwind_jump;
}
+ } else {
+ assert(mp_obj_is_exception_instance(TOP()));
+ RAISE(TOP());
}
DISPATCH();
@@ -751,14 +745,9 @@ unwind_jump:;
// matched against: SETUP_EXCEPT
ENTRY(MP_BC_POP_EXCEPT):
- // TODO need to work out how blocks work etc
- // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
assert(exc_sp >= exc_stack);
assert(currently_in_except_block);
- //sp = (mp_obj_t*)(*exc_sp--);
- //exc_sp--; // discard ip
POP_EXC_BLOCK();
- //sp -= 3; // pop 3 exception values
DISPATCH();
ENTRY(MP_BC_BUILD_TUPLE): {
@@ -1359,10 +1348,8 @@ unwind_loop:
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
// save this exception in the stack so it can be used in a reraise, if needed
exc_sp->prev_exc = nlr.ret_val;
- // push(traceback, exc-val, exc-type)
- PUSH(mp_const_none);
+ // push exception object so it can be handled by bytecode
PUSH(MP_OBJ_FROM_PTR(nlr.ret_val));
- PUSH(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type));
code_state->sp = sp;
#if MICROPY_STACKLESS