Skip to content

Commit 74eb44c

Browse files
committed
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.
1 parent 81836c2 commit 74eb44c

File tree

2 files changed

+14
-17
lines changed

2 files changed

+14
-17
lines changed

py/bc.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@
2828
typedef struct _mp_exc_stack {
2929
const byte *handler;
3030
// bit 0 is saved currently_in_except_block value
31+
// bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY
3132
mp_obj_t *val_sp;
3233
// Saved exception, valid if currently_in_except_block bit is 1
3334
mp_obj_t prev_exc;
34-
// We might only have 2 interesting cases here: SETUP_EXCEPT & SETUP_FINALLY,
35-
// consider storing it in bit 1 of val_sp. TODO: SETUP_WITH?
36-
byte opcode;
3735
} mp_exc_stack_t;
3836

3937
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
5654
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len);
5755
void mp_bytecode_print2(const byte *code, mp_uint_t len);
5856

59-
// Helper macros to access pointer with least significant bit holding a flag
60-
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
61-
#define MP_TAGPTR_TAG(x) ((mp_uint_t)(x) & 1)
62-
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | tag))
57+
// Helper macros to access pointer with least significant bits holding flags
58+
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)3)))
59+
#define MP_TAGPTR_TAG0(x) ((mp_uint_t)(x) & 1)
60+
#define MP_TAGPTR_TAG1(x) ((mp_uint_t)(x) & 2)
61+
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | (tag)))

py/vm.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,17 @@ typedef enum {
8181
#define TOP() (*sp)
8282
#define SET_TOP(val) *sp = (val)
8383

84-
#define PUSH_EXC_BLOCK() do { \
84+
#define PUSH_EXC_BLOCK(with_or_finally) do { \
8585
DECODE_ULABEL; /* except labels are always forward */ \
8686
++exc_sp; \
87-
exc_sp->opcode = *code_state->ip; \
8887
exc_sp->handler = ip + ulab; \
89-
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
88+
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, ((with_or_finally) << 1) | currently_in_except_block); \
9089
exc_sp->prev_exc = MP_OBJ_NULL; \
9190
currently_in_except_block = 0; /* in a try block now */ \
9291
} while (0)
9392

9493
#define POP_EXC_BLOCK() \
95-
currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \
94+
currently_in_except_block = MP_TAGPTR_TAG0(exc_sp->val_sp); /* restore previous state */ \
9695
exc_sp--; /* pop back to previous exception handler */
9796

9897
// 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
130129
mp_exc_stack_t *const exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state);
131130

132131
// variables that are visible to the exception handler (declared volatile)
133-
volatile bool currently_in_except_block = MP_TAGPTR_TAG(code_state->exc_sp); // 0 or 1, to detect nested exceptions
132+
volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions
134133
mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack
135134

136135
// outer exception handling loop
@@ -422,7 +421,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
422421
SET_TOP(mp_load_attr(obj, MP_QSTR___exit__));
423422
mp_load_method(obj, MP_QSTR___enter__, sp + 1);
424423
mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 1);
425-
PUSH_EXC_BLOCK();
424+
PUSH_EXC_BLOCK(1);
426425
PUSH(ret);
427426
DISPATCH();
428427
}
@@ -477,7 +476,6 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
477476
// to just execute finally handler normally (by pushing None
478477
// on value stack)
479478
assert(exc_sp >= exc_stack);
480-
assert(exc_sp->opcode == MP_BC_SETUP_WITH);
481479
POP_EXC_BLOCK();
482480
PUSH(mp_const_none);
483481
}
@@ -496,7 +494,7 @@ unwind_jump:;
496494
while ((unum & 0x7f) > 0) {
497495
unum -= 1;
498496
assert(exc_sp >= exc_stack);
499-
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
497+
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
500498
// We're going to run "finally" code as a coroutine
501499
// (not calling it recursively). Set up a sentinel
502500
// on a stack so it can return back to us when it is
@@ -519,7 +517,7 @@ unwind_jump:;
519517
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
520518
ENTRY(MP_BC_SETUP_EXCEPT):
521519
ENTRY(MP_BC_SETUP_FINALLY): {
522-
PUSH_EXC_BLOCK();
520+
PUSH_EXC_BLOCK((*code_state->ip == MP_BC_SETUP_FINALLY) ? 1 : 0);
523521
DISPATCH();
524522
}
525523

@@ -759,7 +757,7 @@ unwind_jump:;
759757
ENTRY(MP_BC_RETURN_VALUE):
760758
unwind_return:
761759
while (exc_sp >= exc_stack) {
762-
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
760+
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
763761
// We're going to run "finally" code as a coroutine
764762
// (not calling it recursively). Set up a sentinel
765763
// on a stack so it can return back to us when it is

0 commit comments

Comments
 (0)