From c2e72fb34302e444f6cc4c6477877e36902a7035 Mon Sep 17 00:00:00 2001 From: ko1 Date: Thu, 9 Jan 2014 10:12:59 +0000 Subject: * vm.c (rb_vm_pop_cfunc_frame): added. It cares c_return event. The patch base by drkaes (Stefan Kaes). [Bug #9321] * variable.c (rb_mod_const_missing): use rb_vm_pop_cfunc_frame() instead of rb_frame_pop(). * vm_eval.c (raise_method_missing): ditto. * vm_eval.c (rb_iterate): ditto. * internal.h (rb_vm_pop_cfunc_frame): add decl. * test/ruby/test_settracefunc.rb: add tests. provided by drkaes (Stefan Kaes). * vm.c, eval.c, include/ruby/intern.h (rb_frame_pop): move definition of rb_frame_pop() and deprecate it. It doesn't care about `return' events. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44535 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 22 +++++++++++ eval.c | 7 ---- include/ruby/intern.h | 5 ++- internal.h | 1 + test/ruby/test_settracefunc.rb | 84 ++++++++++++++++++++++++++++++++++++++++++ variable.c | 2 +- vm.c | 18 +++++++++ vm_eval.c | 13 +++---- 8 files changed, 136 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index fa8890f51f..f699266218 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +Thu Jan 9 19:12:37 2014 Koichi Sasada + + * vm.c (rb_vm_pop_cfunc_frame): added. It cares c_return event. + The patch base by drkaes (Stefan Kaes). + [Bug #9321] + + * variable.c (rb_mod_const_missing): use rb_vm_pop_cfunc_frame() + instead of rb_frame_pop(). + + * vm_eval.c (raise_method_missing): ditto. + + * vm_eval.c (rb_iterate): ditto. + + * internal.h (rb_vm_pop_cfunc_frame): add decl. + + * test/ruby/test_settracefunc.rb: add tests. + provided by drkaes (Stefan Kaes). + + * vm.c, eval.c, include/ruby/intern.h (rb_frame_pop): + move definition of rb_frame_pop() and deprecate it. + It doesn't care about `return' events. + Thu Jan 9 17:40:28 2014 NAKAMURA Usaku * hash.c (rb_any_hash): should treat the return value of rb_objid_hash() diff --git a/eval.c b/eval.c index 73eef32ec4..92fbceb1d9 100644 --- a/eval.c +++ b/eval.c @@ -1010,13 +1010,6 @@ prev_frame_func(void) return frame_func_id(prev_cfp); } -void -rb_frame_pop(void) -{ - rb_thread_t *th = GET_THREAD(); - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); -} - /* * call-seq: * append_features(mod) -> mod diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 6200e77a63..46af270bb3 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -939,11 +939,14 @@ VALUE rb_mod_remove_cvar(VALUE, VALUE); ID rb_frame_callee(void); VALUE rb_str_succ(VALUE); VALUE rb_time_succ(VALUE); -void rb_frame_pop(void); int rb_frame_method_id_and_class(ID *idp, VALUE *klassp); VALUE rb_make_backtrace(void); VALUE rb_make_exception(int, VALUE*); +/* deprecated */ +DEPRECATED(void rb_frame_pop(void)); + + RUBY_SYMBOL_EXPORT_END #if defined(__cplusplus) diff --git a/internal.h b/internal.h index b0a4773d90..afcd67f369 100644 --- a/internal.h +++ b/internal.h @@ -764,6 +764,7 @@ void rb_vm_inc_const_missing_count(void); void rb_thread_mark(void *th); const void **rb_vm_get_insns_address_table(void); VALUE rb_sourcefilename(void); +void rb_vm_pop_cfunc_frame(void); /* vm_dump.c */ void rb_vm_bugreport(void); diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index b106ea5494..947178eb37 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -1066,4 +1066,88 @@ class TestSetTraceFunc < Test::Unit::TestCase :b_return ], events) end + + def test_const_missing + bug59398 = '[ruby-core:59398]' + events = [] + assert !defined?(MISSING_CONSTANT_59398) + TracePoint.new(:c_call, :c_return, :call, :return){|tp| + next unless tp.defined_class == Module + # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name + # but this only happens when running the full test suite + events << [tp.event,tp.method_id] if tp.method_id == :const_missing || tp.method_id == :rake_original_const_missing + }.enable{ + MISSING_CONSTANT_59398 rescue nil + } + if events.map{|e|e[1]}.include?(:rake_original_const_missing) + assert_equal([ + [:call, :const_missing], + [:c_call, :rake_original_const_missing], + [:c_return, :rake_original_const_missing], + [:return, :const_missing], + ], events, bug59398) + else + assert_equal([ + [:c_call, :const_missing], + [:c_return, :const_missing] + ], events, bug59398) + end + end + + class AliasedRubyMethod + def foo; 1; end; + alias bar foo + end + def test_aliased_ruby_method + events = [] + aliased = AliasedRubyMethod.new + TracePoint.new(:call, :return){|tp| + events << [tp.event, tp.method_id] + }.enable{ + aliased.bar + } + assert_equal([ + [:call, :foo], + [:return, :foo] + ], events, "should use original method name for tracing ruby methods") + end + class AliasedCMethod < Hash + alias original_size size + def size; original_size; end + end + + def test_aliased_c_method + events = [] + aliased = AliasedCMethod.new + TracePoint.new(:call, :return, :c_call, :c_return){|tp| + events << [tp.event, tp.method_id] + }.enable{ + aliased.size + } + assert_equal([ + [:call, :size], + [:c_call, :original_size], + [:c_return, :original_size], + [:return, :size] + ], events, "should use alias method name for tracing c methods") + end + + def test_method_missing + bug59398 = '[ruby-core:59398]' + events = [] + assert !respond_to?(:missing_method_59398) + TracePoint.new(:c_call, :c_return, :call, :return){|tp| + next unless tp.defined_class == BasicObject + # rake/ext/module.rb aliases :const_missing and Ruby uses the aliased name + # but this only happens when running the full test suite + events << [tp.event,tp.method_id] if tp.method_id == :method_missing + }.enable{ + missing_method_59398 rescue nil + } + assert_equal([ + [:c_call, :method_missing], + [:c_return, :method_missing] + ], events, bug59398) + end + end diff --git a/variable.c b/variable.c index 424730dcb9..21c3f66189 100644 --- a/variable.c +++ b/variable.c @@ -1518,7 +1518,7 @@ const_missing(VALUE klass, ID id) VALUE rb_mod_const_missing(VALUE klass, VALUE name) { - rb_frame_pop(); /* pop frame for "const_missing" */ + rb_vm_pop_cfunc_frame(); uninitialized_constant(klass, rb_to_id(name)); UNREACHABLE; diff --git a/vm.c b/vm.c index d1b63796f6..6fae9238d5 100644 --- a/vm.c +++ b/vm.c @@ -277,6 +277,24 @@ vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp) return 0; } +void +rb_vm_pop_cfunc_frame(void) +{ + rb_thread_t *th = GET_THREAD(); + const rb_method_entry_t *me = th->cfp->me; + EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil); + RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); + vm_pop_frame(th); +} + +/* obsolete */ +void +rb_frame_pop(void) +{ + rb_thread_t *th = GET_THREAD(); + vm_pop_frame(th); +} + /* at exit */ void diff --git a/vm_eval.c b/vm_eval.c index 82f5d3ffcf..73af53ade9 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -686,7 +686,7 @@ raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj, { exc = make_no_method_exception(exc, format, obj, argc, argv); if (!(last_call_status & NOEX_MISSING)) { - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); + rb_vm_pop_cfunc_frame(); } rb_exc_raise(exc); } @@ -1087,13 +1087,12 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, #if VMDEBUG printf("skipped frame: %s\n", vm_frametype_name(th->cfp)); #endif - if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) { - const rb_method_entry_t *me = th->cfp->me; - EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil); - RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id); + if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_CFUNC) { + vm_pop_frame(th); + } + else { /* unlikely path */ + rb_vm_pop_cfunc_frame(); } - - th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); } } else{ -- cgit v1.2.3