Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
* vm_trace.c (tracepoint_attr_callee_id, rb_tracearg_callee_id):
Browse files Browse the repository at this point in the history
  add TracePoint#callee_id. [ruby-core:77241] [Feature #12747]

* cont.c, eval.c, gc.c, include/ruby/intern.h, insns.def, thread.c,
  vm.c, vm_backtrace.c, vm_core.h, vm_eval.c, vm_insnhelper.c, vm_trace.c: ditto.

* test/ruby/test_settracefunc.rb: tests for above.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56593 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
k-tsj committed Nov 5, 2016
1 parent 8004ad3 commit 9cbd6ee
Show file tree
Hide file tree
Showing 15 changed files with 189 additions and 42 deletions.
10 changes: 10 additions & 0 deletions ChangeLog
@@ -1,3 +1,13 @@
Sat Nov 5 22:11:33 2016 Kazuki Tsujimoto <kazuki@callcc.net>

* vm_trace.c (tracepoint_attr_callee_id, rb_tracearg_callee_id):
add TracePoint#callee_id. [ruby-core:77241] [Feature #12747]

* cont.c, eval.c, gc.c, include/ruby/intern.h, insns.def, thread.c,
vm.c, vm_backtrace.c, vm_core.h, vm_eval.c, vm_insnhelper.c, vm_trace.c: ditto.

* test/ruby/test_settracefunc.rb: tests for above.

Sat Nov 5 22:09:48 2016 Kazuki Tsujimoto <kazuki@callcc.net>

* eval.c, method.h, proc.c, vm.c, vm_eval.c, vm_insnhelper.c, vm_method.c:
Expand Down
4 changes: 4 additions & 0 deletions NEWS
Expand Up @@ -160,6 +160,10 @@ with all sufficient information, see the ChangeLog file or Redmine
* Thread#report_on_exception and Thread.report_on_exception
[Feature #6647]

* TracePoint

* TracePoint#callee_id [Feature #12747]

* Warning

* New module named Warning is introduced. By default it has only
Expand Down
4 changes: 2 additions & 2 deletions cont.c
Expand Up @@ -1284,7 +1284,7 @@ rb_fiber_start(void)
th->root_svar = Qfalse;
fib->status = RUNNING;

EXEC_EVENT_HOOK(th, RUBY_EVENT_FIBER_SWITCH, th->self, 0, 0, Qnil);
EXEC_EVENT_HOOK(th, RUBY_EVENT_FIBER_SWITCH, th->self, 0, 0, 0, Qnil);
cont->value = rb_vm_invoke_proc(th, proc, argc, argv, VM_BLOCK_HANDLER_NONE);
}
TH_POP_TAG();
Expand Down Expand Up @@ -1474,7 +1474,7 @@ fiber_switch(rb_fiber_t *fib, int argc, const VALUE *argv, int is_resume)
value = fiber_store(fib, th);
RUBY_VM_CHECK_INTS(th);

EXEC_EVENT_HOOK(th, RUBY_EVENT_FIBER_SWITCH, th->self, 0, 0, Qnil);
EXEC_EVENT_HOOK(th, RUBY_EVENT_FIBER_SWITCH, th->self, 0, 0, 0, Qnil);

return value;
}
Expand Down
4 changes: 2 additions & 2 deletions eval.c
Expand Up @@ -563,7 +563,7 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg, VALUE cause)

if (tag != TAG_FATAL) {
RUBY_DTRACE_HOOK(RAISE, rb_obj_classname(th->errinfo));
EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0, mesg);
EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0, 0, mesg);
}
}

Expand Down Expand Up @@ -749,7 +749,7 @@ rb_raise_jump(VALUE mesg, VALUE cause)
ID mid = me->called_id;

rb_vm_pop_frame(th);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, self, me->def->original_id, klass, Qnil);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, self, me->def->original_id, mid, klass, Qnil);

setup_exception(th, TAG_RAISE, mesg, cause);

Expand Down
2 changes: 1 addition & 1 deletion gc.c
Expand Up @@ -1755,7 +1755,7 @@ rb_objspace_set_event_hook(const rb_event_flag_t event)
static void
gc_event_hook_body(rb_thread_t *th, rb_objspace_t *objspace, const rb_event_flag_t event, VALUE data)
{
EXEC_EVENT_HOOK(th, event, th->cfp->self, 0, 0, data);
EXEC_EVENT_HOOK(th, event, th->cfp->self, 0, 0, 0, data);
}

