From 02db91a7a311a96dd82a497cf513137e04191b29 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 22 Aug 2019 12:39:07 +1000 Subject: [PATCH] py: Split RAISE_VARARGS opcode into 3 separate ones. From the beginning of this project the RAISE_VARARGS opcode was named and implemented following CPython, where it has an argument (to the opcode) counting how many args the raise takes: raise # 0 args (re-raise previous exception) raise exc # 1 arg raise exc from exc2 # 2 args (chained raise) In the bytecode this operation therefore takes 2 bytes, one for RAISE_VARARGS and one for the number of args. This patch splits this opcode into 3, where each is now a single byte. This reduces bytecode size by 1 byte for each use of raise. Every byte counts! It also has the benefit of reducing code size (on all ports except nanbox). --- py/bc0.h | 12 ++++---- py/emitbc.c | 11 ++------ py/showbc.c | 13 +++++++-- py/vm.c | 49 +++++++++++++++++---------------- py/vmentrytable.h | 4 ++- tests/cmdline/cmd_showbc.py.exp | 4 +-- 6 files changed, 50 insertions(+), 43 deletions(-) diff --git a/py/bc0.h b/py/bc0.h index f3044125b..7cf061fc4 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -46,7 +46,7 @@ #define MP_BC_BASE_VINT_O (0x30) // UUMMCCCC-------- #define MP_BC_BASE_JUMP_E (0x40) // J-JJJJJEEEEF---- #define MP_BC_BASE_BYTE_O (0x50) // LLLLSSDTTTTTEEFF -#define MP_BC_BASE_BYTE_E (0x60) // E-BRYYI--------- +#define MP_BC_BASE_BYTE_E (0x60) // --BREEEYYI------ #define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // LLLLLLLLLLLLLLLL // (0x80) // LLLLLLLLLLLLLLLL // (0x90) // LLLLLLLLLLLLLLLL @@ -128,9 +128,11 @@ #define MP_BC_UNPACK_EX (MP_BC_BASE_VINT_O + 0x01) // uint #define MP_BC_RETURN_VALUE (MP_BC_BASE_BYTE_E + 0x03) -#define MP_BC_RAISE_VARARGS (MP_BC_BASE_BYTE_E + 0x00) // extra byte -#define MP_BC_YIELD_VALUE (MP_BC_BASE_BYTE_E + 0x04) -#define MP_BC_YIELD_FROM (MP_BC_BASE_BYTE_E + 0x05) +#define MP_BC_RAISE_LAST (MP_BC_BASE_BYTE_E + 0x04) +#define MP_BC_RAISE_OBJ (MP_BC_BASE_BYTE_E + 0x05) +#define MP_BC_RAISE_FROM (MP_BC_BASE_BYTE_E + 0x06) +#define MP_BC_YIELD_VALUE (MP_BC_BASE_BYTE_E + 0x07) +#define MP_BC_YIELD_FROM (MP_BC_BASE_BYTE_E + 0x08) #define MP_BC_MAKE_FUNCTION (MP_BC_BASE_VINT_O + 0x02) // uint #define MP_BC_MAKE_FUNCTION_DEFARGS (MP_BC_BASE_VINT_O + 0x03) // uint @@ -143,6 +145,6 @@ #define MP_BC_IMPORT_NAME (MP_BC_BASE_QSTR_O + 0x0b) // qstr #define MP_BC_IMPORT_FROM (MP_BC_BASE_QSTR_O + 0x0c) // qstr -#define MP_BC_IMPORT_STAR (MP_BC_BASE_BYTE_E + 0x06) +#define MP_BC_IMPORT_STAR (MP_BC_BASE_BYTE_E + 0x09) #endif // MICROPY_INCLUDED_PY_BC0_H diff --git a/py/emitbc.c b/py/emitbc.c index 83fcbae41..a8d57d27b 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -193,13 +193,6 @@ STATIC void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) { c[0] = b1; } -STATIC void emit_write_bytecode_byte_byte(emit_t* emit, int stack_adj, byte b1, byte b2) { - mp_emit_bc_adjust_stack_size(emit, stack_adj); - byte *c = emit_get_cur_to_write_bytecode(emit, 2); - c[0] = b1; - c[1] = b2; -} - // Similar to emit_write_bytecode_uint(), just some extra handling to encode sign STATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) { emit_write_bytecode_byte(emit, stack_adj, b1); @@ -848,8 +841,10 @@ void mp_emit_bc_return_value(emit_t *emit) { } void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { + MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 1 == MP_BC_RAISE_OBJ); + MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 2 == MP_BC_RAISE_FROM); assert(n_args <= 2); - emit_write_bytecode_byte_byte(emit, -n_args, MP_BC_RAISE_VARARGS, n_args); + emit_write_bytecode_byte(emit, -n_args, MP_BC_RAISE_LAST + n_args); } void mp_emit_bc_yield(emit_t *emit, int kind) { diff --git a/py/showbc.c b/py/showbc.c index 8b97c8def..78b5b0141 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -500,9 +500,16 @@ const byte *mp_bytecode_print_str(const byte *ip) { printf("RETURN_VALUE"); break; - case MP_BC_RAISE_VARARGS: - unum = *ip++; - printf("RAISE_VARARGS " UINT_FMT, unum); + case MP_BC_RAISE_LAST: + printf("RAISE_LAST"); + break; + + case MP_BC_RAISE_OBJ: + printf("RAISE_OBJ"); + break; + + case MP_BC_RAISE_FROM: + printf("RAISE_FROM"); break; case MP_BC_YIELD_VALUE: diff --git a/py/vm.c b/py/vm.c index ef07b05a0..16b1348b4 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1162,32 +1162,33 @@ unwind_return: FRAME_LEAVE(); return MP_VM_RETURN_NORMAL; - ENTRY(MP_BC_RAISE_VARARGS): { + ENTRY(MP_BC_RAISE_LAST): { MARK_EXC_IP_SELECTIVE(); - mp_uint_t unum = *ip; - mp_obj_t obj; - if (unum == 2) { - mp_warning(NULL, "exception chaining not supported"); - // ignore (pop) "from" argument - sp--; - } - if (unum == 0) { - // search for the inner-most previous exception, to reraise it - obj = MP_OBJ_NULL; - for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) { - if (e->prev_exc != NULL) { - obj = MP_OBJ_FROM_PTR(e->prev_exc); - break; - } + // search for the inner-most previous exception, to reraise it + mp_obj_t obj = MP_OBJ_NULL; + for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; --e) { + if (e->prev_exc != NULL) { + obj = MP_OBJ_FROM_PTR(e->prev_exc); + break; } - if (obj == MP_OBJ_NULL) { - obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "no active exception to reraise"); - RAISE(obj); - } - } else { - obj = TOP(); } - obj = mp_make_raise_obj(obj); + if (obj == MP_OBJ_NULL) { + obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "no active exception to reraise"); + } + RAISE(obj); + } + + ENTRY(MP_BC_RAISE_OBJ): { + MARK_EXC_IP_SELECTIVE(); + mp_obj_t obj = mp_make_raise_obj(TOP()); + RAISE(obj); + } + + ENTRY(MP_BC_RAISE_FROM): { + MARK_EXC_IP_SELECTIVE(); + mp_warning(NULL, "exception chaining not supported"); + sp--; // ignore (pop) "from" argument + mp_obj_t obj = mp_make_raise_obj(TOP()); RAISE(obj); } @@ -1437,7 +1438,7 @@ unwind_loop: // - exceptions re-raised explicitly by "raise" if (nlr.ret_val != &mp_const_GeneratorExit_obj && *code_state->ip != MP_BC_END_FINALLY - && !(*code_state->ip == MP_BC_RAISE_VARARGS && code_state->ip[1] == 0)) { + && *code_state->ip != MP_BC_RAISE_LAST) { const byte *ip = code_state->fun_bc->bytecode; ip = mp_decode_uint_skip(ip); // skip n_state ip = mp_decode_uint_skip(ip); // skip n_exc_stack diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 32196c19f..7f55a4806 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -99,7 +99,9 @@ static const void *const entry_table[256] = { [MP_BC_CALL_METHOD] = &&entry_MP_BC_CALL_METHOD, [MP_BC_CALL_METHOD_VAR_KW] = &&entry_MP_BC_CALL_METHOD_VAR_KW, [MP_BC_RETURN_VALUE] = &&entry_MP_BC_RETURN_VALUE, - [MP_BC_RAISE_VARARGS] = &&entry_MP_BC_RAISE_VARARGS, + [MP_BC_RAISE_LAST] = &&entry_MP_BC_RAISE_LAST, + [MP_BC_RAISE_OBJ] = &&entry_MP_BC_RAISE_OBJ, + [MP_BC_RAISE_FROM] = &&entry_MP_BC_RAISE_FROM, [MP_BC_YIELD_VALUE] = &&entry_MP_BC_YIELD_VALUE, [MP_BC_YIELD_FROM] = &&entry_MP_BC_YIELD_FROM, [MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME, diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index f1ce02b67..839034a69 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -305,9 +305,9 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ BUILD_TUPLE 1 \\d\+ IMPORT_NAME 'a' \\d\+ IMPORT_STAR -\\d\+ RAISE_VARARGS 0 +\\d\+ RAISE_LAST \\d\+ LOAD_CONST_SMALL_INT 1 -\\d\+ RAISE_VARARGS 1 +\\d\+ RAISE_OBJ \\d\+ LOAD_CONST_NONE \\d\+ RETURN_VALUE \\d\+ LOAD_CONST_SMALL_INT 1