summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-02-08 13:30:33 +1100
committerDamien George <damien.p.george@gmail.com>2018-02-08 13:30:33 +1100
commit0c650d427601d5c84bd623d58abc9be5451c576c (patch)
tree8b739915dcdb48e224b0834a0a3cee9f8f6887ba
parent0b12cc8febe11e43c012b12cb2d6ad59bbda4724 (diff)
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
-rw-r--r--py/vm.c61
1 files changed, 23 insertions, 38 deletions
diff --git a/py/vm.c b/py/vm.c
index b18a2b5e3..c629a61e2 100644
--- a/py/vm.c
+++ b/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;