#define gc_event_hook_available_p(objspace) ((objspace)->flags.has_hook)
Expand Down
2 changes: 1 addition & 1 deletion include/ruby/intern.h
Expand Up @@ -969,7 +969,7 @@ VALUE rb_mod_remove_cvar(VALUE, VALUE);
ID rb_frame_callee(void);
VALUE rb_str_succ(VALUE);
VALUE rb_time_succ(VALUE);
int rb_frame_method_id_and_class(ID *idp, VALUE *klassp);
int rb_frame_method_id_and_class(ID *idp, ID *called_idp, VALUE *klassp);
VALUE rb_make_backtrace(void);
VALUE rb_make_exception(int, const VALUE*);

Expand Down
2 changes: 1 addition & 1 deletion insns.def
Expand Up @@ -831,7 +831,7 @@ trace
}
}

EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* id and klass are resolved at callee */,
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0, 0 /* id and klass are resolved at callee */,
(flag & (RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN)) ? TOPN(0) : Qundef);
}

Expand Down
111 changes: 111 additions & 0 deletions test/ruby/test_settracefunc.rb
Expand Up @@ -1488,4 +1488,115 @@ def test_fiber_switch
assert_equal ev, :fiber_switch
}
end

def test_tracepoint_callee_id
events = []
capture_events = Proc.new{|tp|
events << [tp.event, tp.method_id, tp.callee_id]
}

o = Class.new{
def m
raise
end
alias alias_m m
}.new
TracePoint.new(:raise, :call, :return, &capture_events).enable{
o.alias_m rescue nil
}
assert_equal [[:call, :m, :alias_m], [:raise, :m, :alias_m], [:return, :m, :alias_m]], events
events.clear

o = Class.new{
alias alias_raise raise
def m
alias_raise
end
}.new
TracePoint.new(:c_return, &capture_events).enable{
o.m rescue nil
}
assert_equal [:c_return, :raise, :alias_raise], events[0]
events.clear

o = Class.new(String){
include Enumerable
alias each each_char
}.new('foo')
TracePoint.new(:c_return, &capture_events).enable{
o.find{true}
}
assert_equal [:c_return, :each_char, :each], events[0]
events.clear

o = Class.new{
define_method(:m){}
alias alias_m m
}.new
TracePoint.new(:call, :return, &capture_events).enable{
o.alias_m
}
assert_equal [[:call, :m, :alias_m], [:return, :m, :alias_m]], events
events.clear

o = Class.new{
def m
tap{return}
end
alias alias_m m
}.new
TracePoint.new(:return, &capture_events).enable{
o.alias_m
}
assert_equal [[:return, :m, :alias_m]], events
events.clear

o = Class.new{
define_method(:m){raise}
alias alias_m m
}.new
TracePoint.new(:b_return, :return, &capture_events).enable{
o.alias_m rescue nil
}
assert_equal [[:b_return, :m, :alias_m], [:return, :m, :alias_m]], events[0..1]
events.clear

o = Class.new{
define_method(:m){tap{return}}
alias alias_m m
}.new
TracePoint.new(:b_return, &capture_events).enable{
o.alias_m
}
assert_equal [[:b_return, :m, :alias_m], [:b_return, :m, :alias_m]], events[0..1]
events.clear

o = Class.new{
alias alias_tap tap
define_method(:m){alias_tap{return}}
}.new
TracePoint.new(:c_return, &capture_events).enable{
o.m
}
assert_equal [[:c_return, :tap, :alias_tap]], events
events.clear

c = Class.new{
alias initialize itself
}
TracePoint.new(:c_call, &capture_events).enable{
c.new
}
assert_equal [:c_call, :itself, :initialize], events[1]
events.clear

o = Class.new{
alias alias_itself itself
}.new
TracePoint.new(:c_call, :c_return, &capture_events).enable{
o.alias_itself
}
assert_equal [[:c_call, :itself, :alias_itself], [:c_return, :itself, :alias_itself]], events
events.clear
end
end
6 changes: 3 additions & 3 deletions thread.c
Expand Up @@ -589,11 +589,11 @@ 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(vm_proc_ep(th->first_proc));
th->root_svar = Qfalse;
EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, Qundef);
EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, 0, Qundef);
th->value = rb_vm_invoke_proc(th, proc,
(int)RARRAY_LEN(args), RARRAY_CONST_PTR(args),
VM_BLOCK_HANDLER_NONE);
EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, th->self, 0, 0, Qundef);
EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, th->self, 0, 0, 0, Qundef);
}
else {
th->value = (*th->first_func)((void *)args);
Expand Down Expand Up @@ -2063,7 +2063,7 @@ rb_threadptr_execute_interrupts(rb_thread_t *th, int blocking_timing)
if (th->status == THREAD_RUNNABLE)
th->running_time_us += TIME_QUANTUM_USEC;

EXEC_EVENT_HOOK(th, RUBY_INTERNAL_EVENT_SWITCH, th->cfp->self, 0, 0, Qundef);
EXEC_EVENT_HOOK(th, RUBY_INTERNAL_EVENT_SWITCH, th->cfp->self, 0, 0, 0, Qundef);

rb_thread_schedule_limits(limits_us);
}
Expand Down
29 changes: 16 additions & 13 deletions vm.c
Expand Up @@ -330,7 +330,7 @@ ruby_th_dtrace_setup(rb_thread_t *th, VALUE klass, ID id,
enum ruby_value_type type;
if (!klass) {
if (!th) th = GET_THREAD();
if (!rb_thread_method_id_and_class(th, &id, &klass) || !klass)
if (!rb_thread_method_id_and_class(th, &id, 0, &klass) || !klass)
return FALSE;
}
if (RB_TYPE_P(klass, T_ICLASS)) {
Expand Down Expand Up @@ -522,7 +522,7 @@ rb_vm_pop_cfunc_frame(void)
rb_control_frame_t *cfp = th->cfp;
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);

EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, cfp->self, me->def->original_id, me->owner, Qnil);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, cfp->self, me->def->original_id, me->called_id, me->owner, Qnil);
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->owner, me->def->original_id);
vm_pop_frame(th, cfp, cfp->ep);
}
Expand Down Expand Up @@ -984,9 +984,9 @@ invoke_bmethod(rb_thread_t *th, const rb_iseq_t *iseq, VALUE self, const struct
iseq->body->stack_max);

