Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ports/unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,12 @@ MP_NOINLINE int main_(int argc, char **argv) {
}
}

#if MICROPY_PY_SYS_SETTRACE
MP_STATE_THREAD(prof_trace_callback) = NULL;
#endif

#if MICROPY_PY_SYS_ATEXIT
// Beware, the sys.settrace callback should be disabled before running sys.atexit.
if (mp_obj_is_callable(MP_STATE_VM(sys_exitfunc))) {
mp_call_function_0(MP_STATE_VM(sys_exitfunc));
}
Expand Down
5 changes: 5 additions & 0 deletions ports/unix/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_ATEXIT (1)
#define MICROPY_PY_SYS_SETTRACE (0)
#if MICROPY_PY_SYS_SETTRACE
#define MICROPY_PERSISTENT_CODE_SAVE (1)
#define MICROPY_COMP_CONST (0)
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define MICROPY_PY_SYS_PLATFORM "darwin"
#else
Expand Down
5 changes: 5 additions & 0 deletions py/bc.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
code_state->prev = NULL;
#endif

#if MICROPY_PY_SYS_SETTRACE
code_state->prev_state = NULL;
code_state->frame = NULL;
#endif

// get params
size_t n_state = mp_decode_uint(&code_state->ip);
code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack
Expand Down
4 changes: 4 additions & 0 deletions py/bc.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ typedef struct _mp_code_state_t {
#if MICROPY_STACKLESS
struct _mp_code_state_t *prev;
#endif
#if MICROPY_PY_SYS_SETTRACE
struct _mp_code_state_t *prev_state;
struct _mp_obj_frame_t *frame;
#endif
// Variable-length
mp_obj_t state[0];
// Variable-length, never accessed by name, only as (void*)(state + n_state)
Expand Down
7 changes: 6 additions & 1 deletion py/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,9 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_

qstr qstr_exception_local = 0;
uint end_finally_label = comp_next_label(comp);

#if MICROPY_PY_SYS_SETTRACE
EMIT_ARG(set_source_line, pns_except->source_line);
#endif
if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) {
// this is a catch all exception handler
if (i + 1 != n_except) {
Expand Down Expand Up @@ -3154,6 +3156,9 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
scope_find_or_add_id(scope, MP_QSTR___class__, ID_INFO_KIND_LOCAL);
}

#if MICROPY_PY_SYS_SETTRACE
EMIT_ARG(set_source_line, pns->source_line);
#endif
compile_load_id(comp, MP_QSTR___name__);
compile_store_id(comp, MP_QSTR___module__);
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // 0 is class name
Expand Down
3 changes: 3 additions & 0 deletions py/emitbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, byte b, mp_raw_code_
assert(c == MP_ALIGN(c, sizeof(void*)));
*c = rc;
#endif
#if MICROPY_PY_SYS_SETTRACE
rc->line_of_definition = emit->last_source_line;
#endif
}

// unsigned labels are relative to ip following this instruction, stored as 16 bits
Expand Down
15 changes: 15 additions & 0 deletions py/emitglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "py/emitglue.h"
#include "py/runtime0.h"
#include "py/bc.h"
#include "py/profiling.h"

#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
Expand All @@ -52,6 +53,9 @@ mp_uint_t mp_verbose_flag = 0;
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
rc->kind = MP_CODE_RESERVED;
#if MICROPY_PY_SYS_SETTRACE
rc->line_of_definition = 0;
#endif
return rc;
}

Expand All @@ -75,6 +79,11 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
rc->n_raw_code = n_raw_code;
#endif

#if MICROPY_PY_SYS_SETTRACE
mp_bytecode_prelude_t *prelude = &rc->prelude;
prof_extract_prelude(code, prelude);
#endif

#ifdef DEBUG_PRINT
#if !MICROPY_DEBUG_PRINTERS
const size_t len = 0;
Expand Down Expand Up @@ -172,6 +181,12 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
}

#if MICROPY_PY_SYS_SETTRACE
mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(fun);
self_fun->rc = rc;
#endif

break;
}

Expand Down
28 changes: 28 additions & 0 deletions py/emitglue.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@

#include "py/obj.h"

#if MICROPY_PY_SYS_SETTRACE
typedef struct _mp_bytecode_prelude_t {
uint n_state;
uint n_exc_stack;
uint scope_flags;
uint n_pos_args;
uint n_kwonly_args;
uint n_def_pos_args;
// const char* source_file;
qstr qstr_source_file;
// const char* block_name;
qstr qstr_block_name;
const byte* code_info;
size_t code_info_size;
const byte* line_info;
const byte* locals;
const byte* bytecode;
} mp_bytecode_prelude_t;
#endif

