mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* eval.c, vm.c, vm_eval.c, vm_insnhelper.c: fix issues about
return and c-return trace. This issue skips (c-)return event with global jump such as break or return. This fix make vm invoke hooks at stack rewind timing. fix [ruby-core:27606] [Bug #2610]. * test/ruby/test_settracefunc.rb: add a test for above. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2979842520
commit
618445576f
6 changed files with 121 additions and 40 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
Sun Jan 24 22:48:05 2010 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
* eval.c, vm.c, vm_eval.c, vm_insnhelper.c: fix issues about
|
||||||
|
return and c-return trace. This issue skips (c-)return event
|
||||||
|
with global jump such as break or return. This fix make vm invoke
|
||||||
|
hooks at stack rewind timing. fix [ruby-core:27606] [Bug #2610].
|
||||||
|
|
||||||
|
* test/ruby/test_settracefunc.rb: add a test for above.
|
||||||
|
|
||||||
Sun Jan 24 14:21:48 2010 Tanaka Akira <akr@fsij.org>
|
Sun Jan 24 14:21:48 2010 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* string.c (rb_enc_strlen_cr): increment by rb_enc_mbminlen(enc) for
|
* string.c (rb_enc_strlen_cr): increment by rb_enc_mbminlen(enc) for
|
||||||
|
|
25
eval.c
25
eval.c
|
@ -352,11 +352,10 @@ rb_frozen_class_p(VALUE klass)
|
||||||
NORETURN(static void rb_longjmp(int, volatile VALUE));
|
NORETURN(static void rb_longjmp(int, volatile VALUE));
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rb_longjmp(int tag, volatile VALUE mesg)
|
setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg)
|
||||||
{
|
{
|
||||||
VALUE at;
|
VALUE at;
|
||||||
VALUE e;
|
VALUE e;
|
||||||
rb_thread_t *th = GET_THREAD();
|
|
||||||
const char *file;
|
const char *file;
|
||||||
volatile int line = 0;
|
volatile int line = 0;
|
||||||
|
|
||||||
|
@ -425,10 +424,15 @@ rb_longjmp(int tag, volatile VALUE mesg)
|
||||||
rb_trap_restore_mask();
|
rb_trap_restore_mask();
|
||||||
|
|
||||||
if (tag != TAG_FATAL) {
|
if (tag != TAG_FATAL) {
|
||||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self,
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0);
|
||||||
0 /* TODO: id */, 0 /* TODO: klass */);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_longjmp(int tag, volatile VALUE mesg)
|
||||||
|
{
|
||||||
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
setup_exception(th, tag, mesg);
|
||||||
rb_thread_raised_clear(th);
|
rb_thread_raised_clear(th);
|
||||||
JUMP_TAG(tag);
|
JUMP_TAG(tag);
|
||||||
}
|
}
|
||||||
|
@ -559,9 +563,18 @@ void
|
||||||
rb_raise_jump(VALUE mesg)
|
rb_raise_jump(VALUE mesg)
|
||||||
{
|
{
|
||||||
rb_thread_t *th = GET_THREAD();
|
rb_thread_t *th = GET_THREAD();
|
||||||
|
rb_control_frame_t *cfp = th->cfp;
|
||||||
|
VALUE klass = cfp->me->klass;
|
||||||
|
VALUE self = cfp->self;
|
||||||
|
ID mid = cfp->me->called_id;
|
||||||
|
|
||||||
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
||||||
/* TODO: fix me */
|
|
||||||
rb_longjmp(TAG_RAISE, mesg);
|
setup_exception(th, TAG_RAISE, mesg);
|
||||||
|
|
||||||
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, self, mid, klass);
|
||||||
|
rb_thread_raised_clear(th);
|
||||||
|
JUMP_TAG(TAG_RAISE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -263,6 +263,29 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
||||||
assert_equal([], events)
|
assert_equal([], events)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_break # [ruby-core:27606] [Bug #2610]
|
||||||
|
events = []
|
||||||
|
eval <<-EOF.gsub(/^.*?: /, "")
|
||||||
|
1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
|
||||||
|
2: events << [event, lineno, mid, klass]
|
||||||
|
3: })
|
||||||
|
4: [1,2,3].any? {|n| n}
|
||||||
|
8: set_trace_func(nil)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
[["c-return", 3, :set_trace_func, Kernel],
|
||||||
|
["line", 4, __method__, self.class],
|
||||||
|
["c-call", 4, :any?, Enumerable],
|
||||||
|
["c-call", 4, :each, Array],
|
||||||
|
["line", 4, __method__, self.class],
|
||||||
|
["c-return", 4, :each, Array],
|
||||||
|
["c-return", 4, :any?, Enumerable],
|
||||||
|
["line", 5, __method__, self.class],
|
||||||
|
["c-call", 5, :set_trace_func, Kernel]].each{|e|
|
||||||
|
assert_equal(e, events.shift)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def test_invalid_proc
|
def test_invalid_proc
|
||||||
assert_raise(TypeError) { set_trace_func(1) }
|
assert_raise(TypeError) { set_trace_func(1) }
|
||||||
end
|
end
|
||||||
|
|
43
vm.c
43
vm.c
|
@ -1001,6 +1001,27 @@ vm_init_redefined_flag(void)
|
||||||
#undef OP
|
#undef OP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* for vm development */
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
vm_frametype_name(const rb_control_frame_t *cfp)
|
||||||
|
{
|
||||||
|
switch (VM_FRAME_TYPE(cfp)) {
|
||||||
|
case VM_FRAME_MAGIC_METHOD: return "method";
|
||||||
|
case VM_FRAME_MAGIC_BLOCK: return "block";
|
||||||
|
case VM_FRAME_MAGIC_CLASS: return "class";
|
||||||
|
case VM_FRAME_MAGIC_TOP: return "top";
|
||||||
|
case VM_FRAME_MAGIC_FINISH: return "finish";
|
||||||
|
case VM_FRAME_MAGIC_CFUNC: return "cfunc";
|
||||||
|
case VM_FRAME_MAGIC_PROC: return "proc";
|
||||||
|
case VM_FRAME_MAGIC_IFUNC: return "ifunc";
|
||||||
|
case VM_FRAME_MAGIC_EVAL: return "eval";
|
||||||
|
case VM_FRAME_MAGIC_LAMBDA: return "lambda";
|
||||||
|
default:
|
||||||
|
rb_bug("unknown frame");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* evaluator body */
|
/* evaluator body */
|
||||||
|
|
||||||
/* finish
|
/* finish
|
||||||
|
@ -1137,7 +1158,11 @@ vm_exec(rb_thread_t *th)
|
||||||
cont_pc = cont_sp = catch_iseqval = 0;
|
cont_pc = cont_sp = catch_iseqval = 0;
|
||||||
|
|
||||||
while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
|
while (th->cfp->pc == 0 || th->cfp->iseq == 0) {
|
||||||
th->cfp++;
|
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);
|
||||||
|
}
|
||||||
|
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
cfp = th->cfp;
|
cfp = th->cfp;
|
||||||
|
@ -1298,8 +1323,20 @@ vm_exec(rb_thread_t *th)
|
||||||
goto vm_loop_start;
|
goto vm_loop_start;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
th->cfp++;
|
/* skip frame */
|
||||||
if (th->cfp->pc != &finish_insn_seq[0]) {
|
|
||||||
|
switch (VM_FRAME_TYPE(th->cfp)) {
|
||||||
|
case VM_FRAME_MAGIC_METHOD:
|
||||||
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0);
|
||||||
|
break;
|
||||||
|
case VM_FRAME_MAGIC_CLASS:
|
||||||
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
||||||
|
|
||||||
|
if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) {
|
||||||
goto exception_handler;
|
goto exception_handler;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
15
vm_eval.c
15
vm_eval.c
|
@ -814,6 +814,9 @@ rb_f_loop(VALUE self)
|
||||||
return Qnil; /* dummy */
|
return Qnil; /* dummy */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
vm_frametype_name(const rb_control_frame_t *cfp);
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
|
rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
|
||||||
VALUE (* bl_proc) (ANYARGS), VALUE data2)
|
VALUE (* bl_proc) (ANYARGS), VALUE data2)
|
||||||
|
@ -852,7 +855,17 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
|
||||||
state = 0;
|
state = 0;
|
||||||
th->state = 0;
|
th->state = 0;
|
||||||
th->errinfo = Qnil;
|
th->errinfo = Qnil;
|
||||||
th->cfp = cfp;
|
|
||||||
|
/* check skipped frame */
|
||||||
|
while (th->cfp != cfp) {
|
||||||
|
/* printf("skipped frame: %s\n", vm_frametype_name(th->cfp)); */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
/* SDR(); printf("%p, %p\n", cdfp, escape_dfp); */
|
/* SDR(); printf("%p, %p\n", cdfp, escape_dfp); */
|
||||||
|
|
|
@ -360,30 +360,18 @@ call_cfunc(VALUE (*func)(), VALUE recv,
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||||||
int num, VALUE recv, const rb_block_t *blockptr, VALUE flag,
|
int num, VALUE recv, const rb_block_t *blockptr,
|
||||||
const rb_method_entry_t *me)
|
const rb_method_entry_t *me)
|
||||||
{
|
{
|
||||||
VALUE val = 0;
|
VALUE val = 0;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
const rb_method_definition_t *def = me->def;
|
const rb_method_definition_t *def = me->def;
|
||||||
VALUE klass = me->klass;
|
rb_control_frame_t *cfp;
|
||||||
ID id = me->called_id;
|
|
||||||
|
|
||||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
|
||||||
|
|
||||||
TH_PUSH_TAG(th);
|
cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||||||
/* TODO: fix me. separate event */
|
|
||||||
if (th->event_flags & (RUBY_EVENT_C_RETURN | RUBY_EVENT_VM)) {
|
|
||||||
state = TH_EXEC_TAG();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_th->tag = _tag.prev;
|
|
||||||
}
|
|
||||||
if (state == 0) {
|
|
||||||
rb_control_frame_t *cfp =
|
|
||||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
|
||||||
recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
|
recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
|
||||||
|
|
||||||
cfp->me = me;
|
cfp->me = me;
|
||||||
reg_cfp->sp -= num + 1;
|
reg_cfp->sp -= num + 1;
|
||||||
|
|
||||||
|
@ -394,10 +382,8 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_pop_frame(th);
|
vm_pop_frame(th);
|
||||||
}
|
|
||||||
TH_POP_TAG();
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
|
||||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
|
|
||||||
if (state) TH_JUMP_TAG(th, state);
|
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
@ -512,7 +498,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||||
case VM_METHOD_TYPE_CFUNC:{
|
case VM_METHOD_TYPE_CFUNC:{
|
||||||
val = vm_call_cfunc(th, cfp, num, recv, blockptr, flag, me);
|
val = vm_call_cfunc(th, cfp, num, recv, blockptr, me);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VM_METHOD_TYPE_ATTRSET:{
|
case VM_METHOD_TYPE_ATTRSET:{
|
||||||
|
|
Loading…
Reference in a new issue