py: Replace POP_BLOCK and POP_EXCEPT opcodes with POP_EXCEPT_JUMP.

POP_BLOCK and POP_EXCEPT are now the same, and are always followed by a
JUMP.  So this optimisation reduces code size, and RAM usage of bytecode by
two bytes for each try-except handler.
This commit is contained in:
Damien George 2019-02-15 12:18:59 +11:00
parent 6f9e3ff719
commit 5a2599d962
11 changed files with 35 additions and 65 deletions

View File

@ -321,7 +321,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(O, O, U, U), // 0x38-0x3b
OC4(U, O, B, O), // 0x3c-0x3f
OC4(O, B, B, O), // 0x40-0x43
OC4(B, B, O, B), // 0x44-0x47
OC4(O, U, O, B), // 0x44-0x47
OC4(U, U, U, U), // 0x48-0x4b
OC4(U, U, U, U), // 0x4c-0x4f
OC4(V, V, U, V), // 0x50-0x53

View File

@ -77,8 +77,7 @@
#define MP_BC_END_FINALLY (0x41)
#define MP_BC_GET_ITER (0x42)
#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned
#define MP_BC_POP_BLOCK (0x44)
#define MP_BC_POP_EXCEPT (0x45)
#define MP_BC_POP_EXCEPT_JUMP (0x44) // rel byte code offset, 16-bit unsigned
#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte
#define MP_BC_GET_ITER_STACK (0x47)

View File

@ -1535,8 +1535,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
compile_increase_except_level(comp, l1, MP_EMIT_SETUP_BLOCK_EXCEPT);
compile_node(comp, pn_body); // body
EMIT(pop_block);
EMIT_ARG(jump, success_label); // jump over exception handler
EMIT_ARG(pop_except_jump, success_label, false); // jump over exception handler
EMIT_ARG(label_assign, l1); // start of exception handler
EMIT(start_except_handler);
@ -1607,8 +1606,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
compile_decrease_except_level(comp);
}
EMIT(pop_except);
EMIT_ARG(jump, l2);
EMIT_ARG(pop_except_jump, l2, true);
EMIT_ARG(label_assign, end_finally_label);
EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance
}
@ -1741,8 +1739,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns
compile_load_id(comp, context);
compile_await_object_method(comp, MP_QSTR___anext__);
c_assign(comp, pns->nodes[0], ASSIGN_STORE); // variable
EMIT(pop_block);
EMIT_ARG(jump, try_else_label);
EMIT_ARG(pop_except_jump, try_else_label, false);
EMIT_ARG(label_assign, try_exception_label);
EMIT(start_except_handler);
@ -1751,8 +1748,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns
EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);
EMIT_ARG(pop_jump_if, false, try_finally_label);
EMIT(pop_top); // pop exception instance
EMIT(pop_except);
EMIT_ARG(jump, while_else_label);
EMIT_ARG(pop_except_jump, while_else_label, true);
EMIT_ARG(label_assign, try_finally_label);
EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack

View File

@ -134,8 +134,7 @@ typedef struct _emit_method_table_t {
void (*get_iter)(emit_t *emit, bool use_stack);
void (*for_iter)(emit_t *emit, mp_uint_t label);
void (*for_iter_end)(emit_t *emit);
void (*pop_block)(emit_t *emit);
void (*pop_except)(emit_t *emit);
void (*pop_except_jump)(emit_t *emit, mp_uint_t label, bool within_exc_handler);
void (*unary_op)(emit_t *emit, mp_unary_op_t op);
void (*binary_op)(emit_t *emit, mp_binary_op_t op);
void (*build)(emit_t *emit, mp_uint_t n_args, int kind);
@ -232,8 +231,7 @@ void mp_emit_bc_end_finally(emit_t *emit);
void mp_emit_bc_get_iter(emit_t *emit, bool use_stack);
void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label);
void mp_emit_bc_for_iter_end(emit_t *emit);
void mp_emit_bc_pop_block(emit_t *emit);
void mp_emit_bc_pop_except(emit_t *emit);
void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler);
void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op);
void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op);
void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind);

View File

