From a5e02f249d398df2d3861f99ba9754061db562ff Mon Sep 17 00:00:00 2001 From: mame Date: Tue, 5 Dec 2017 08:56:50 +0000 Subject: vm_core.h (rb_iseq_locatoin_t): add a field `code_range` This change makes each ISeq keep NODE's code range. This information is needed for method coverage. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61025 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- compile.c | 1 + ext/coverage/coverage.c | 2 +- iseq.c | 39 ++++++++++++++++++++++++++++++++------- method.h | 2 +- thread.c | 24 ++++++++++++++++++------ vm_core.h | 1 + 6 files changed, 54 insertions(+), 15 deletions(-) diff --git a/compile.c b/compile.c index 4da76748c1..7b2839e853 100644 --- a/compile.c +++ b/compile.c @@ -8566,6 +8566,7 @@ ibf_load_iseq_each(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t of RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, body->location.base_label)); RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, body->location.label)); load_body->location.first_lineno = body->location.first_lineno; + load_body->location.code_range = body->location.code_range; load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, body->is_size); load_body->ci_entries = ibf_load_ci_entries(load, body); diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c index 08c386e79b..73aa57791b 100644 --- a/ext/coverage/coverage.c +++ b/ext/coverage/coverage.c @@ -129,7 +129,7 @@ method_coverage_i(void *vstart, void *vend, size_t stride, void *data) if (RB_TYPE_P(v, T_IMEMO) && imemo_type(v) == imemo_ment) { const rb_method_entry_t *me = (rb_method_entry_t *) v; VALUE path = Qundef, first_lineno = Qundef; - VALUE data[2], ncoverage, methods; + VALUE data[5], ncoverage, methods; VALUE methods_id = ID2SYM(rb_intern("methods")); VALUE klass; const rb_method_entry_t *me2 = rb_resolve_me_location(me, data); diff --git a/iseq.c b/iseq.c index fb88fd89ae..0e5594fb06 100644 --- a/iseq.c +++ b/iseq.c @@ -240,7 +240,7 @@ rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath) } static rb_iseq_location_t * -iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno) +iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_range_t *code_range) { rb_iseq_location_t *loc = &iseq->body->location; @@ -248,6 +248,16 @@ iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, VAL RB_OBJ_WRITE(iseq, &loc->label, name); RB_OBJ_WRITE(iseq, &loc->base_label, name); loc->first_lineno = first_lineno; + if (code_range) { + loc->code_range = *code_range; + } + else { + loc->code_range.first_loc.lineno = 0; + loc->code_range.first_loc.column = 0; + loc->code_range.last_loc.lineno = -1; + loc->code_range.last_loc.column = -1; + } + return loc; } @@ -285,7 +295,7 @@ rb_iseq_add_mark_object(const rb_iseq_t *iseq, VALUE obj) static VALUE prepare_iseq_build(rb_iseq_t *iseq, - VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, + VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_code_range_t *code_range, const rb_iseq_t *parent, enum iseq_type type, const rb_compile_option_t *option) { @@ -299,7 +309,7 @@ prepare_iseq_build(rb_iseq_t *iseq, set_relation(iseq, parent); name = rb_fstring(name); - iseq_location_setup(iseq, name, path, realpath, first_lineno); + iseq_location_setup(iseq, name, path, realpath, first_lineno, code_range); if (iseq != iseq->body->local_iseq) { RB_OBJ_WRITE(iseq, &iseq->body->location.base_label, iseq->body->local_iseq->body->location.label); } @@ -505,7 +515,7 @@ rb_iseq_new_with_opt(const NODE *node, VALUE name, VALUE path, VALUE realpath, rb_iseq_t *iseq = iseq_alloc(); if (!option) option = &COMPILE_OPTION_DEFAULT; - prepare_iseq_build(iseq, name, path, realpath, first_lineno, parent, type, option); + prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, parent, type, option); rb_iseq_compile_node(iseq, node); finish_iseq_build(iseq); @@ -564,12 +574,13 @@ iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt) rb_iseq_t *iseq = iseq_alloc(); VALUE magic, version1, version2, format_type, misc; - VALUE name, path, realpath, first_lineno; + VALUE name, path, realpath, first_lineno, code_range; VALUE type, body, locals, params, exception; st_data_t iseq_type; rb_compile_option_t option; int i = 0; + rb_code_range_t tmp_loc = { {0, 0}, {-1, -1} }; /* [magic, major_version, minor_version, format_type, misc, * label, path, first_lineno, @@ -604,9 +615,17 @@ iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt) rb_raise(rb_eTypeError, "unsupport type: :%"PRIsVALUE, rb_sym2str(type)); } + code_range = rb_hash_aref(misc, ID2SYM(rb_intern("code_range"))); + if (RB_TYPE_P(code_range, T_ARRAY) && RARRAY_LEN(code_range) == 4) { + tmp_loc.first_loc.lineno = NUM2LONG(rb_ary_entry(code_range, 0)); + tmp_loc.first_loc.column = NUM2LONG(rb_ary_entry(code_range, 1)); + tmp_loc.last_loc.lineno = NUM2LONG(rb_ary_entry(code_range, 2)); + tmp_loc.last_loc.column = NUM2LONG(rb_ary_entry(code_range, 3)); + } + make_compile_option(&option, opt); option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */ - prepare_iseq_build(iseq, name, path, realpath, first_lineno, + prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, parent, (enum iseq_type)iseq_type, &option); rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body); @@ -2161,6 +2180,12 @@ iseq_data_to_ary(const rb_iseq_t *iseq) rb_hash_aset(misc, ID2SYM(rb_intern("arg_size")), INT2FIX(iseq->body->param.size)); rb_hash_aset(misc, ID2SYM(rb_intern("local_size")), INT2FIX(iseq->body->local_table_size)); rb_hash_aset(misc, ID2SYM(rb_intern("stack_max")), INT2FIX(iseq->body->stack_max)); + rb_hash_aset(misc, ID2SYM(rb_intern("code_range")), + rb_ary_new_from_args(4, + LONG2FIX(iseq->body->location.code_range.first_loc.lineno), + LONG2FIX(iseq->body->location.code_range.first_loc.column), + LONG2FIX(iseq->body->location.code_range.last_loc.lineno), + LONG2FIX(iseq->body->location.code_range.last_loc.column))); /* * [:magic, :major_version, :minor_version, :format_type, :misc, @@ -2499,8 +2524,8 @@ Init_ISeq(void) rb_define_private_method(rb_cISeq, "marshal_dump", iseqw_marshal_dump, 0); rb_define_private_method(rb_cISeq, "marshal_load", iseqw_marshal_load, 1); /* disable this feature because there is no verifier. */ - rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); #endif + rb_define_singleton_method(rb_cISeq, "load", iseq_s_load, -1); (void)iseq_s_load; rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1); diff --git a/method.h b/method.h index 584332561b..dc430401a7 100644 --- a/method.h +++ b/method.h @@ -191,7 +191,7 @@ const rb_method_entry_t *rb_method_entry(VALUE klass, ID id); const rb_method_entry_t *rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class); const rb_method_entry_t *rb_resolve_refined_method(VALUE refinements, const rb_method_entry_t *me); RUBY_SYMBOL_EXPORT_BEGIN -const rb_method_entry_t *rb_resolve_me_location(const rb_method_entry_t *, VALUE[2]); +const rb_method_entry_t *rb_resolve_me_location(const rb_method_entry_t *, VALUE[5]); RUBY_SYMBOL_EXPORT_END const rb_callable_method_entry_t *rb_callable_method_entry(VALUE klass, ID id); diff --git a/thread.c b/thread.c index 58c1505cbc..c7fd8d6f0d 100644 --- a/thread.c +++ b/thread.c @@ -5019,24 +5019,33 @@ update_coverage(VALUE data, const rb_trace_arg_t *trace_arg) } const rb_method_entry_t * -rb_resolve_me_location(const rb_method_entry_t *me, VALUE resolved_location[2]) +rb_resolve_me_location(const rb_method_entry_t *me, VALUE resolved_location[5]) { - VALUE path, first_lineno; + VALUE path, first_lineno, first_column, last_lineno, last_column; retry: switch (me->def->type) { case VM_METHOD_TYPE_ISEQ: { - rb_iseq_location_t loc = me->def->body.iseq.iseqptr->body->location; - path = loc.pathobj; - first_lineno = loc.first_lineno; + const rb_iseq_t *iseq = me->def->body.iseq.iseqptr; + rb_iseq_location_t *loc = &iseq->body->location; + path = rb_iseq_path(iseq); + first_lineno = INT2FIX(loc->code_range.first_loc.lineno); + first_column = INT2FIX(loc->code_range.first_loc.column); + last_lineno = INT2FIX(loc->code_range.last_loc.lineno); + last_column = INT2FIX(loc->code_range.last_loc.column); break; } case VM_METHOD_TYPE_BMETHOD: { const rb_iseq_t *iseq = rb_proc_get_iseq(me->def->body.proc, 0); if (iseq) { + rb_iseq_location_t *loc; rb_iseq_check(iseq); path = rb_iseq_path(iseq); - first_lineno = iseq->body->location.first_lineno; + loc = &iseq->body->location; + first_lineno = INT2FIX(loc->code_range.first_loc.lineno); + first_column = INT2FIX(loc->code_range.first_loc.column); + last_lineno = INT2FIX(loc->code_range.last_loc.lineno); + last_column = INT2FIX(loc->code_range.last_loc.column); break; } return NULL; @@ -5060,6 +5069,9 @@ rb_resolve_me_location(const rb_method_entry_t *me, VALUE resolved_location[2]) if (resolved_location) { resolved_location[0] = path; resolved_location[1] = first_lineno; + resolved_location[2] = first_column; + resolved_location[3] = last_lineno; + resolved_location[4] = last_column; } return me; } diff --git a/vm_core.h b/vm_core.h index 031cc7b95b..2aa2ba04e2 100644 --- a/vm_core.h +++ b/vm_core.h @@ -252,6 +252,7 @@ typedef struct rb_iseq_location_struct { VALUE base_label; /* String */ VALUE label; /* String */ VALUE first_lineno; /* TODO: may be unsigned short */ + rb_code_range_t code_range; } rb_iseq_location_t; #define PATHOBJ_PATH 0 -- cgit v1.2.3