diff options
Diffstat (limited to 'py/vm.c')
-rw-r--r-- | py/vm.c | 51 |
1 files changed, 19 insertions, 32 deletions
@@ -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 |