зеркало из https://github.com/github/ruby.git
[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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38007 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
2dc5e62545
Коммит
4db8340398
25
ChangeLog
25
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)
|
||||
|
|
51
compile.c
51
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);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**********************************************************/
|
||||
|
|
|
@ -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
|
||||
|
|
5
thread.c
5
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);
|
||||
|
|
3
vm.c
3
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;
|
||||
|
|
12
vm_trace.c
12
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()) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче