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

ruby-changes:26019

From: ko1 <ko1@a...>
Date: Sat, 1 Dec 2012 02:00:40 +0900 (JST)
Subject: [ruby-changes:26019] ko1:r38076 (trunk): [EXPERIMENTAL]

ko1	2012-12-01 02:00:30 +0900 (Sat, 01 Dec 2012)

  New Revision: 38076

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38076

  Log:
    [EXPERIMENTAL]
    * iseq.c: add following two methods.
    * ISeq#line_trace_all returns all line traces (line numbers)
    * ISeq#line_trace_specify(pos, set) set `pos'th line event to
      specified_line event (if set is true).
      These features are introduced for debuggers (mainly to make
      breakpoint).
    * iseq.h: add decl. of C APIs.
    * test/ruby/test_iseq.rb: add tests.
    * vm_trace.c: add `specified_line' event.
    * include/ruby/ruby.h: ditto.

  Modified files:
    trunk/ChangeLog
    trunk/include/ruby/ruby.h
    trunk/iseq.c
    trunk/iseq.h
    trunk/test/ruby/test_iseq.rb
    trunk/vm_trace.c

Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 38075)
+++ include/ruby/ruby.h	(revision 38076)
@@ -1581,6 +1581,7 @@
 #define RUBY_EVENT_B_RETURN        0x0200
 #define RUBY_EVENT_THREAD_BEGIN    0x0400
 #define RUBY_EVENT_THREAD_END      0x0800
+#define RUBY_EVENT_SPECIFIED_LINE  0x8000
 #define RUBY_EVENT_TRACEPOINT_ALL  0xFFFF
 
 typedef unsigned int rb_event_flag_t;
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38075)
+++ ChangeLog	(revision 38076)
@@ -1,3 +1,21 @@
+Sat Dec  1 01:51:06 2012  Koichi Sasada  <ko1@a...>
+
+	[EXPERIMENTAL]
+	* iseq.c: add following two methods.
+	  * ISeq#line_trace_all returns all line traces (line numbers)
+	  * ISeq#line_trace_specify(pos, set) set `pos'th line event to
+	    specified_line event (if set is true).
+	  These features are introduced for debuggers (mainly to make
+	  breakpoint).
+
+	* iseq.h: add decl. of C APIs.
+
+	* test/ruby/test_iseq.rb: add tests.
+
+	* vm_trace.c: add `specified_line' event.
+
+	* include/ruby/ruby.h: ditto.
+
 Sat Dec  1 01:49:52 2012  NAKAMURA Usaku  <usa@r...>
 
 	* test/rubygems/test_gem_dependency_installler.rb: gems are of course
Index: iseq.c
===================================================================
--- iseq.c	(revision 38075)
+++ iseq.c	(revision 38076)
@@ -1889,6 +1889,107 @@
     return iseqval;
 }
 
+/* Experimental tracing support: trace(line) -> trace(specified_line)
+ * MRI Specific.
+ */
+
+int
+rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *events_ptr, void *d), void *data)
+{
+    int trace_num = 0;
+    size_t pos, insn;
+    rb_iseq_t *iseq;
+    int cont = 1;
+    GetISeqPtr(iseqval, iseq);
+
+    for (pos = 0; cont && pos < iseq->iseq_size; pos += insn_len(insn)) {
+	insn = iseq->iseq[pos];
+
+	if (insn == BIN(trace)) {
+	    rb_event_flag_t current_events = (VALUE)iseq->iseq[pos+1];
+	    rb_event_flag_t events = current_events & RUBY_EVENT_SPECIFIED_LINE;
+	    trace_num++;
+
+	    if (func) {
+		int line = find_line_no(iseq, pos);
+		/* printf("line: %d\n", line); */
+		cont = (*func)(line, &events, data);
+		if (current_events != events) {
+		    iseq->iseq[pos+1] = iseq->iseq_encoded[pos+1] = (VALUE)(current_events | (events & RUBY_EVENT_SPECIFIED_LINE));
+		}
+	    }
+	}
+    }
+    return trace_num;
+}
+
+static int
+collect_trace(int line, rb_event_flag_t *events_ptr, void *ptr)
+{
+    VALUE result = (VALUE)ptr;
+    rb_ary_push(result, INT2NUM(line));
+    return 1;
+}
+
+VALUE
+rb_iseq_line_trace_all(VALUE iseqval)
+{
+    VALUE result = rb_ary_new();
+    rb_iseq_line_trace_each(iseqval, collect_trace, (void *)result);
+    return result;
+}
+
+struct set_specifc_data {
+    int pos;
+    int set;
+    int prev; /* 1: set, 2: unset, 0: not found */
+};
+
+static int
+line_trace_specify(int line, rb_event_flag_t *events_ptr, void *ptr)
+{
+    struct set_specifc_data *data = (struct set_specifc_data *)ptr;
+
+    if (data->pos == 0) {
+	data->prev = *events_ptr & RUBY_EVENT_SPECIFIED_LINE ? 1 : 2;
+	if (data->set) {
+	    *events_ptr = *events_ptr | RUBY_EVENT_SPECIFIED_LINE;
+	}
+	else {
+	    *events_ptr = *events_ptr & ~RUBY_EVENT_SPECIFIED_LINE;
+	}
+	return 0; /* found */
+    }
+    else {
+	data->pos--;
+	return 1;
+    }
+}
+
+VALUE
+rb_iseq_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set)
+{
+    struct set_specifc_data data;
+
+    data.prev = 0;
+    data.pos = NUM2INT(pos);
+    if (data.pos < 0) rb_raise(rb_eTypeError, "`pos' is negative");
+
+    switch (set) {
+      case Qtrue:  data.set = 1; break;
+      case Qfalse: data.set = 0; break;
+      default:
+	rb_raise(rb_eTypeError, "`set' should be true/false");
+    }
+
+    rb_iseq_line_trace_each(iseqval, line_trace_specify, (void *)&data);
+
+    if (data.prev == 0) {
+	rb_raise(rb_eTypeError, "`pos' is out of range.");
+    }
+    return data.prev == 1 ? Qtrue : Qfalse;
+}
+
 /*
  *  Document-class: RubyVM::InstructionSequence
  *
@@ -1918,6 +2019,10 @@
     rb_define_method(rb_cISeq, "to_a", iseq_to_a, 0);
     rb_define_method(rb_cISeq, "eval", iseq_eval, 0);
 
+    /* experimental */
+    rb_define_method(rb_cISeq, "line_trace_all", rb_iseq_line_trace_all, 0);
+    rb_define_method(rb_cISeq, "line_trace_specify", rb_iseq_line_trace_specify, 2);
+
 #if 0 /* TBD */
     rb_define_method(rb_cISeq, "marshal_dump", iseq_marshal_dump, 0);
     rb_define_method(rb_cISeq, "marshal_load", iseq_marshal_load, 1);
