Skip to content

Commit

Permalink
py/objfun: Add function.__code__ attribute.
Browse files Browse the repository at this point in the history
This is used to provide introspection of attributes
such as function name or source file & line.

Signed-off-by: Andrew Leech <[email protected]>
  • Loading branch information
pi-anl committed Nov 23, 2023
1 parent 00d9ee4 commit aa3a436
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 16 deletions.
2 changes: 1 addition & 1 deletion py/emitbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ STATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp
STATIC void emit_write_bytecode_byte_child(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) {
emit_write_bytecode_byte_const(emit, stack_adj, b,
mp_emit_common_alloc_const_child(emit->emit_common, rc));
#if MICROPY_PY_SYS_SETTRACE
#if MICROPY_PY_SYS_SETTRACE || MICROPY_PY_FUNCTION_ATTRS
rc->line_of_definition = emit->last_source_line;
#endif
}
Expand Down
6 changes: 3 additions & 3 deletions py/emitglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ 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
#if MICROPY_PY_SYS_SETTRACE || MICROPY_PY_FUNCTION_ATTRS
rc->line_of_definition = 0;
#endif
return rc;
Expand Down Expand Up @@ -82,7 +82,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
rc->n_children = n_children;
#endif

#if MICROPY_PY_SYS_SETTRACE
#if MICROPY_PY_SYS_SETTRACE || MICROPY_PY_FUNCTION_ATTRS
mp_bytecode_prelude_t *prelude = &rc->prelude;
mp_prof_extract_prelude(code, prelude);
#endif
Expand Down Expand Up @@ -207,7 +207,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
}

#if MICROPY_PY_SYS_SETTRACE
#if MICROPY_PY_SYS_SETTRACE || MICROPY_PY_FUNCTION_ATTRS
mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t *)MP_OBJ_TO_PTR(fun);
self_fun->rc = rc;
#endif
Expand Down
4 changes: 1 addition & 3 deletions py/emitglue.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,14 @@ typedef struct _mp_raw_code_t {
size_t fun_data_len; // so mp_raw_code_save and mp_bytecode_print work
#endif
struct _mp_raw_code_t **children;
#if MICROPY_PERSISTENT_CODE_SAVE
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_PY_FUNCTION_ATTRS
size_t n_children;
#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;
#endif
Expand Down
8 changes: 8 additions & 0 deletions py/objfun.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "py/runtime.h"
#include "py/bc.h"
#include "py/stackctrl.h"
#include "py/profile.h"

#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
Expand Down Expand Up @@ -344,6 +345,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 (attr == MP_QSTR___code__) {
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_code_t *code = MP_OBJ_TO_PTR(mp_obj_new_code(self->context, self->rc));
if (code != NULL) {
dest[0] = MP_OBJ_FROM_PTR(code);
}
}
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion py/objfun.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ typedef struct _mp_obj_fun_bc_t {
const mp_module_context_t *context; // context within which this function was defined
struct _mp_raw_code_t *const *child_table; // table of children
const byte *bytecode; // bytecode for the function
#if MICROPY_PY_SYS_SETTRACE
#if MICROPY_PY_SYS_SETTRACE || MICROPY_PY_FUNCTION_ATTRS
const struct _mp_raw_code_t *rc;
#endif
// the following extra_args array is allocated space to take (in order):
Expand Down
23 changes: 22 additions & 1 deletion py/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@
#include "py/gc.h"
#include "py/objfun.h"

#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_PY_FUNCTION_ATTRS

#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
#define QSTR_MAP(context, idx) (context->constants.qstr_table[idx])
#else
#define QSTR_MAP(context, idx) ((idx)? idx: context->constants.source_file)
#endif

#if MICROPY_PY_SYS_SETTRACE

#if !MICROPY_PERSISTENT_CODE_SAVE
Expand All @@ -38,7 +46,8 @@
#endif

#define prof_trace_cb MP_STATE_THREAD(prof_trace_callback)
#define QSTR_MAP(context, idx) (context->constants.qstr_table[idx])

#endif // MICROPY_PY_SYS_SETTRACE

STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) {
const mp_bytecode_prelude_t *prelude = &rc->prelude;
Expand Down Expand Up @@ -101,7 +110,10 @@ STATIC mp_obj_tuple_t *code_consts(const mp_module_context_t *context, const mp_
return consts;
}

#if MICROPY_PY_SYS_SETTRACE
STATIC mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) {
// Returns a string encoding the mapping from bytecode offsets to line numbers.

// const mp_bytecode_prelude_t *prelude = &rc->prelude;
uint start = 0;
uint stop = rc->fun_data_len - start;
Expand Down Expand Up @@ -138,6 +150,7 @@ STATIC mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) {
m_del(byte, buffer, buffer_size);
return o;
}
#endif // MICROPY_PY_SYS_SETTRACE

STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (dest[0] != MP_OBJ_NULL) {
Expand All @@ -148,12 +161,14 @@ STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
const mp_raw_code_t *rc = o->rc;
const mp_bytecode_prelude_t *prelude = &rc->prelude;
switch (attr) {
#if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
case MP_QSTR_co_code:
dest[0] = mp_obj_new_bytes(
(void *)prelude->opcodes,
rc->fun_data_len - (prelude->opcodes - (const byte *)rc->fun_data)
);
break;
#endif
case MP_QSTR_co_consts:
dest[0] = MP_OBJ_FROM_PTR(code_consts(o->context, rc));
break;
Expand Down Expand Up @@ -199,12 +214,14 @@ STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
break;
}
#if MICROPY_PY_SYS_SETTRACE
case MP_QSTR_co_lnotab:
if (!o->lnotab) {
o->lnotab = raw_code_lnotab(rc);
}
dest[0] = o->lnotab;
break;
#endif
}
}

