@ -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