diff --git a/lib/micropython-lib b/lib/micropython-lib index 5b496e944ec04..f345a0db99b9d 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit 5b496e944ec045177afa1620920a168410b7f60b +Subproject commit f345a0db99b9dc454ffcbfb13bfb68978467018d diff --git a/ports/unix/variants/standard/mpconfigvariant.h b/ports/unix/variants/standard/mpconfigvariant.h index 75201e9abc8d6..447832a7656b6 100644 --- a/ports/unix/variants/standard/mpconfigvariant.h +++ b/ports/unix/variants/standard/mpconfigvariant.h @@ -27,5 +27,7 @@ // Set base feature level. #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) +#define MICROPY_PY_SYS_SETTRACE (1) + // Enable extra Unix features. #include "../mpconfigvariant_common.h" diff --git a/py/modsys.c b/py/modsys.c index 9ab02293b9063..3ce14bf5d17ad 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -238,6 +238,21 @@ static mp_obj_t mp_sys_settrace(mp_obj_t obj) { return mp_prof_settrace(obj); } MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace); + +static mp_obj_t mp_sys_gettrace() { + return mp_prof_gettrace(); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_gettrace_obj, mp_sys_gettrace); + +// _getframe(): Return current frame object. +static mp_obj_t mp_sys__getframe(size_t n_args, const mp_obj_t *args) { + size_t depth = 0; + if (n_args == 1) { + depth = mp_obj_get_int(args[0]); + } + return mp_prof_get_frame(depth); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_getframe_obj, 0, 1, mp_sys__getframe); #endif // MICROPY_PY_SYS_SETTRACE #if MICROPY_PY_SYS_PATH && !MICROPY_PY_SYS_ATTR_DELEGATION @@ -322,6 +337,8 @@ static const mp_rom_map_elem_t mp_module_sys_globals_table[] = { #if MICROPY_PY_SYS_SETTRACE { MP_ROM_QSTR(MP_QSTR_settrace), MP_ROM_PTR(&mp_sys_settrace_obj) }, + { MP_ROM_QSTR(MP_QSTR_gettrace), MP_ROM_PTR(&mp_sys_gettrace_obj) }, + { MP_ROM_QSTR(MP_QSTR__getframe), MP_ROM_PTR(&mp_sys_getframe_obj) }, #endif #if MICROPY_PY_SYS_STDFILES diff --git a/py/objfun.c b/py/objfun.c index a742c5267254c..f71f7c9ee32bb 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -34,7 +34,8 @@ #include "py/objfun.h" #include "py/runtime.h" #include "py/bc.h" -#include "py/cstack.h" +#include "py/stackctrl.h" +#include "py/profile.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) @@ -366,17 +367,13 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); dest[0] = MP_OBJ_FROM_PTR(self->context->module.globals); } - #if MICROPY_PY_FUNCTION_ATTRS_CODE + + #if MICROPY_PY_SYS_SETTRACE if (attr == MP_QSTR___code__) { - const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); - if ((self->base.type == &mp_type_fun_bc - || self->base.type == &mp_type_gen_wrap) - && self->child_table == NULL) { - #if MICROPY_PY_BUILTINS_CODE <= MICROPY_PY_BUILTINS_CODE_BASIC - dest[0] = mp_obj_new_code(self->context->constants, self->bytecode); - #else - dest[0] = mp_obj_new_code(self->context, self->rc, true); - #endif + mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t code_obj = mp_obj_new_code(self->context, self->rc, false); + if (code_obj != MP_OBJ_NULL) { + dest[0] = code_obj; } } #endif diff --git a/py/profile.c b/py/profile.c index 397d0291f9fad..4b813bb0d7b06 100644 --- a/py/profile.c +++ b/py/profile.c @@ -86,17 +86,26 @@ static void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t } static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - if (dest[0] != MP_OBJ_NULL) { + mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in); + + if (dest[0] == MP_OBJ_SENTINEL) { + // store attr + switch (attr) { + case MP_QSTR_f_trace: + o->f_trace = dest[1]; + dest[0] = MP_OBJ_NULL; + break; + } + return; + } else if (dest[0] != MP_OBJ_NULL) { // not load attribute return; } - mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in); - switch (attr) { case MP_QSTR_f_back: dest[0] = mp_const_none; - if (o->code_state->prev_state) { + if (o->code_state->prev_state && o->code_state->prev_state->frame) { dest[0] = MP_OBJ_FROM_PTR(o->code_state->prev_state->frame); } break; @@ -112,6 +121,12 @@ static void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { case MP_QSTR_f_lineno: dest[0] = MP_OBJ_NEW_SMALL_INT(o->lineno); break; + case MP_QSTR_f_trace: + dest[0] = o->f_trace; + break; + case MP_QSTR_f_locals: + dest[0] = mp_obj_new_dict(0); + break; } } @@ -148,6 +163,7 @@ mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) { o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); o->trace_opcodes = false; o->callback = MP_OBJ_NULL; + o->f_trace = MP_OBJ_NULL; return MP_OBJ_FROM_PTR(o); } @@ -187,6 +203,33 @@ mp_obj_t mp_prof_settrace(mp_obj_t callback) { return mp_const_none; } +mp_obj_t mp_prof_gettrace(void) { + if (prof_trace_cb == MP_OBJ_NULL) { + return mp_const_none; + } + return prof_trace_cb; +} + +mp_obj_t mp_prof_get_frame(size_t depth) { + + mp_code_state_t *code_state = MP_STATE_THREAD(current_code_state); + + for (size_t i = 0; i < depth; i++) { + code_state = code_state->prev_state; + if (code_state == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("call stack is not deep enough")); + } + } + + mp_obj_frame_t *frame = MP_OBJ_TO_PTR(mp_obj_new_frame(code_state)); + if (frame == NULL) { + // Couldn't allocate a frame object + return MP_OBJ_NULL; + } + + return MP_OBJ_FROM_PTR(frame); +} + mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state) { assert(!mp_prof_is_executing); diff --git a/py/profile.h b/py/profile.h index db72b9f076818..352deb34e23bc 100644 --- a/py/profile.h +++ b/py/profile.h @@ -43,6 +43,7 @@ typedef struct _mp_obj_frame_t { mp_uint_t lasti; mp_uint_t lineno; bool trace_opcodes; + mp_obj_t f_trace; } mp_obj_frame_t; uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc); @@ -52,7 +53,9 @@ mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state); // This is the implementation for the sys.settrace mp_obj_t mp_prof_settrace(mp_obj_t callback); +mp_obj_t mp_prof_gettrace(void); +mp_obj_t mp_prof_get_frame(size_t depth); mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state); mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state); diff --git a/tests/misc/sys__getframe.py b/tests/misc/sys__getframe.py new file mode 100644 index 0000000000000..800921a41d493 --- /dev/null +++ b/tests/misc/sys__getframe.py @@ -0,0 +1,27 @@ +import sys + +try: + sys._getframe +except AttributeError: + print("SKIP") + raise SystemExit + +top_frame = sys._getframe() + +print(top_frame.f_code.co_name == "") + + +def new_frame(): + curr_frame = sys._getframe() + prev_frame = sys._getframe(1) + + print(curr_frame.f_code.co_name == "new_frame") + + print(prev_frame.f_code.co_name == "") + print(curr_frame.f_back.f_code.co_name == "") + + print(prev_frame.f_lineno == curr_frame.f_back.f_lineno) + print(prev_frame.f_code.co_filename == curr_frame.f_back.f_code.co_filename) + + +new_frame()