Expand All @@ -229,6 +246,8 @@ mp_obj_t mp_obj_new_code(const mp_module_context_t *context, const mp_raw_code_t
return MP_OBJ_FROM_PTR(o);
}

#if MICROPY_PY_SYS_SETTRACE

/******************************************************************************/
// frame object

Expand Down Expand Up @@ -1005,3 +1024,5 @@ void mp_prof_print_instr(const byte *ip, mp_code_state_t *code_state) {
#endif // MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE

#endif // MICROPY_PY_SYS_SETTRACE

#endif // MICROPY_PERSISTENT_CODE_SAVE || MICROPY_PY_FUNCTION_ATTRS
15 changes: 8 additions & 7 deletions py/profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@

#include "py/emitglue.h"

#if MICROPY_PY_SYS_SETTRACE

#define mp_prof_is_executing MP_STATE_THREAD(prof_callback_is_executing)

typedef struct _mp_obj_code_t {
// TODO this was 4 words
mp_obj_base_t base;
Expand All @@ -42,6 +38,14 @@ typedef struct _mp_obj_code_t {
mp_obj_t lnotab;
} mp_obj_code_t;

void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude);

mp_obj_t mp_obj_new_code(const mp_module_context_t *mc, const mp_raw_code_t *rc);

#if MICROPY_PY_SYS_SETTRACE

#define mp_prof_is_executing MP_STATE_THREAD(prof_callback_is_executing)

typedef struct _mp_obj_frame_t {
mp_obj_base_t base;
const mp_code_state_t *code_state;
Expand All @@ -53,9 +57,6 @@ typedef struct _mp_obj_frame_t {
bool trace_opcodes;
} mp_obj_frame_t;

void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude);

mp_obj_t mp_obj_new_code(const mp_module_context_t *mc, const mp_raw_code_t *rc);
mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state);

// This is the implementation for the sys.settrace
Expand Down

0 comments on commit aa3a436

Please sign in to comment.