summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--compile.c2
-rw-r--r--iseq.c38
-rw-r--r--test/ruby/test_iseq.rb76
4 files changed, 96 insertions, 21 deletions
diff --git a/NEWS b/NEWS
index 7e55a04b2d..a773dba580 100644
--- a/NEWS
+++ b/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
diff --git a/compile.c b/compile.c
index 95d0e5f891..12669118da 100644
--- a/compile.c
+++ b/compile.c
@@ -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);
diff --git a/iseq.c b/iseq.c
index e25c423b83..d1e567a17d 100644
--- a/iseq.c
+++ b/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 */
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 2f23f78e23..74691854d9 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -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