@ -48,14 +48,6 @@
// top element.
// Exception stack also grows up, top element is also pointed at.
// Exception stack unwind reasons (WHY_* in CPython-speak)
// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds
// left to do encoded in the JUMP number
typedef enum {
UNWIND_RETURN = 1 ,
UNWIND_JUMP ,
} mp_unwind_reason_t ;
# define DECODE_UINT \
mp_uint_t unum = 0 ; \
do { \
@ -613,29 +605,18 @@ dispatch_loop:
mp_call_method_n_kw ( 3 , 0 , sp ) ;
SET_TOP ( mp_const_none ) ;
} else if ( MP_OBJ_IS_SMALL_INT ( TOP ( ) ) ) {
mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE ( TOP ( ) ) ;
if ( cause_val = = UNWIND_RETURN ) {
// stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN)
mp_obj_t ret_val = sp [ - 1 ] ;
// Getting here there are two distinct cases:
// - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1))
// - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc))
// For both cases we do exactly the same thing.
mp_obj_t data = sp [ - 1 ] ;
mp_obj_t cause = sp [ 0 ] ;
sp [ - 1 ] = mp_const_none ;
sp [ 0 ] = mp_const_none ;
sp [ 1 ] = mp_const_none ;
mp_call_method_n_kw ( 3 , 0 , sp - 3 ) ;
sp [ - 3 ] = ret_val ;
sp [ - 2 ] = MP_OBJ_NEW_SMALL_INT ( UNWIND_RETURN ) ;
} else {
assert ( cause_val = = UNWIND_JUMP ) ;
// stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP)
mp_obj_t dest_ip = sp [ - 2 ] ;
mp_obj_t num_exc = sp [ - 1 ] ;
sp [ - 2 ] = mp_const_none ;
sp [ - 1 ] = mp_const_none ;
sp [ 0 ] = mp_const_none ;
mp_call_method_n_kw ( 3 , 0 , sp - 4 ) ;
sp [ - 4 ] = dest_ip ;
sp [ - 3 ] = num_exc ;
sp [ - 2 ] = MP_OBJ_NEW_SMALL_INT ( UNWIND_JUMP ) ;
}
sp [ - 3 ] = data ;
sp [ - 2 ] = cause ;
sp - = 2 ; // we removed (__exit__, ctx_mgr)
} else {
assert ( mp_obj_is_exception_instance ( TOP ( ) ) ) ;
@ -680,10 +661,11 @@ unwind_jump:;
// of a "with" block contains the context manager info.
// We're going to run "finally" code as a coroutine
// (not calling it recursively). Set up a sentinel
// on a stack so it can return back to us when it is
// on the stack so it can return back to us when it is
// done (when WITH_CLEANUP or END_FINALLY reached).
PUSH ( ( mp_obj_t ) unum ) ; // push number of exception handlers left to unwind
PUSH ( MP_OBJ_NEW_SMALL_INT ( UNWIND_JUMP ) ) ; // push sentinel
// The sentinel is the number of exception handlers left to
// unwind, which is a non-negative integer.
PUSH ( MP_OBJ_NEW_SMALL_INT ( unum ) ) ;
ip = exc_sp - > handler ; // get exception handler byte code address
exc_sp - - ; // pop exception handler
goto dispatch_loop ; // run the exception handler
@ -720,11 +702,14 @@ unwind_jump:;
} 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 ( ) ) ;
if ( reason = = UNWIND_RETURN ) {
mp_int_t cause = MP_OBJ_SMALL_INT_VALUE ( POP ( ) ) ;
if ( cause < 0 ) {
// A negative cause indicates unwind return
goto unwind_return ;
} else {
assert ( reason = = UNWIND_JUMP ) ;
// Otherwise it's an unwind jump and we must push as a raw
// number the number of exception handlers to unwind
PUSH ( ( mp_obj_t ) cause ) ;
goto unwind_jump ;
}
} else {
@ -1101,7 +1086,7 @@ unwind_return:
// (not calling it recursively). Set up a sentinel
// on a stack so it can return back to us when it is
// done (when WITH_CLEANUP or END_FINALLY reached).
PUSH ( MP_OBJ_NEW_SMALL_INT ( UNWIND_RETURN ) ) ;
PUSH ( MP_OBJ_NEW_SMALL_INT ( - 1 ) ) ;
ip = exc_sp - > handler ;
exc_sp - - ;
goto dispatch_loop ;