py/vm: Simplify stack sentinel values for unwind return and jump.
This patch simplifies how sentinel values are stored on the stack when doing an unwind return or jump. Instead of storing two values on the stack for an unwind jump it now stores only one: a negative small integer means unwind-return and a non-negative small integer means unwind-jump with the value being the number of exceptions to unwind. The savings in code size are: bare-arm: -56 minimal x86: -68 unix x64: -80 unix nanbox: -4 stm32: -56 cc3200: -64 esp8266: -76 esp32: -156
This commit is contained in:
parent
0b12cc8feb
commit
0c650d4276
61
py/vm.c
61
py/vm.c
|
@ -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];
|
||||
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);
|
||||
}
|
||||
// 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] = 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;
|
||||
|
|
Loading…
Reference in New Issue