py: Reduce size of VM exception stack element by 1 machine word.
This optimisation reduces the VM exception stack element (mp_exc_stack_t) by 1 word, by using bit 1 of a pointer to store whether the opcode was a FINALLY or WITH opcode. This optimisation was pending, waiting for maturity of the exception handling code, which has now proven itself. Saves 1 machine word RAM for each exception (4->3 words per exception). Increases stmhal code by 4 bytes, and decreases unix x64 code by 32 bytes.
This commit is contained in:
parent
81836c28b3
commit
74eb44c392
13
py/bc.h
13
py/bc.h
@ -28,12 +28,10 @@
|
||||
typedef struct _mp_exc_stack {
|
||||
const byte *handler;
|
||||
// bit 0 is saved currently_in_except_block value
|
||||
// bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY
|
||||
mp_obj_t *val_sp;
|
||||
// Saved exception, valid if currently_in_except_block bit is 1
|
||||
mp_obj_t prev_exc;
|
||||
// We might only have 2 interesting cases here: SETUP_EXCEPT & SETUP_FINALLY,
|
||||
// consider storing it in bit 1 of val_sp. TODO: SETUP_WITH?
|
||||
byte opcode;
|
||||
} mp_exc_stack_t;
|
||||
|
||||
typedef struct _mp_code_state {
|
||||
@ -56,7 +54,8 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
||||
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len);
|
||||
void mp_bytecode_print2(const byte *code, mp_uint_t len);
|
||||
|
||||
// Helper macros to access pointer with least significant bit holding a flag
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((mp_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | tag))
|
||||
// Helper macros to access pointer with least significant bits holding flags
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)3)))
|
||||
#define MP_TAGPTR_TAG0(x) ((mp_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_TAG1(x) ((mp_uint_t)(x) & 2)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | (tag)))
|
||||
|
18
py/vm.c
18
py/vm.c
@ -81,18 +81,17 @@ typedef enum {
|
||||
#define TOP() (*sp)
|
||||
#define SET_TOP(val) *sp = (val)
|
||||
|
||||
#define PUSH_EXC_BLOCK() do { \
|
||||
#define PUSH_EXC_BLOCK(with_or_finally) do { \
|
||||
DECODE_ULABEL; /* except labels are always forward */ \
|
||||
++exc_sp; \
|
||||
exc_sp->opcode = *code_state->ip; \
|
||||
exc_sp->handler = ip + ulab; \
|
||||
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
|
||||
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1) | currently_in_except_block); \
|
||||
exc_sp->prev_exc = MP_OBJ_NULL; \
|
||||
currently_in_except_block = 0; /* in a try block now */ \
|
||||
} while (0)
|
||||
|
||||
#define POP_EXC_BLOCK() \
|
||||
currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \
|
||||
currently_in_except_block = MP_TAGPTR_TAG0(exc_sp->val_sp); /* restore previous state */ \
|
||||
exc_sp--; /* pop back to previous exception handler */
|
||||
|
||||
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
|
||||
@ -130,7 +129,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
|
||||
mp_exc_stack_t *const exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state);
|
||||
|
||||
// variables that are visible to the exception handler (declared volatile)
|
||||
volatile bool currently_in_except_block = MP_TAGPTR_TAG(code_state->exc_sp); // 0 or 1, to detect nested exceptions
|
||||
volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions
|
||||
mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack
|
||||
|
||||
// outer exception handling loop
|
||||
@ -422,7 +421,7 @@ dispatch_loop:
|
||||
SET_TOP(mp_load_attr(obj, MP_QSTR___exit__));
|
||||
mp_load_method(obj, MP_QSTR___enter__, sp + 1);
|
||||
mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 1);
|
||||
PUSH_EXC_BLOCK();
|
||||
PUSH_EXC_BLOCK(1);
|
||||
PUSH(ret);
|
||||
DISPATCH();
|
||||
}
|
||||
@ -477,7 +476,6 @@ dispatch_loop:
|
||||
// to just execute finally handler normally (by pushing None
|
||||
// on value stack)
|
||||
assert(exc_sp >= exc_stack);
|
||||
assert(exc_sp->opcode == MP_BC_SETUP_WITH);
|
||||
POP_EXC_BLOCK();
|
||||
PUSH(mp_const_none);
|
||||
}
|
||||
@ -496,7 +494,7 @@ unwind_jump:;
|
||||
while ((unum & 0x7f) > 0) {
|
||||
unum -= 1;
|
||||
assert(exc_sp >= exc_stack);
|
||||
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
|
||||
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
|
||||
// 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
|
||||
@ -519,7 +517,7 @@ unwind_jump:;
|
||||
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
|
||||
ENTRY(MP_BC_SETUP_EXCEPT):
|
||||
ENTRY(MP_BC_SETUP_FINALLY): {
|
||||
PUSH_EXC_BLOCK();
|
||||
PUSH_EXC_BLOCK((*code_state->ip == MP_BC_SETUP_FINALLY) ? 1 : 0);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -759,7 +757,7 @@ unwind_jump:;
|
||||
ENTRY(MP_BC_RETURN_VALUE):
|
||||
unwind_return:
|
||||
while (exc_sp >= exc_stack) {
|
||||
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
|
||||
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
|
||||
// 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
|
||||
|
Loading…
Reference in New Issue
Block a user