Skip to content

Commit 0c650d4

Browse files
committed
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
1 parent 0b12cc8 commit 0c650d4

1 file changed

Lines changed: 23 additions & 38 deletions

File tree

py/vm.c

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@
4848
// top element.
4949
// Exception stack also grows up, top element is also pointed at.
5050

51-
// Exception stack unwind reasons (WHY_* in CPython-speak)
52-
// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds
53-
// left to do encoded in the JUMP number
54-
typedef enum {
55-
UNWIND_RETURN = 1,
56-
UNWIND_JUMP,
57-
} mp_unwind_reason_t;
58-
5951
#define DECODE_UINT \
6052
mp_uint_t unum = 0; \
6153
do { \
@@ -613,29 +605,18 @@ run_code_state: ;
613605
mp_call_method_n_kw(3, 0, sp);
614606
SET_TOP(mp_const_none);
615607
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
616-
mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE(TOP());
617-
if (cause_val == UNWIND_RETURN) {
618-
// stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN)
619-
mp_obj_t ret_val = sp[-1];
620-
sp[-1] = mp_const_none;
621-
sp[0] = mp_const_none;
622-
sp[1] = mp_const_none;
623-
mp_call_method_n_kw(3, 0, sp - 3);
624-
sp[-3] = ret_val;
625-
sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN);
626-
} else {
627-
assert(cause_val == UNWIND_JUMP);
628-
// stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP)
629-
mp_obj_t dest_ip = sp[-2];
630-
mp_obj_t num_exc = sp[-1];
631-
sp[-2] = mp_const_none;
632-
sp[-1] = mp_const_none;
633-
sp[0] = mp_const_none;
634-
mp_call_method_n_kw(3, 0, sp - 4);
635-
sp[-4] = dest_ip;
636-
sp[-3] = num_exc;
637-
sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP);
638-
}
608+
// Getting here there are two distinct cases:
609+
// - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1))
610+
// - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc))
611+
// For both cases we do exactly the same thing.
612+
mp_obj_t data = sp[-1];
613+
mp_obj_t cause = sp[0];
614+
sp[-1] = mp_const_none;
615+
sp[0] = mp_const_none;
616+
sp[1] = mp_const_none;
617+
mp_call_method_n_kw(3, 0, sp - 3);
618+
sp[-3] = data;
619+
sp[-2] = cause;
639620
sp -= 2; // we removed (__exit__, ctx_mgr)
640621
} else {
641622
assert(mp_obj_is_exception_instance(TOP()));
@@ -680,10 +661,11 @@ unwind_jump:;
680661
// of a "with" block contains the context manager info.
681662
// We're going to run "finally" code as a coroutine
682663
// (not calling it recursively). Set up a sentinel
683-
// on a stack so it can return back to us when it is
664+
// on the stack so it can return back to us when it is
684665
// done (when WITH_CLEANUP or END_FINALLY reached).
685-
PUSH((mp_obj_t)unum); // push number of exception handlers left to unwind
686-
PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel
666+
// The sentinel is the number of exception handlers left to
667+
// unwind, which is a non-negative integer.
668+
PUSH(MP_OBJ_NEW_SMALL_INT(unum));
687669
ip = exc_sp->handler; // get exception handler byte code address
688670
exc_sp--; // pop exception handler
689671
goto dispatch_loop; // run the exception handler
@@ -720,11 +702,14 @@ unwind_jump:;
720702
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
721703
// We finished "finally" coroutine and now dispatch back
722704
// to our caller, based on TOS value
723-
mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP());
724-
if (reason == UNWIND_RETURN) {
705+
mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP());
706+
if (cause < 0) {
707+
// A negative cause indicates unwind return
725708
goto unwind_return;
726709
} else {
727-
assert(reason == UNWIND_JUMP);
710+
// Otherwise it's an unwind jump and we must push as a raw
711+
// number the number of exception handlers to unwind
712+
PUSH((mp_obj_t)cause);
728713
goto unwind_jump;
729714
}
730715
} else {
@@ -1101,7 +1086,7 @@ unwind_jump:;
11011086
// (not calling it recursively). Set up a sentinel
11021087
// on a stack so it can return back to us when it is
11031088
// done (when WITH_CLEANUP or END_FINALLY reached).
1104-
PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN));
1089+
PUSH(MP_OBJ_NEW_SMALL_INT(-1));
11051090
ip = exc_sp->handler;
11061091
exc_sp--;
11071092
goto dispatch_loop;

0 commit comments

Comments
 (0)