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/