summaryrefslogtreecommitdiff
path: root/vm_backtrace.c
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2021-06-08 17:34:08 +0900
committerYusuke Endoh <mame@ruby-lang.org>2021-06-18 03:35:38 +0900
commitdfba87cd622f9699f54d1d0b8c057deb428874b6 (patch)
treebd07194e1c0dc96cd517cbf1e3c37389e5d48614 /vm_backtrace.c
parentea6062898ad0d66ede0a1866028c0605c357e2cb (diff)
downloadruby-dfba87cd622f9699f54d1d0b8c057deb428874b6.tar.gz
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.
Diffstat (limited to 'vm_backtrace.c')
-rw-r--r--vm_backtrace.c69
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)
{