aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--eval.c7
-rw-r--r--include/ruby/intern.h5
-rw-r--r--internal.h1
-rw-r--r--test/ruby/test_settracefunc.rb84
-rw-r--r--variable.c2
-rw-r--r--vm.c18
-rw-r--r--vm_eval.c13
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 <ko1@atdot.net>
+
+ * 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 <usa@ruby-lang.org>
* 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{