mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
TracePoint#enable(target_line:)
is supported. [Feature #15289]
* vm_trace.c: `TracePoint#enable(target_line:)` is supported. This option enables a hook only at specified target_line. target_line should be combination with target and :line event. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66008 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
6e33c16ffd
commit
72e60a0437
6 changed files with 77 additions and 20 deletions
27
iseq.c
27
iseq.c
|
@ -2980,7 +2980,7 @@ rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
|
|||
}
|
||||
|
||||
static int
|
||||
iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval)
|
||||
iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
|
||||
{
|
||||
unsigned int pc;
|
||||
int n = 0;
|
||||
|
@ -2990,18 +2990,29 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events,
|
|||
VM_ASSERT((iseq->flags & ISEQ_USE_COMPILE_DATA) == 0);
|
||||
|
||||
for (pc=0; pc<body->iseq_size;) {
|
||||
rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc);
|
||||
if (pc_events & turnon_events) {
|
||||
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pc);
|
||||
rb_event_flag_t pc_events = entry->events;
|
||||
rb_event_flag_t target_events = turnon_events;
|
||||
unsigned int line = (int)entry->line_no;
|
||||
|
||||
if (target_line == 0 || target_line == line) {
|
||||
/* ok */
|
||||
}
|
||||
else {
|
||||
target_events &= ~RUBY_EVENT_LINE;
|
||||
}
|
||||
|
||||
if (pc_events & target_events) {
|
||||
n++;
|
||||
}
|
||||
pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (turnon_events | iseq->aux.global_trace_events));
|
||||
pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->aux.global_trace_events));
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
if (iseq->local_hooks == NULL) {
|
||||
((rb_iseq_t *)iseq)->local_hooks = RB_ZALLOC(rb_hook_list_t);
|
||||
}
|
||||
rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->local_hooks, tpval);
|
||||
rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->local_hooks, tpval, target_line);
|
||||
}
|
||||
|
||||
return n;
|
||||
|
@ -3010,6 +3021,7 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events,
|
|||
struct trace_set_local_events_struct {
|
||||
rb_event_flag_t turnon_events;
|
||||
VALUE tpval;
|
||||
unsigned int target_line;
|
||||
int n;
|
||||
};
|
||||
|
||||
|
@ -3017,16 +3029,17 @@ static void
|
|||
iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p)
|
||||
{
|
||||
struct trace_set_local_events_struct *data = (struct trace_set_local_events_struct *)p;
|
||||
data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval);
|
||||
data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval, data->target_line);
|
||||
iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
|
||||
}
|
||||
|
||||
int
|
||||
rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval)
|
||||
rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
|
||||
{
|
||||
struct trace_set_local_events_struct data;
|
||||
data.turnon_events = turnon_events;
|
||||
data.tpval = tpval;
|
||||
data.target_line = target_line;
|
||||
data.n = 0;
|
||||
|
||||
iseq_add_local_tracepoint_i(iseq, (void *)&data);
|
||||
|
|
2
iseq.h
2
iseq.h
|
@ -148,7 +148,7 @@ void rb_ibf_load_iseq_complete(rb_iseq_t *iseq);
|
|||
const rb_iseq_t *rb_iseq_ibf_load(VALUE str);
|
||||
VALUE rb_iseq_ibf_load_extra_data(VALUE str);
|
||||
void rb_iseq_init_trace(rb_iseq_t *iseq);
|
||||
int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval);
|
||||
int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line);
|
||||
int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval);
|
||||
|
||||
#if VM_INSN_INFO_TABLE_IMPL == 2
|
||||
|
|
|
@ -133,8 +133,8 @@ class IO
|
|||
end
|
||||
|
||||
class TracePoint
|
||||
def enable target: nil, &blk
|
||||
self.__enable target, &blk
|
||||
def enable target: nil, target_line: nil, &blk
|
||||
self.__enable target, target_line, &blk
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2056,4 +2056,31 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||
end
|
||||
assert_equal [:tp2, :tp2, :tp1, :tp2, :___], events
|
||||
end
|
||||
|
||||
def test_tracepoint_enable_with_target_line
|
||||
events = []
|
||||
code1 = proc{
|
||||
events << 1
|
||||
events << 2
|
||||
events << 3
|
||||
}
|
||||
tp = TracePoint.new(:line) do |tp|
|
||||
events << :tp
|
||||
end
|
||||
tp.enable(target: code1, target_line: 2064) do
|
||||
code1.call
|
||||
end
|
||||
assert_equal [1, :tp, 2, 3], events
|
||||
|
||||
|
||||
e = assert_raise(ArgumentError) do
|
||||
TracePoint.new(:line){}.enable(target_line: 10){}
|
||||
end
|
||||
assert_equal 'only target_line is specified', e.message
|
||||
|
||||
e = assert_raise(ArgumentError) do
|
||||
TracePoint.new(:call){}.enable(target: code1, target_line: 10){}
|
||||
end
|
||||
assert_equal 'target_line is specified, but line event is not specified', e.message
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1825,7 +1825,7 @@ struct rb_trace_arg_struct {
|
|||
|
||||
void rb_hook_list_mark(rb_hook_list_t *hooks);
|
||||
void rb_hook_list_free(rb_hook_list_t *hooks);
|
||||
void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval);
|
||||
void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line);
|
||||
void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval);
|
||||
|
||||
void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, rb_hook_list_t *hooks, int pop_p);
|
||||
|
|
35
vm_trace.c
35
vm_trace.c
|
@ -40,6 +40,7 @@ typedef struct rb_event_hook_struct {
|
|||
|
||||
struct {
|
||||
rb_thread_t *th;
|
||||
unsigned int target_line;
|
||||
} filter;
|
||||
} rb_event_hook_t;
|
||||
|
||||
|
@ -107,7 +108,8 @@ alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data,
|
|||
hook->data = data;
|
||||
|
||||
/* no filters */
|
||||
hook->filter.th = 0;
|
||||
hook->filter.th = NULL;
|
||||
hook->filter.target_line = 0;
|
||||
|
||||
return hook;
|
||||
}
|
||||
|
@ -293,7 +295,8 @@ exec_hooks_body(const rb_execution_context_t *ec, rb_hook_list_t *list, const rb
|
|||
for (hook = list->hooks; hook; hook = hook->next) {
|
||||
if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) &&
|
||||
(trace_arg->event & hook->events) &&
|
||||
(hook->filter.th == 0 || hook->filter.th == rb_ec_thread_ptr(ec))) {
|
||||
(LIKELY(hook->filter.th == 0) || hook->filter.th == rb_ec_thread_ptr(ec)) &&
|
||||
(LIKELY(hook->filter.target_line == 0) || (hook->filter.target_line == (unsigned int)rb_vm_get_sourceline(ec->cfp)))) {
|
||||
if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_RAW_ARG)) {
|
||||
(*hook->func)(trace_arg->event, hook->data, trace_arg->self, trace_arg->id, trace_arg->klass);
|
||||
}
|
||||
|
@ -1154,21 +1157,31 @@ iseq_of(VALUE target)
|
|||
const rb_method_definition_t *rb_method_def(VALUE method); /* proc.c */
|
||||
|
||||
static VALUE
|
||||
rb_tracepoint_enable_for_target(VALUE tpval, VALUE target)
|
||||
rb_tracepoint_enable_for_target(VALUE tpval, VALUE target, VALUE target_line)
|
||||
{
|
||||
rb_tp_t *tp = tpptr(tpval);
|
||||
const rb_iseq_t *iseq = iseq_of(target);
|
||||
int n;
|
||||
unsigned int line = 0;
|
||||
|
||||
if (tp->tracing > 0) {
|
||||
rb_raise(rb_eArgError, "can't nest-enable a targetting TracePoint");
|
||||
}
|
||||
|
||||
if (!NIL_P(target_line)) {
|
||||
if ((tp->events & RUBY_EVENT_LINE) == 0) {
|
||||
rb_raise(rb_eArgError, "target_line is specified, but line event is not specified");
|
||||
}
|
||||
else {
|
||||
line = NUM2UINT(target_line);
|
||||
}
|
||||
}
|
||||
|
||||
VM_ASSERT(tp->local_target_set == Qfalse);
|
||||
tp->local_target_set = rb_obj_hide(rb_ident_hash_new());
|
||||
|
||||
/* iseq */
|
||||
n = rb_iseq_add_local_tracepoint_recursively(iseq, tp->events, tpval);
|
||||
n = rb_iseq_add_local_tracepoint_recursively(iseq, tp->events, tpval, line);
|
||||
rb_hash_aset(tp->local_target_set, (VALUE)iseq, Qtrue);
|
||||
|
||||
/* bmethod */
|
||||
|
@ -1177,7 +1190,7 @@ rb_tracepoint_enable_for_target(VALUE tpval, VALUE target)
|
|||
if (def->type == VM_METHOD_TYPE_BMETHOD &&
|
||||
(tp->events & (RUBY_EVENT_CALL | RUBY_EVENT_RETURN))) {
|
||||
def->body.bmethod.hooks = ZALLOC(rb_hook_list_t);
|
||||
rb_hook_list_connect_tracepoint(target, def->body.bmethod.hooks, tpval);
|
||||
rb_hook_list_connect_tracepoint(target, def->body.bmethod.hooks, tpval, 0);
|
||||
rb_hash_aset(tp->local_target_set, target, Qfalse);
|
||||
|
||||
n++;
|
||||
|
@ -1240,11 +1253,12 @@ rb_tracepoint_disable(VALUE tpval)
|
|||
}
|
||||
|
||||
void
|
||||
rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval)
|
||||
rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line)
|
||||
{
|
||||
rb_tp_t *tp = tpptr(tpval);
|
||||
rb_event_hook_t *hook = alloc_event_hook((rb_event_hook_func_t)tp_call_trace, tp->events, tpval,
|
||||
RUBY_EVENT_HOOK_FLAG_SAFE | RUBY_EVENT_HOOK_FLAG_RAW_ARG);
|
||||
hook->filter.target_line = target_line;
|
||||
hook_list_connect(target, list, hook, FALSE);
|
||||
}
|
||||
|
||||
|
@ -1306,16 +1320,19 @@ rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval)
|
|||
*
|
||||
*/
|
||||
static VALUE
|
||||
tracepoint_enable_m(VALUE tpval, VALUE target)
|
||||
tracepoint_enable_m(VALUE tpval, VALUE target, VALUE target_line)
|
||||
{
|
||||
rb_tp_t *tp = tpptr(tpval);
|
||||
int previous_tracing = tp->tracing;
|
||||
|
||||
if (NIL_P(target)) {
|
||||
if (!NIL_P(target_line)) {
|
||||
rb_raise(rb_eArgError, "only target_line is specified");
|
||||
}
|
||||
rb_tracepoint_enable(tpval);
|
||||
}
|
||||
else {
|
||||
rb_tracepoint_enable_for_target(tpval, target);
|
||||
rb_tracepoint_enable_for_target(tpval, target, target_line);
|
||||
}
|
||||
|
||||
if (rb_block_given_p()) {
|
||||
|
@ -1706,7 +1723,7 @@ Init_vm_trace(void)
|
|||
*/
|
||||
rb_define_singleton_method(rb_cTracePoint, "trace", tracepoint_trace_s, -1);
|
||||
|
||||
rb_define_method(rb_cTracePoint, "__enable", tracepoint_enable_m, 1);
|
||||
rb_define_method(rb_cTracePoint, "__enable", tracepoint_enable_m, 2);
|
||||
rb_define_method(rb_cTracePoint, "disable", tracepoint_disable_m, 0);
|
||||
rb_define_method(rb_cTracePoint, "enabled?", rb_tracepoint_enabled_p, 0);
|
||||
|
||||
|
|
Loading…
Reference in a new issue