From 749575097f1b5c738cd43dce6ef0960eee8af7a3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 28 Dec 2014 07:17:43 +0200 Subject: [PATCH] vm: Record exception ip only for instructions where exceptions may happen. Mirroring ip to a volatile memory variable for each opcode is an expensive operation. For quite a lot of often executed opcodes like stack manipulation or jumps, exceptions cannot actually happen. So, record ip only for opcode where that's possible. --- py/vm.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/py/vm.c b/py/vm.c index e7583ce076..ae66ed1fff 100644 --- a/py/vm.c +++ b/py/vm.c @@ -101,11 +101,19 @@ typedef enum { // MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp // MP_VM_RETURN_EXCEPTION, exception in fastn[0] mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc) { +#define SELECTIVE_EXC_IP (0) +#if SELECTIVE_EXC_IP +#define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip - 1; } +#define MARK_EXC_IP_GLOBAL() +#else +#define MARK_EXC_IP_SELECTIVE() +#define MARK_EXC_IP_GLOBAL() { code_state->ip = ip; } +#endif #if MICROPY_OPT_COMPUTED_GOTO #include "vmentrytable.h" #define DISPATCH() do { \ TRACE(ip); \ - code_state->ip = ip; \ + MARK_EXC_IP_GLOBAL(); \ goto *entry_table[*ip++]; \ } while(0) #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check @@ -161,7 +169,7 @@ dispatch_loop: DISPATCH(); #else TRACE(ip); - code_state->ip = ip; + MARK_EXC_IP_GLOBAL(); switch (*ip++) { #endif @@ -201,6 +209,7 @@ dispatch_loop: } ENTRY(MP_BC_LOAD_CONST_DEC): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_const_dec(qst)); DISPATCH(); @@ -228,6 +237,7 @@ dispatch_loop: load_check: if (obj_shared == MP_OBJ_NULL) { local_name_error: { + MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment"); RAISE(obj); } @@ -243,24 +253,28 @@ dispatch_loop: } ENTRY(MP_BC_LOAD_NAME): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_name(qst)); DISPATCH(); } ENTRY(MP_BC_LOAD_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_global(qst)); DISPATCH(); } ENTRY(MP_BC_LOAD_ATTR): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; SET_TOP(mp_load_attr(TOP(), qst)); DISPATCH(); } ENTRY(MP_BC_LOAD_METHOD): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_load_method(*sp, qst, sp); sp += 1; @@ -268,10 +282,12 @@ dispatch_loop: } ENTRY(MP_BC_LOAD_BUILD_CLASS): + MARK_EXC_IP_SELECTIVE(); PUSH(mp_load_build_class()); DISPATCH(); ENTRY(MP_BC_LOAD_SUBSCR): { + MARK_EXC_IP_SELECTIVE(); mp_obj_t index = POP(); SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL)); DISPATCH(); @@ -290,18 +306,21 @@ dispatch_loop: } ENTRY(MP_BC_STORE_NAME): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_name(qst, POP()); DISPATCH(); } ENTRY(MP_BC_STORE_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_global(qst, POP()); DISPATCH(); } ENTRY(MP_BC_STORE_ATTR): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_store_attr(sp[0], qst, sp[-1]); sp -= 2; @@ -309,11 +328,13 @@ dispatch_loop: } ENTRY(MP_BC_STORE_SUBSCR): + MARK_EXC_IP_SELECTIVE(); mp_obj_subscr(sp[-1], sp[0], sp[-2]); sp -= 3; DISPATCH(); ENTRY(MP_BC_DELETE_FAST): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; if (fastn[-unum] == MP_OBJ_NULL) { goto local_name_error; @@ -323,6 +344,7 @@ dispatch_loop: } ENTRY(MP_BC_DELETE_DEREF): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) { goto local_name_error; @@ -332,12 +354,14 @@ dispatch_loop: } ENTRY(MP_BC_DELETE_NAME): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_delete_name(qst); DISPATCH(); } ENTRY(MP_BC_DELETE_GLOBAL): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_delete_global(qst); DISPATCH(); @@ -417,6 +441,7 @@ dispatch_loop: } ENTRY(MP_BC_SETUP_WITH): { + MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = TOP(); SET_TOP(mp_load_attr(obj, MP_QSTR___exit__)); mp_load_method(obj, MP_QSTR___enter__, sp + 1); @@ -427,6 +452,7 @@ dispatch_loop: } ENTRY(MP_BC_WITH_CLEANUP): { + MARK_EXC_IP_SELECTIVE(); // Arriving here, there's "exception control block" on top of stack, // and __exit__ bound method underneath it. Bytecode calls __exit__, // and "deletes" it off stack, shifting "exception control block" @@ -486,6 +512,7 @@ dispatch_loop: } ENTRY(MP_BC_UNWIND_JUMP): { + MARK_EXC_IP_SELECTIVE(); DECODE_SLABEL; PUSH((void*)(ip + slab)); // push destination ip for jump PUSH((void*)(mp_uint_t)(*ip)); // push number of exception handlers to unwind (0x80 bit set if we also need to pop stack) @@ -517,11 +544,13 @@ unwind_jump:; // matched against: POP_BLOCK or POP_EXCEPT (anything else?) ENTRY(MP_BC_SETUP_EXCEPT): ENTRY(MP_BC_SETUP_FINALLY): { + MARK_EXC_IP_SELECTIVE(); PUSH_EXC_BLOCK((*code_state->ip == MP_BC_SETUP_FINALLY) ? 1 : 0); DISPATCH(); } ENTRY(MP_BC_END_FINALLY): + MARK_EXC_IP_SELECTIVE(); // not fully implemented // if TOS is an exception, reraises the exception (3 values on TOS) // if TOS is None, just pops it and continues @@ -549,10 +578,12 @@ unwind_jump:; DISPATCH(); ENTRY(MP_BC_GET_ITER): + MARK_EXC_IP_SELECTIVE(); SET_TOP(mp_getiter(TOP())); DISPATCH(); ENTRY(MP_BC_FOR_ITER): { + MARK_EXC_IP_SELECTIVE(); DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->sp = sp; assert(TOP()); @@ -594,6 +625,7 @@ unwind_jump:; DISPATCH(); ENTRY(MP_BC_BUILD_TUPLE): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_tuple(unum, sp)); @@ -601,6 +633,7 @@ unwind_jump:; } ENTRY(MP_BC_BUILD_LIST): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_list(unum, sp)); @@ -608,6 +641,7 @@ unwind_jump:; } ENTRY(MP_BC_LIST_APPEND): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // I think it's guaranteed by the compiler that sp[unum] is a list mp_obj_list_append(sp[-unum], sp[0]); @@ -616,17 +650,20 @@ unwind_jump:; } ENTRY(MP_BC_BUILD_MAP): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; PUSH(mp_obj_new_dict(unum)); DISPATCH(); } ENTRY(MP_BC_STORE_MAP): + MARK_EXC_IP_SELECTIVE(); sp -= 2; mp_obj_dict_store(sp[0], sp[2], sp[1]); DISPATCH(); ENTRY(MP_BC_MAP_ADD): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // I think it's guaranteed by the compiler that sp[-unum - 1] is a map mp_obj_dict_store(sp[-unum - 1], sp[0], sp[-1]); @@ -636,6 +673,7 @@ unwind_jump:; #if MICROPY_PY_BUILTINS_SET ENTRY(MP_BC_BUILD_SET): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; sp -= unum - 1; SET_TOP(mp_obj_new_set(unum, sp)); @@ -643,6 +681,7 @@ unwind_jump:; } ENTRY(MP_BC_SET_ADD): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // I think it's guaranteed by the compiler that sp[-unum] is a set mp_obj_set_store(sp[-unum], sp[0]); @@ -653,6 +692,7 @@ unwind_jump:; #if MICROPY_PY_BUILTINS_SLICE ENTRY(MP_BC_BUILD_SLICE): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; if (unum == 2) { mp_obj_t stop = POP(); @@ -669,6 +709,7 @@ unwind_jump:; #endif ENTRY(MP_BC_UNPACK_SEQUENCE): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; mp_unpack_sequence(sp[0], unum, sp); sp += unum - 1; @@ -676,6 +717,7 @@ unwind_jump:; } ENTRY(MP_BC_UNPACK_EX): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; mp_unpack_ex(sp[0], unum, sp); sp += (unum & 0xff) + ((unum >> 8) & 0xff); @@ -715,6 +757,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_FUNCTION): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword @@ -724,6 +767,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword @@ -735,6 +779,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_METHOD): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword @@ -744,6 +789,7 @@ unwind_jump:; } ENTRY(MP_BC_CALL_METHOD_VAR_KW): { + MARK_EXC_IP_SELECTIVE(); DECODE_UINT; // unum & 0xff == n_positional // (unum >> 8) & 0xff == n_keyword @@ -755,6 +801,7 @@ unwind_jump:; } ENTRY(MP_BC_RETURN_VALUE): + MARK_EXC_IP_SELECTIVE(); unwind_return: while (exc_sp >= exc_stack) { if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { @@ -778,6 +825,7 @@ unwind_return: return MP_VM_RETURN_NORMAL; ENTRY(MP_BC_RAISE_VARARGS): { + MARK_EXC_IP_SELECTIVE(); mp_uint_t unum = *ip++; mp_obj_t obj; assert(unum <= 1); @@ -810,6 +858,7 @@ yield: return MP_VM_RETURN_YIELD; ENTRY(MP_BC_YIELD_FROM): { + MARK_EXC_IP_SELECTIVE(); //#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) #define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) #define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { RAISE(t); } @@ -862,6 +911,7 @@ yield: } ENTRY(MP_BC_IMPORT_NAME): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = POP(); SET_TOP(mp_import_name(qst, obj, TOP())); @@ -869,6 +919,7 @@ yield: } ENTRY(MP_BC_IMPORT_FROM): { + MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t obj = mp_import_from(TOP(), qst); PUSH(obj); @@ -876,6 +927,7 @@ yield: } ENTRY(MP_BC_IMPORT_STAR): + MARK_EXC_IP_SELECTIVE(); mp_import_all(POP()); DISPATCH(); @@ -893,10 +945,12 @@ yield: DISPATCH(); ENTRY(MP_BC_UNARY_OP_MULTI): + MARK_EXC_IP_SELECTIVE(); SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); DISPATCH(); ENTRY(MP_BC_BINARY_OP_MULTI): { + MARK_EXC_IP_SELECTIVE(); mp_obj_t rhs = POP(); mp_obj_t lhs = TOP(); SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); @@ -904,6 +958,7 @@ yield: } ENTRY_DEFAULT: + MARK_EXC_IP_SELECTIVE(); #else ENTRY_DEFAULT: if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { @@ -938,6 +993,7 @@ yield: pending_exception_check: if (mp_pending_exception != MP_OBJ_NULL) { + MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = mp_pending_exception; mp_pending_exception = MP_OBJ_NULL; RAISE(obj);