summaryrefslogtreecommitdiff
path: root/iseq.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-30 17:00:30 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-30 17:00:30 +0000
commit12f2f7371f2dcf9c8da2a96fa251d1af2a7e977e (patch)
tree70a25ad7b5cf5a7404817c2c0d03a4d0060e8603 /iseq.c
parent60317fa81df069a7a2a7bdcb0aaaaebc9b77bed9 (diff)
[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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38076 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'iseq.c')
-rw-r--r--iseq.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/iseq.c b/iseq.c
index 06cf4f122b..2e178d2b54 100644
--- a/iseq.c
+++ b/iseq.c
@@ -1889,6 +1889,107 @@ rb_iseq_build_for_ruby2cext(
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 @@ Init_ISeq(void)
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);