diff options
author | Yusuke Endoh <mame@ruby-lang.org> | 2021-06-08 17:34:08 +0900 |
---|---|---|
committer | Yusuke Endoh <mame@ruby-lang.org> | 2021-06-18 03:35:38 +0900 |
commit | dfba87cd622f9699f54d1d0b8c057deb428874b6 (patch) | |
tree | bd07194e1c0dc96cd517cbf1e3c37389e5d48614 /vm_backtrace.c | |
parent | ea6062898ad0d66ede0a1866028c0605c357e2cb (diff) |
Make it possible to get AST::Node from Thread::Backtrace::Location
RubyVM::AST.of(Thread::Backtrace::Location) returns a node that
corresponds to the location. Typically, the node is a method call, but
not always.
This change also includes iseq's dump/load support of node_ids for each
instructions.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4558
Diffstat (limited to 'vm_backtrace.c')
-rw-r--r-- | vm_backtrace.c | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/vm_backtrace.c b/vm_backtrace.c index 01c9aeb355..d0fdda343f 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -34,7 +34,7 @@ id2str(ID id) #define ALL_BACKTRACE_LINES -1 inline static int -calc_lineno(const rb_iseq_t *iseq, const VALUE *pc) +calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id) { VM_ASSERT(iseq); VM_ASSERT(iseq->body); @@ -46,7 +46,11 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc) VM_ASSERT(! iseq->body->local_table_size); return 0; } - return FIX2INT(iseq->body->location.first_lineno); + if (lineno) *lineno = FIX2INT(iseq->body->location.first_lineno); +#ifdef EXPERIMENTAL_ISEQ_NODE_ID + if (node_id) *node_id = -1; +#endif + return 1; } else { ptrdiff_t n = pc - iseq->body->iseq_encoded; @@ -65,10 +69,32 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc) __builtin_trap(); } #endif - return rb_iseq_line_no(iseq, pos); + if (lineno) *lineno = rb_iseq_line_no(iseq, pos); +#ifdef EXPERIMENTAL_ISEQ_NODE_ID + if (node_id) *node_id = rb_iseq_node_id(iseq, pos); +#endif + return 1; } } +inline static int +calc_lineno(const rb_iseq_t *iseq, const VALUE *pc) +{ + int lineno; + if (calc_pos(iseq, pc, &lineno, NULL)) return lineno; + return 0; +} + +#ifdef EXPERIMENTAL_ISEQ_NODE_ID +inline static int +calc_node_id(const rb_iseq_t *iseq, const VALUE *pc) +{ + int node_id; + if (calc_pos(iseq, pc, NULL, &node_id)) return node_id; + return -1; +} +#endif + int rb_vm_get_sourceline(const rb_control_frame_t *cfp) { @@ -143,6 +169,12 @@ static const rb_data_type_t location_data_type = { 0, 0, RUBY_TYPED_FREE_IMMEDIATELY }; +int +rb_frame_info_p(VALUE obj) +{ + return rb_typeddata_is_kind_of(obj, &location_data_type); +} + static inline rb_backtrace_location_t * location_ptr(VALUE locobj) { @@ -287,6 +319,37 @@ location_path_m(VALUE self) return location_path(location_ptr(self)); } +#ifdef EXPERIMENTAL_ISEQ_NODE_ID +static int +location_node_id(rb_backtrace_location_t *loc) +{ + switch (loc->type) { + case LOCATION_TYPE_ISEQ: + return calc_node_id(loc->body.iseq.iseq, loc->body.iseq.pc); + case LOCATION_TYPE_CFUNC: + if (loc->body.cfunc.prev_loc) { + return location_node_id(loc->body.cfunc.prev_loc); + } + return -1; + default: + rb_bug("location_node_id: unreachable"); + UNREACHABLE; + } +} +#endif + +void +rb_frame_info_get(VALUE obj, VALUE *path, int *node_id) +{ +#ifdef EXPERIMENTAL_ISEQ_NODE_ID + rb_backtrace_location_t *loc = location_ptr(obj); + *path = location_path(loc); + *node_id = location_node_id(loc); +#else + *path = Qnil; +#endif +} + static VALUE location_realpath(rb_backtrace_location_t *loc) { |