RUBY_DTRACE_METHOD_ENTRY_HOOK(th, me->owner, me->def->original_id);
EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->def->original_id, me->owner, Qnil);
EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, self, me->def->original_id, me->called_id, me->owner, Qnil);
ret = vm_exec(th);
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->def->original_id, me->owner, ret);
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, self, me->def->original_id, me->called_id, me->owner, ret);
RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->owner, me->def->original_id);
return ret;
}
Expand Down Expand Up @@ -1592,26 +1592,27 @@ hook_before_rewind(rb_thread_t *th, rb_control_frame_t *cfp, int will_finish_vm_
switch (VM_FRAME_TYPE(th->cfp)) {
case VM_FRAME_MAGIC_METHOD:
RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0);
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, Qnil);
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, 0, Qnil);
break;
case VM_FRAME_MAGIC_BLOCK:
case VM_FRAME_MAGIC_LAMBDA:
if (VM_FRAME_BMETHOD_P(th->cfp)) {
EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, 0, Qnil);

if (!will_finish_vm_exec) {
/* kick RUBY_EVENT_RETURN at invoke_block_from_c() for bmethod */
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self,
rb_vm_frame_method_entry(th->cfp)->def->original_id,
rb_vm_frame_method_entry(th->cfp)->called_id,
rb_vm_frame_method_entry(th->cfp)->owner, Qnil);
}
}
else {
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, 0, Qnil);
}
break;
case VM_FRAME_MAGIC_CLASS:
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil);
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_END, th->cfp->self, 0, 0, 0, Qnil);
break;
}
}
Expand Down Expand Up @@ -1735,6 +1736,7 @@ vm_exec(rb_thread_t *th)
if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) {
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self,
rb_vm_frame_method_entry(th->cfp)->def->original_id,
rb_vm_frame_method_entry(th->cfp)->called_id,
rb_vm_frame_method_entry(th->cfp)->owner, Qnil);
RUBY_DTRACE_CMETHOD_RETURN_HOOK(th,
rb_vm_frame_method_entry(th->cfp)->owner,
Expand Down Expand Up @@ -1958,12 +1960,13 @@ rb_iseq_eval_main(const rb_iseq_t *iseq)
}

int
rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp)
rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
{
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);

if (me) {
if (idp) *idp = me->def->original_id;
if (called_idp) *called_idp = me->called_id;
if (klassp) *klassp = me->owner;
return TRUE;
}
Expand All @@ -1973,15 +1976,15 @@ rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *
}

int
rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp)
rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, ID *called_idp, VALUE *klassp)
{
return rb_vm_control_frame_id_and_class(th->cfp, idp, klassp);
return rb_vm_control_frame_id_and_class(th->cfp, idp, called_idp, klassp);
}

int
rb_frame_method_id_and_class(ID *idp, VALUE *klassp)
rb_frame_method_id_and_class(ID *idp, ID *called_idp, VALUE *klassp)
{
return rb_thread_method_id_and_class(GET_THREAD(), idp, klassp);
return rb_thread_method_id_and_class(GET_THREAD(), idp, called_idp, klassp);
}

VALUE
Expand Down
2 changes: 1 addition & 1 deletion vm_backtrace.c
Expand Up @@ -1088,7 +1088,7 @@ static VALUE
get_klass(const rb_control_frame_t *cfp)
{
VALUE klass;
if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
if (RB_TYPE_P(klass, T_ICLASS)) {
return RBASIC(klass)->klass;
}
Expand Down

0 comments on commit 9cbd6ee

Please sign in to comment.