[前][次][番号順一覧][スレッド一覧]

ruby-changes:49310

From: ko1 <ko1@a...>
Date: Sat, 23 Dec 2017 23:47:10 +0900 (JST)
Subject: [ruby-changes:49310] ko1:r61427 (trunk): RubyVM::InstructionSequence#trace_points.

ko1	2017-12-23 23:46:59 +0900 (Sat, 23 Dec 2017)

  New Revision: 61427

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=61427

  Log:
    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.

  Modified files:
    trunk/NEWS
    trunk/compile.c
    trunk/iseq.c
    trunk/test/ruby/test_iseq.rb
Index: iseq.c
===================================================================
--- iseq.c	(revision 61426)
+++ iseq.c	(revision 61427)
@@ -1874,6 +1874,43 @@ iseqw_each_child(VALUE self) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1874
     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) https://github.com/ruby/ruby/blob/trunk/iseq.c#L2716
     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 */
Index: compile.c
===================================================================
--- compile.c	(revision 61426)
+++ compile.c	(revision 61427)
@@ -763,7 +763,7 @@ rb_vm_insn_addr2insn(const void *addr) / https://github.com/ruby/ruby/blob/trunk/compile.c#L763
 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);
Index: NEWS
===================================================================
--- NEWS	(revision 61426)
+++ NEWS	(revision 61427)
@@ -168,6 +168,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L168
   * New method:
 
     * RubyVM::InstructionSequence#each_child
+    * RubyVM::InstructionSequence#trace_points
 
 * String
 
Index: test/ruby/test_iseq.rb
===================================================================
--- test/ruby/test_iseq.rb	(revision 61426)
+++ test/ruby/test_iseq.rb	(revision 61427)
@@ -281,27 +281,31 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L281
     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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L325
 
     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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]