@ -764,14 +764,10 @@ void mp_emit_bc_for_iter_end(emit_t *emit) {
emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS);
}
void mp_emit_bc_pop_block(emit_t *emit) {
void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {
(void)within_exc_handler;
emit_bc_pre(emit, 0);
emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK);
}
void mp_emit_bc_pop_except(emit_t *emit) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT);
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_POP_EXCEPT_JUMP, label);
}
void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
@ -958,8 +954,7 @@ const emit_method_table_t emit_bc_method_table = {
mp_emit_bc_get_iter,
mp_emit_bc_for_iter,
mp_emit_bc_for_iter_end,
mp_emit_bc_pop_block,
mp_emit_bc_pop_except,
mp_emit_bc_pop_except_jump,
mp_emit_bc_unary_op,
mp_emit_bc_binary_op,
mp_emit_bc_build,

View File

@ -1916,7 +1916,7 @@ STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc
prev_finally->unwind_label = UNWIND_LABEL_DO_FINAL_UNWIND;
ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR);
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET);
// Cancel any active exception (see also emit_native_pop_except)
// Cancel any active exception (see also emit_native_pop_except_jump)
emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ);
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET);
// Jump to the innermost active finally
@ -2111,18 +2111,15 @@ STATIC void emit_native_for_iter_end(emit_t *emit) {
emit_post(emit);
}
STATIC void emit_native_pop_block(emit_t *emit) {
emit_native_pre(emit);
if (!emit->exc_stack[emit->exc_stack_size - 1].is_finally) {
emit_native_leave_exc_stack(emit, false);
}
emit_post(emit);
}
STATIC void emit_native_pop_except(emit_t *emit) {
STATIC void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {
if (within_exc_handler) {
// Cancel any active exception so subsequent handlers don't see it
emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ);
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
} else {
emit_native_leave_exc_stack(emit, false);
}
emit_native_jump(emit, label);
}
STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
@ -2726,8 +2723,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_get_iter,
emit_native_for_iter,
emit_native_for_iter_end,
emit_native_pop_block,
emit_native_pop_except,
emit_native_pop_except_jump,
emit_native_unary_op,
emit_native_binary_op,
emit_native_build,

View File

@ -401,14 +401,9 @@ const byte *mp_bytecode_print_str(const byte *ip) {
printf("FOR_ITER " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));
break;
case MP_BC_POP_BLOCK:
// pops block and restores the stack
printf("POP_BLOCK");
break;
case MP_BC_POP_EXCEPT:
// pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
printf("POP_EXCEPT");
case MP_BC_POP_EXCEPT_JUMP:
DECODE_ULABEL; // these labels are always forward
printf("POP_EXCEPT_JUMP " UINT_FMT, (mp_uint_t)(ip + unum - mp_showbc_code_start));
break;
case MP_BC_BUILD_TUPLE:

14
py/vm.c
View File

@ -759,17 +759,13 @@ unwind_jump:;
}
// matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
ENTRY(MP_BC_POP_BLOCK):
// we are exiting an exception handler, so pop the last one of the exception-stack
ENTRY(MP_BC_POP_EXCEPT_JUMP): {
assert(exc_sp >= exc_stack);
POP_EXC_BLOCK();
DISPATCH();
// matched against: SETUP_EXCEPT
ENTRY(MP_BC_POP_EXCEPT):
assert(exc_sp >= exc_stack);
POP_EXC_BLOCK();
DISPATCH();
DECODE_ULABEL;
ip += ulab;
DISPATCH_WITH_PEND_EXC_CHECK();
}
ENTRY(MP_BC_BUILD_TUPLE): {
MARK_EXC_IP_SELECTIVE();

View File

@ -76,8 +76,7 @@ static const void *const entry_table[256] = {
[MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER,
[MP_BC_GET_ITER_STACK] = &&entry_MP_BC_GET_ITER_STACK,
[MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER,
[MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK,
[MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT,
[MP_BC_POP_EXCEPT_JUMP] = &&entry_MP_BC_POP_EXCEPT_JUMP,
[MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE,
[MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST,
[MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP,

View File

@ -257,13 +257,11 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ JUMP \\d\+
\\d\+ LOAD_FAST 0
\\d\+ POP_JUMP_IF_TRUE \\d\+
\\d\+ POP_BLOCK
\\d\+ JUMP \\d\+
\\d\+ POP_EXCEPT_JUMP \\d\+
\\d\+ POP_TOP
\\d\+ LOAD_DEREF 14
\\d\+ POP_TOP
\\d\+ POP_EXCEPT
\\d\+ JUMP \\d\+
\\d\+ POP_EXCEPT_JUMP \\d\+
\\d\+ END_FINALLY
\\d\+ LOAD_CONST_NONE
\\d\+ LOAD_FAST 1
@ -272,11 +270,9 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ JUMP \\d\+
\\d\+ SETUP_EXCEPT \\d\+
\\d\+ UNWIND_JUMP \\d\+ 1
\\d\+ POP_BLOCK
\\d\+ JUMP \\d\+
\\d\+ POP_EXCEPT_JUMP \\d\+
\\d\+ POP_TOP
\\d\+ POP_EXCEPT
\\d\+ JUMP \\d\+
\\d\+ POP_EXCEPT_JUMP \\d\+
\\d\+ END_FINALLY
\\d\+ LOAD_FAST 0
\\d\+ POP_JUMP_IF_TRUE \\d\+

View File

@ -105,7 +105,7 @@ def make_opcode_format():
OC4(O, O, U, U), # 0x38-0x3b
OC4(U, O, B, O), # 0x3c-0x3f
OC4(O, B, B, O), # 0x40-0x43
OC4(B, B, O, B), # 0x44-0x47
OC4(O, U, O, B), # 0x44-0x47
OC4(U, U, U, U), # 0x48-0x4b
OC4(U, U, U, U), # 0x4c-0x4f
OC4(V, V, U, V), # 0x50-0x53