Index: iseq.h
===================================================================
--- iseq.h	(revision 38075)
+++ iseq.h	(revision 38076)
@@ -28,6 +28,10 @@
 struct st_table *ruby_insn_make_insn_table(void);
 unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos);
 
+int rb_iseq_line_trace_each(VALUE iseqval, int (*func)(int line, rb_event_flag_t *events_ptr, void *d), void *data);
+VALUE rb_iseq_line_trace_all(VALUE iseqval);
+VALUE rb_iseq_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set);
+
 /* proc.c */
 rb_iseq_t *rb_method_get_iseq(VALUE body);
 rb_iseq_t *rb_proc_get_iseq(VALUE proc, int *is_proc);
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 38075)
+++ vm_trace.c	(revision 38076)
@@ -525,6 +525,7 @@
 	C(b_return, B_RETURN);
 	C(thread_begin, THREAD_BEGIN);
 	C(thread_end, THREAD_END);
+	C(specified_line, SPECIFIED_LINE);
 #undef C
       default:
 	return 0;
@@ -632,6 +633,7 @@
     C(b_return, B_RETURN);
     C(thread_begin, THREAD_BEGIN);
     C(thread_end, THREAD_END);
+    C(specified_line, SPECIFIED_LINE);
 #undef C
     rb_raise(rb_eArgError, "unknown event: %s", rb_id2name(SYM2ID(sym)));
 }
Index: test/ruby/test_iseq.rb
===================================================================
--- test/ruby/test_iseq.rb	(revision 38075)
+++ test/ruby/test_iseq.rb	(revision 38076)
@@ -25,4 +25,28 @@
   ensure
     Encoding.default_internal = enc
   end
+
+  def test_line_trace
+    iseq = ISeq.compile \
+  %q{ a = 1
+      b = 2
+      c = 3
+      # d = 4
+      e = 5
+      # f = 6
+      g = 7
+
+    }
+    assert_equal([1, 2, 3, 5, 7], iseq.line_trace_all)
+    iseq.line_trace_specify(1, true) # line 2
+    iseq.line_trace_specify(3, true) # line 5
+
+    result = []
+    TracePoint.new(:specified_line){|tp|
+      result << tp.lineno
+    }.enable{
+      iseq.eval
+    }
+    assert_equal([2, 5], result)
+  end
 end

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

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