mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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.
This commit is contained in:
parent
ea6062898a
commit
dfba87cd62
Notes:
git
2021-06-18 03:35:59 +09:00
5 changed files with 107 additions and 21 deletions
27
ast.c
27
ast.c
|
@ -197,23 +197,26 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE save_script
|
||||||
{
|
{
|
||||||
VALUE path, node, lines;
|
VALUE path, node, lines;
|
||||||
int node_id;
|
int node_id;
|
||||||
const rb_iseq_t *iseq = NULL;
|
|
||||||
|
|
||||||
if (rb_obj_is_proc(body)) {
|
if (rb_frame_info_p(body)) {
|
||||||
iseq = vm_proc_iseq(body);
|
rb_frame_info_get(body, &path, &node_id);
|
||||||
|
if (NIL_P(path)) return Qnil;
|
||||||
if (!rb_obj_is_iseq((VALUE)iseq)) {
|
|
||||||
iseq = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iseq = rb_method_iseq(body);
|
const rb_iseq_t *iseq = NULL;
|
||||||
|
|
||||||
|
if (rb_obj_is_proc(body)) {
|
||||||
|
iseq = vm_proc_iseq(body);
|
||||||
|
|
||||||
|
if (!rb_obj_is_iseq((VALUE)iseq)) return Qnil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iseq = rb_method_iseq(body);
|
||||||
|
}
|
||||||
|
path = rb_iseq_path(iseq);
|
||||||
|
node_id = iseq->body->location.node_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iseq) return Qnil;
|
|
||||||
|
|
||||||
path = rb_iseq_path(iseq);
|
|
||||||
node_id = iseq->body->location.node_id;
|
|
||||||
if (!NIL_P(lines = script_lines(path))) {
|
if (!NIL_P(lines = script_lines(path))) {
|
||||||
node = rb_ast_parse_array(lines, save_script_lines);
|
node = rb_ast_parse_array(lines, save_script_lines);
|
||||||
}
|
}
|
||||||
|
|
28
compile.c
28
compile.c
|
@ -9704,13 +9704,13 @@ event_name_to_flag(VALUE sym)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
|
iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
|
||||||
VALUE body, VALUE labels_wrapper)
|
VALUE body, VALUE node_ids, VALUE labels_wrapper)
|
||||||
{
|
{
|
||||||
/* TODO: body should be frozen */
|
/* TODO: body should be frozen */
|
||||||
long i, len = RARRAY_LEN(body);
|
long i, len = RARRAY_LEN(body);
|
||||||
struct st_table *labels_table = DATA_PTR(labels_wrapper);
|
struct st_table *labels_table = DATA_PTR(labels_wrapper);
|
||||||
int j;
|
int j;
|
||||||
int line_no = 0;
|
int line_no = 0, node_id = -1, insn_idx = 0;
|
||||||
int ret = COMPILE_OK;
|
int ret = COMPILE_OK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -9744,6 +9744,10 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
|
||||||
st_data_t insn_id;
|
st_data_t insn_id;
|
||||||
VALUE insn;
|
VALUE insn;
|
||||||
|
|
||||||
|
if (node_ids) {
|
||||||
|
node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
|
||||||
|
}
|
||||||
|
|
||||||
insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
|
insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
|
||||||
if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
|
if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
|
||||||
/* TODO: exception */
|
/* TODO: exception */
|
||||||
|
@ -9764,7 +9768,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
|
||||||
argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
|
argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
|
||||||
|
|
||||||
// add element before operand setup to make GC root
|
// add element before operand setup to make GC root
|
||||||
NODE dummy_line_node = generate_dummy_line_node(line_no, -1);
|
NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
|
||||||
ADD_ELEM(anchor,
|
ADD_ELEM(anchor,
|
||||||
(LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
|
(LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
|
||||||
(enum ruby_vminsn_type)insn_id, argc, argv));
|
(enum ruby_vminsn_type)insn_id, argc, argv));
|
||||||
|
@ -9848,7 +9852,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NODE dummy_line_node = generate_dummy_line_node(line_no, -1);
|
NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
|
||||||
ADD_ELEM(anchor,
|
ADD_ELEM(anchor,
|
||||||
(LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
|
(LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
|
||||||
(enum ruby_vminsn_type)insn_id, argc, NULL));
|
(enum ruby_vminsn_type)insn_id, argc, NULL));
|
||||||
|
@ -10054,6 +10058,14 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
|
||||||
#undef INT_PARAM
|
#undef INT_PARAM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE node_ids = Qfalse;
|
||||||
|
#ifdef EXPERIMENTAL_ISEQ_NODE_ID
|
||||||
|
node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
|
||||||
|
if (!RB_TYPE_P(node_ids, T_ARRAY)) {
|
||||||
|
rb_raise(rb_eTypeError, "node_ids is not an array");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
|
if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
|
||||||
len = RARRAY_LENINT(arg_opt_labels);
|
len = RARRAY_LENINT(arg_opt_labels);
|
||||||
iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
|
iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
|
||||||
|
@ -10103,7 +10115,7 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
|
||||||
iseq_build_from_ary_exception(iseq, labels_table, exception);
|
iseq_build_from_ary_exception(iseq, labels_table, exception);
|
||||||
|
|
||||||
/* body */
|
/* body */
|
||||||
iseq_build_from_ary_body(iseq, anchor, body, labels_wrapper);
|
iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
|
||||||
|
|
||||||
iseq->body->param.size = arg_size;
|
iseq->body->param.size = arg_size;
|
||||||
iseq->body->local_table_size = local_size;
|
iseq->body->local_table_size = local_size;
|
||||||
|
@ -10928,6 +10940,9 @@ ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < iseq->body->insns_info.size; i++) {
|
for (i = 0; i < iseq->body->insns_info.size; i++) {
|
||||||
ibf_dump_write_small_value(dump, entries[i].line_no);
|
ibf_dump_write_small_value(dump, entries[i].line_no);
|
||||||
|
#ifdef EXPERIMENTAL_ISEQ_NODE_ID
|
||||||
|
ibf_dump_write_small_value(dump, entries[i].node_id);
|
||||||
|
#endif
|
||||||
ibf_dump_write_small_value(dump, entries[i].events);
|
ibf_dump_write_small_value(dump, entries[i].events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10943,6 +10958,9 @@ ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset,
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
|
entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
|
||||||
|
#ifdef EXPERIMENTAL_ISEQ_NODE_ID
|
||||||
|
entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
|
||||||
|
#endif
|
||||||
entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
|
entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,8 @@ int rb_backtrace_p(VALUE obj);
|
||||||
VALUE rb_backtrace_to_str_ary(VALUE obj);
|
VALUE rb_backtrace_to_str_ary(VALUE obj);
|
||||||
VALUE rb_backtrace_to_location_ary(VALUE obj);
|
VALUE rb_backtrace_to_location_ary(VALUE obj);
|
||||||
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
|
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
|
||||||
|
int rb_frame_info_p(VALUE obj);
|
||||||
|
void rb_frame_info_get(VALUE obj, VALUE *path, int *node_id);
|
||||||
|
|
||||||
MJIT_SYMBOL_EXPORT_BEGIN
|
MJIT_SYMBOL_EXPORT_BEGIN
|
||||||
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
|
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
|
||||||
|
|
2
iseq.c
2
iseq.c
|
@ -2998,7 +2998,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
|
||||||
INT2FIX(iseq_body->location.code_location.end_pos.lineno),
|
INT2FIX(iseq_body->location.code_location.end_pos.lineno),
|
||||||
INT2FIX(iseq_body->location.code_location.end_pos.column)));
|
INT2FIX(iseq_body->location.code_location.end_pos.column)));
|
||||||
#ifdef EXPERIMENTAL_ISEQ_NODE_ID
|
#ifdef EXPERIMENTAL_ISEQ_NODE_ID
|
||||||
rb_hash_aset(misc, ID2SYM(rb_intern("node_ids_for_each_insn")), node_ids);
|
rb_hash_aset(misc, ID2SYM(rb_intern("node_ids")), node_ids);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -34,7 +34,7 @@ id2str(ID id)
|
||||||
#define ALL_BACKTRACE_LINES -1
|
#define ALL_BACKTRACE_LINES -1
|
||||||
|
|
||||||
inline static int
|
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);
|
||||||
VM_ASSERT(iseq->body);
|
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);
|
VM_ASSERT(! iseq->body->local_table_size);
|
||||||
return 0;
|
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 {
|
else {
|
||||||
ptrdiff_t n = pc - iseq->body->iseq_encoded;
|
ptrdiff_t n = pc - iseq->body->iseq_encoded;
|
||||||
|
@ -65,10 +69,32 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
int
|
||||||
rb_vm_get_sourceline(const rb_control_frame_t *cfp)
|
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
|
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 *
|
static inline rb_backtrace_location_t *
|
||||||
location_ptr(VALUE locobj)
|
location_ptr(VALUE locobj)
|
||||||
{
|
{
|
||||||
|
@ -287,6 +319,37 @@ location_path_m(VALUE self)
|
||||||
return location_path(location_ptr(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
|
static VALUE
|
||||||
location_realpath(rb_backtrace_location_t *loc)
|
location_realpath(rb_backtrace_location_t *loc)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue