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:
Damien George 2018-02-08 13:30:33 +11:00
parent 0b12cc8feb
commit 0c650d4276
1 changed files with 23 additions and 38 deletions

53
py/vm.c
View File

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