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.
pull/1020/merge
Damien George 2014-12-22 12:49:57 +00:00
rodzic 81836c28b3
commit 74eb44c392
2 zmienionych plików z 14 dodań i 17 usunięć

13
py/bc.h
Wyświetl plik

@ -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
Wyświetl plik

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