// These variables and functions glue the code emitters to the runtime.

// These must fit in 8 bits; see scope.h
Expand Down Expand Up @@ -63,6 +83,14 @@ typedef struct _mp_raw_code_t {
size_t fun_data_len;
uint16_t n_obj;
uint16_t n_raw_code;
#if MICROPY_PY_SYS_SETTRACE
mp_bytecode_prelude_t prelude;
// `line_of_definition` is a Python source line where the raw_code was
// created e.g. MP_BC_MAKE_FUNCTION. This is different from lineno info
// stored in prelude, which provides line number for first statement of
// a function. Required to properly implement "call" trace event.
mp_uint_t line_of_definition;
#endif
#if MICROPY_EMIT_MACHINE_CODE
uint16_t prelude_offset;
uint16_t n_qstr;
Expand Down
20 changes: 20 additions & 0 deletions py/modsys.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@
#include "py/smallint.h"
#include "py/runtime.h"

#if MICROPY_PY_SYS_SETTRACE
#include "py/objmodule.h"
#include "py/profiling.h"

STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj);
#endif

#if MICROPY_PY_SYS

// defined per port; type of these is irrelevant, just need pointer
Expand Down Expand Up @@ -156,6 +163,15 @@ STATIC mp_obj_t mp_sys_atexit(mp_obj_t obj) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit);
#endif

#if MICROPY_PY_SYS_SETTRACE
// settrace(tracefunc): Set the system’s trace function.
STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) {
return prof_settrace(obj);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_settrace_obj, mp_sys_settrace);

#endif // MICROPY_PY_SYS_SETTRACE

STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) },

Expand Down Expand Up @@ -190,6 +206,10 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mp_sys_exit_obj) },
#endif

#if MICROPY_PY_SYS_SETTRACE
{ MP_ROM_QSTR(MP_QSTR_settrace), MP_ROM_PTR(&mp_sys_settrace_obj) },
#endif

#if MICROPY_PY_SYS_STDFILES
{ MP_ROM_QSTR(MP_QSTR_stdin), MP_ROM_PTR(&mp_sys_stdin_obj) },
{ MP_ROM_QSTR(MP_QSTR_stdout), MP_ROM_PTR(&mp_sys_stdout_obj) },
Expand Down
15 changes: 15 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,11 @@ typedef double mp_float_t;
#define MICROPY_PY_SYS_ATEXIT (0)
#endif

// Whether to provide "sys.settrace" function
#ifndef MICROPY_PY_SYS_SETTRACE
#define MICROPY_PY_SYS_SETTRACE (0)
#endif

// Whether to provide "sys.getsizeof" function
#ifndef MICROPY_PY_SYS_GETSIZEOF
#define MICROPY_PY_SYS_GETSIZEOF (0)
Expand Down Expand Up @@ -1571,4 +1576,14 @@ typedef double mp_float_t;
# define MP_WARN_CAT(x) (NULL)
#endif

// Feature dependency check.
#if MICROPY_PY_SYS_SETTRACE
#if !MICROPY_PERSISTENT_CODE_SAVE
#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_PERSISTENT_CODE_SAVE to be enabled!"
#endif
#if MICROPY_COMP_CONST
#error "MICROPY_PY_SYS_SETTRACE requires MICROPY_COMP_CONST to be disabled!"
#endif
#endif

#endif // MICROPY_INCLUDED_PY_MPCONFIG_H
6 changes: 6 additions & 0 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ typedef struct _mp_state_thread_t {
mp_obj_dict_t *dict_globals;

nlr_buf_t *nlr_top;

#if MICROPY_PY_SYS_SETTRACE
mp_obj_t prof_trace_callback;
bool prof_callback_is_executing;
struct _mp_code_state_t *current_code_state;
#endif // MICROPY_PY_SYS_SETTRACE
} mp_state_thread_t;

// This structure combines the above 3 structures.
Expand Down
7 changes: 7 additions & 0 deletions py/objfun.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,18 @@

#include "py/obj.h"

#if MICROPY_PY_SYS_SETTRACE
#include "py/emitglue.h"
#endif

typedef struct _mp_obj_fun_bc_t {
mp_obj_base_t base;
mp_obj_dict_t *globals; // the context within which this function was defined
const byte *bytecode; // bytecode for the function
const mp_uint_t *const_table; // constant table
#if MICROPY_PY_SYS_SETTRACE
const mp_raw_code_t *rc;
#endif
// the following extra_args array is allocated space to take (in order):
// - values of positional default args (if any)
// - a single slot for default kw args dict (if it has them)
Expand Down
Loading