summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--compile.c55
-rw-r--r--include/ruby/debug.h2
-rw-r--r--include/ruby/ruby.h7
-rw-r--r--insns.def3
-rw-r--r--test/ruby/test_settracefunc.rb57
-rw-r--r--thread.c5
-rw-r--r--vm.c3
-rw-r--r--vm_trace.c12
9 files changed, 138 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index 944c27cf02..e28ae43c2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+Fri Nov 30 07:21:33 2012 Koichi Sasada <ko1@atdot.net>
+
+ [EXPERIMENTAL: NEED DISCUSS]
+ * vm_trace.c: add events
+ * :thread_begin - hook at thread beggining.
+ * :thead_end - hook at thread ending.
+ * :b_call - hook at block enter.
+ * :b_return - hook at block leave.
+ This change slow down block invocation.
+ Please try and give us feedback until 2.0 code freeze.
+
+ * include/ruby/ruby.h: ditto.
+
+ * compile.c (rb_iseq_compile_node): ditto.
+
+ * insns.def: ditto.
+
+ * thread.c: ditto.
+
+ * vm.c: ditto.
+
+ * include/ruby/debug.h: add a comment.
+
+ * test/ruby/test_settracefunc.rb: add a tests.
+
Fri Nov 30 06:56:30 2012 Ryan Davis <ryand-ruby@zenspider.com>
* test/minitest/*: Imported minitest 4.3.2 (r8027)
diff --git a/compile.c b/compile.c
index f061ae35da..152c3d0d34 100644
--- a/compile.c
+++ b/compile.c
@@ -475,31 +475,36 @@ rb_iseq_compile_node(VALUE self, NODE *node)
iseq_set_arguments(iseq, ret, node->nd_args);
switch (iseq->type) {
- case ISEQ_TYPE_BLOCK: {
- LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
- LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
-
- ADD_LABEL(ret, start);
- COMPILE(ret, "block body", node->nd_body);
- ADD_LABEL(ret, end);
-
- /* wide range catch handler must put at last */
- ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
- ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
- break;
- }
- case ISEQ_TYPE_CLASS: {
- ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CLASS);
- COMPILE(ret, "scoped node", node->nd_body);
- ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
- break;
- }
- case ISEQ_TYPE_METHOD: {
- ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CALL);
- COMPILE(ret, "scoped node", node->nd_body);
- ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
- break;
- }
+ case ISEQ_TYPE_BLOCK:
+ {
+ LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
+ LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
+
+ ADD_LABEL(ret, start);
+ ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_B_CALL);
+ COMPILE(ret, "block body", node->nd_body);
+ ADD_TRACE(ret, nd_line(node), RUBY_EVENT_B_RETURN);
+ ADD_LABEL(ret, end);
+
+ /* wide range catch handler must put at last */
+ ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
+ ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
+ break;
+ }
+ case ISEQ_TYPE_CLASS:
+ {
+ ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CLASS);
+ COMPILE(ret, "scoped node", node->nd_body);
+ ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
+ break;
+ }
+ case ISEQ_TYPE_METHOD:
+ {
+ ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CALL);
+ COMPILE(ret, "scoped node", node->nd_body);
+ ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
+ break;
+ }
default: {
COMPILE(ret, "scoped node", node->nd_body);
break;
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index 88a6ecfe6b..7767770a83 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -38,8 +38,10 @@ VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);
/* Old style set_trace_func APIs */
+/* duplicated def of include/ruby/ruby.h */
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
int rb_remove_event_hook(rb_event_hook_func_t func);
+
int rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data);
void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index d432f4b1f7..59d178a6b3 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -1574,6 +1574,13 @@ int ruby_native_thread_p(void);
#define RUBY_EVENT_SWITCH 0x20000
#define RUBY_EVENT_COVERAGE 0x40000
+/* for TracePoint extended events */
+#define RUBY_EVENT_B_CALL 0x0100
+#define RUBY_EVENT_B_RETURN 0x0200
+#define RUBY_EVENT_THREAD_BEGIN 0x0400
+#define RUBY_EVENT_THREAD_END 0x0800
+#define RUBY_EVENT_TRACEPOINT_ALL 0xFFFF
+
typedef unsigned int rb_event_flag_t;
typedef void (*rb_event_hook_func_t)(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass);
diff --git a/insns.def b/insns.def
index 0cc5bb9c8e..e9716f4d0f 100644
--- a/insns.def
+++ b/insns.def
@@ -871,8 +871,9 @@ trace
rb_sourceline());
}
}
+
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* id and klass are resolved at callee */,
- flag & RUBY_EVENT_RETURN ? TOPN(0) : Qundef);
+ (flag & RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN) ? TOPN(0) : Qundef);
}
/**********************************************************/
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index 0c08e7f245..82d3dc4fae 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -532,9 +532,14 @@ class TestSetTraceFunc < Test::Unit::TestCase
end
def test_tracepoint
- events1, answer_events = *trace_by_tracepoint()
+ events1, answer_events = *trace_by_tracepoint(:line, :class, :end, :call, :return, :c_call, :c_return, :raise)
mesg = events1.map{|e|
+ if false
+ p [:event, e[0]]
+ p [:line_file, e[1], e[2]]
+ p [:id, e[4]]
+ end
"#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}"
}.join("\n")
answer_events.zip(events1){|answer, event|
@@ -682,4 +687,54 @@ class TestSetTraceFunc < Test::Unit::TestCase
end
}
end
+
+ def method_for_test_tracepoint_block
+ yield
+ end
+
+ def test_tracepoint_block
+ events = []
+ TracePoint.new(:call, :return, :c_call, :b_call, :c_return, :b_return){|tp|
+ events << [
+ tp.event, tp.method_id, tp.defined_class, tp.self.class,
+ /return/ =~ tp.event ? tp.return_value : nil
+ ]
+ }.enable{
+ 1.times{
+ 3
+ }
+ method_for_test_tracepoint_block{
+ 4
+ }
+ }
+ # pp events
+ expected_events =
+ [[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:c_call, :times, Integer, Fixnum, nil],
+ [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 3],
+ [:c_return, :times, Integer, Fixnum, 1],
+ [:call, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
+ [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
+ [:return, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
+ [:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4]
+ ].zip(events){|expected, actual|
+ assert_equal(expected, actual)
+ }
+ end
+
+ def test_tracepoint_thread
+ events = []
+ created_thread = nil
+ TracePoint.new(:thread_begin, :thread_end){|tp|
+ events << [Thread.current, tp.event, tp.self]
+ }.enable{
+ created_thread = Thread.new{}
+ created_thread.join
+ }
+ assert_equal([created_thread, :thread_begin, self], events[0])
+ assert_equal([created_thread, :thread_end, self], events[1])
+ assert_equal(2, events.size)
+ end
end
diff --git a/thread.c b/thread.c
index 6d4e060c5d..cd02f3de44 100644
--- a/thread.c
+++ b/thread.c
@@ -478,8 +478,9 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
th->errinfo = Qnil;
th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
th->root_svar = Qnil;
- th->value = rb_vm_invoke_proc(th, proc,
- (int)RARRAY_LEN(args), RARRAY_PTR(args), 0);
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, proc->block.self, 0, 0, th->self);
+ th->value = rb_vm_invoke_proc(th, proc, (int)RARRAY_LEN(args), RARRAY_PTR(args), 0);
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, proc->block.self, 0, 0, th->self);
}
else {
th->value = (*th->first_func)((void *)args);
diff --git a/vm.c b/vm.c
index ab86569bec..f14d3915c3 100644
--- a/vm.c
+++ b/vm.c
@@ -1353,6 +1353,9 @@ vm_exec(rb_thread_t *th)
RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0)
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, Qnil);
break;
+ case VM_FRAME_MAGIC_BLOCK:
+ EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
+ break;
case VM_FRAME_MAGIC_CLASS:
EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil);
break;
diff --git a/vm_trace.c b/vm_trace.c
index 211b36e969..d94e9df8e0 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -507,6 +507,10 @@ get_event_id(rb_event_flag_t event)
C(c_call, C_CALL);
C(c_return, C_RETURN);
C(raise, RAISE);
+ C(b_call, B_CALL);
+ C(b_return, B_RETURN);
+ C(thread_begin, THREAD_BEGIN);
+ C(thread_end, THREAD_END);
#undef C
default:
return 0;
@@ -610,6 +614,10 @@ symbol2event_flag(VALUE v)
C(c_call, C_CALL);
C(c_return, C_RETURN);
C(raise, RAISE);
+ C(b_call, B_CALL);
+ C(b_return, B_RETURN);
+ C(thread_begin, THREAD_BEGIN);
+ C(thread_end, THREAD_END);
#undef C
rb_raise(rb_eArgError, "unknown event: %s", rb_id2name(SYM2ID(sym)));
}
@@ -736,7 +744,7 @@ rb_tracearg_self(rb_trace_arg_t *trace_arg)
VALUE
rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
{
- if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN)) {
+ if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN)) {
/* ok */
}
else {
@@ -975,7 +983,7 @@ tracepoint_new_s(int argc, VALUE *argv, VALUE self)
}
}
else {
- events = RUBY_EVENT_ALL;
+ events = RUBY_EVENT_TRACEPOINT_ALL;
}
if (!rb_block_given_p()) {