merge revision(s) 44535,44536: [Backport #9321]

* 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.

	* vm.c, eval.c, include/ruby/intern.h (rb_frame_pop):


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@46671 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
usa 2014-07-03 06:20:05 +00:00
parent c669702738
commit 6ece90852b
9 changed files with 137 additions and 17 deletions

View file

@ -1,3 +1,25 @@
Thu Jul 3 15:17:22 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 Jul 3 15:00:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* encoding.c (enc_find): [DOC] never accepted a symbol.

7
eval.c
View file

@ -931,13 +931,6 @@ rb_frame_caller(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

View file

@ -911,11 +911,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));
#if defined __GNUC__ && __GNUC__ >= 4
#pragma GCC visibility pop
#endif

View file

@ -321,6 +321,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);

View file

@ -1020,4 +1020,88 @@ class TestSetTraceFunc < Test::Unit::TestCase
assert_equal 4, n
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

View file

@ -1517,7 +1517,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;

View file

@ -1,6 +1,6 @@
#define RUBY_VERSION "2.0.0"
#define RUBY_RELEASE_DATE "2014-07-03"
#define RUBY_PATCHLEVEL 513
#define RUBY_PATCHLEVEL 514
#define RUBY_RELEASE_YEAR 2014
#define RUBY_RELEASE_MONTH 7

18
vm.c
View file

@ -231,6 +231,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

View file

@ -684,7 +684,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);
}
@ -1073,13 +1073,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{