mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
RubyVM::InstructionSequence#trace_points.
* iseq.c (iseqw_trace_points): add `RubyVM::InstructionSequence#trace_points` method for tools which want to manipulate ISeq (and traces). * test/ruby/test_iseq.rb: add a test for this method. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61427 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ac40fc997b
commit
3044138bd7
4 changed files with 96 additions and 21 deletions
1
NEWS
1
NEWS
|
@ -168,6 +168,7 @@ with all sufficient information, see the ChangeLog file or Redmine
|
|||
* New method:
|
||||
|
||||
* RubyVM::InstructionSequence#each_child
|
||||
* RubyVM::InstructionSequence#trace_points
|
||||
|
||||
* String
|
||||
|
||||
|
|
|
@ -763,7 +763,7 @@ rb_vm_insn_addr2insn(const void *addr) /* cold path */
|
|||
VALUE *
|
||||
rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
|
||||
{
|
||||
VALUE *original_code;
|
||||
VALUE *original_code;3
|
||||
|
||||
if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
|
||||
original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, iseq->body->iseq_size);
|
||||
|
|
38
iseq.c
38
iseq.c
|
@ -1874,6 +1874,43 @@ iseqw_each_child(VALUE self)
|
|||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE ary)
|
||||
{
|
||||
#define C(ev, cstr, l) if (events & ev) rb_ary_push(ary, rb_ary_new_from_args(2, l, ID2SYM(rb_intern(cstr))));
|
||||
C(RUBY_EVENT_CLASS, "class", rb_iseq_first_lineno(iseq));
|
||||
C(RUBY_EVENT_CALL, "call", rb_iseq_first_lineno(iseq));
|
||||
C(RUBY_EVENT_B_CALL, "b_call", rb_iseq_first_lineno(iseq));
|
||||
C(RUBY_EVENT_LINE, "line", INT2FIX(line));
|
||||
C(RUBY_EVENT_END, "end", INT2FIX(line));
|
||||
C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
|
||||
C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
|
||||
#undef C
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* iseq.trace_points -> ary
|
||||
*
|
||||
* Return trace points in the instruction sequence.
|
||||
* Return an array of [line, event_symbol] pair.
|
||||
*/
|
||||
static VALUE
|
||||
iseqw_trace_points(VALUE self)
|
||||
{
|
||||
const rb_iseq_t *iseq = iseqw_check(self);
|
||||
unsigned int i;
|
||||
VALUE ary = rb_ary_new();
|
||||
|
||||
for (i=0; i<iseq->body->insns_info_size; i++) {
|
||||
const struct iseq_insn_info_entry *entry = &iseq->body->insns_info[i];
|
||||
if (entry->events) {
|
||||
push_event_info(iseq, entry->events, entry->line_no, ary);
|
||||
}
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the instruction sequence containing the given proc or method.
|
||||
*
|
||||
|
@ -2679,6 +2716,7 @@ Init_ISeq(void)
|
|||
rb_define_method(rb_cISeq, "label", iseqw_label, 0);
|
||||
rb_define_method(rb_cISeq, "base_label", iseqw_base_label, 0);
|
||||
rb_define_method(rb_cISeq, "first_lineno", iseqw_first_lineno, 0);
|
||||
rb_define_method(rb_cISeq, "trace_points", iseqw_trace_points, 0);
|
||||
rb_define_method(rb_cISeq, "each_child", iseqw_each_child, 0);
|
||||
|
||||
#if 0 /* TBD */
|
||||
|
|
|
@ -281,27 +281,31 @@ class TestISeq < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_each_child
|
||||
iseq = ISeq.compile <<-EOS
|
||||
class C
|
||||
def foo
|
||||
begin
|
||||
rescue
|
||||
p :rescue
|
||||
ensure
|
||||
p :ensure
|
||||
end
|
||||
end
|
||||
def bar
|
||||
1.times{
|
||||
2.times{
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
class D < C
|
||||
end
|
||||
def sample_iseq
|
||||
ISeq.compile <<-EOS.gsub(/^.*?: /, "")
|
||||
1: class C
|
||||
2: def foo
|
||||
3: begin
|
||||
4: rescue
|
||||
5: p :rescue
|
||||
6: ensure
|
||||
7: p :ensure
|
||||
8: end
|
||||
9: end
|
||||
10: def bar
|
||||
11: 1.times{
|
||||
12: 2.times{
|
||||
13: }
|
||||
14: }
|
||||
15: end
|
||||
16: end
|
||||
17: class D < C
|
||||
18: end
|
||||
EOS
|
||||
end
|
||||
|
||||
def test_each_child
|
||||
iseq = sample_iseq
|
||||
|
||||
collect_iseq = lambda{|iseq|
|
||||
iseqs = []
|
||||
|
@ -321,4 +325,36 @@ class TestISeq < Test::Unit::TestCase
|
|||
|
||||
assert_equal expected, collect_iseq.call(iseq)
|
||||
end
|
||||
|
||||
def test_trace_points
|
||||
collect_iseq = lambda{|iseq|
|
||||
iseqs = []
|
||||
iseq.each_child{|child_iseq|
|
||||
iseqs << collect_iseq.call(child_iseq)
|
||||
}
|
||||
[["#{iseq.label}@#{iseq.first_lineno}", iseq.trace_points], *iseqs.sort_by{|k, *| k}]
|
||||
}
|
||||
assert_equal [["<compiled>@1", [[1, :line],
|
||||
[17, :line]]],
|
||||
[["<class:C>@1", [[1, :class],
|
||||
[2, :line],
|
||||
[10, :line],
|
||||
[16, :end]]],
|
||||
[["bar@10", [[10, :call],
|
||||
[11, :line],
|
||||
[15, :return]]],
|
||||
[["block in bar@11", [[11, :b_call],
|
||||
[12, :line],
|
||||
[14, :b_return]]],
|
||||
[["block (2 levels) in bar@12", [[12, :b_call],
|
||||
[13, :b_return]]]]]],
|
||||
[["foo@2", [[2, :call],
|
||||
[4, :line],
|
||||
[7, :line],
|
||||
[9, :return]]],
|
||||
[["ensure in foo@2", [[7, :line]]]],
|
||||
[["rescue in foo@4", [[5, :line]]]]]],
|
||||
[["<class:D>@17", [[17, :class],
|
||||
[18, :end]]]]], collect_iseq.call(sample_iseq)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue