[前][次][番号順一覧][スレッド一覧]

ruby-changes:14556

From: ko1 <ko1@a...>
Date: Sun, 24 Jan 2010 22:52:50 +0900 (JST)
Subject: [ruby-changes:14556] Ruby:r26395 (trunk): * eval.c, vm.c, vm_eval.c, vm_insnhelper.c: fix issues about

ko1	2010-01-24 22:52:32 +0900 (Sun, 24 Jan 2010)

  New Revision: 26395

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26395

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

  Modified files:
    trunk/ChangeLog
    trunk/eval.c
    trunk/test/ruby/test_settracefunc.rb
    trunk/vm.c
    trunk/vm_eval.c
    trunk/vm_insnhelper.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 26394)
+++ ChangeLog	(revision 26395)
@@ -1,3 +1,12 @@
+Sun Jan 24 22:48:05 2010  Koichi Sasada  <ko1@a...>
+
+	* 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@f...>
 
 	* string.c (rb_enc_strlen_cr): increment by rb_enc_mbminlen(enc) for
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 26394)
+++ vm_eval.c	(revision 26395)
@@ -814,6 +814,9 @@
     return Qnil;		/* dummy */
 }
 
+static const char *
+vm_frametype_name(const rb_control_frame_t *cfp);
+
 VALUE
 rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
 	   VALUE (* bl_proc) (ANYARGS), VALUE data2)
@@ -852,7 +855,17 @@
 		state = 0;
 		th->state = 0;
 		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{
 		/* SDR(); printf("%p, %p\n", cdfp, escape_dfp); */
Index: eval.c
===================================================================
--- eval.c	(revision 26394)
+++ eval.c	(revision 26395)
@@ -352,11 +352,10 @@
 NORETURN(static void rb_longjmp(int, volatile VALUE));
 
 static void
-rb_longjmp(int tag, volatile VALUE mesg)
+setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg)
 {
     VALUE at;
     VALUE e;
-    rb_thread_t *th = GET_THREAD();
     const char *file;
     volatile int line = 0;
 
@@ -425,10 +424,15 @@
     rb_trap_restore_mask();
 
     if (tag != TAG_FATAL) {
-	EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self,
-			0 /* TODO: id */, 0 /* TODO: klass */);
+	EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0);
     }
+}
 
+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);
     JUMP_TAG(tag);
 }
@@ -559,9 +563,18 @@
 rb_raise_jump(VALUE mesg)
 {
     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);
-    /* 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
Index: vm.c
===================================================================
--- vm.c	(revision 26394)
+++ vm.c	(revision 26395)
@@ -1001,6 +1001,27 @@
 #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 */
 
 /*                  finish
@@ -1137,7 +1158,11 @@
 	cont_pc = cont_sp = catch_iseqval = 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;
@@ -1298,8 +1323,20 @@
 	    goto vm_loop_start;
 	}
 	else {
-	    th->cfp++;
-	    if (th->cfp->pc != &finish_insn_seq[0]) {
+	    /* skip frame */
+
+	    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;
 	    }
 	    else {
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 26394)
+++ vm_insnhelper.c	(revision 26395)
@@ -360,44 +360,30 @@
 
 static inline VALUE
 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)
 {
     VALUE val = 0;
     int state = 0;
     const rb_method_definition_t *def = me->def;
-    VALUE klass = me->klass;
-    ID id = me->called_id;
+    rb_control_frame_t *cfp;
 
-    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);
-    /* 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);
+    cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
+			recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
+    cfp->me = me;
+    reg_cfp->sp -= num + 1;
 
-	cfp->me = me;
-	reg_cfp->sp -= num + 1;
+    val = call_cfunc(def->body.cfunc.func, recv, (int)def->body.cfunc.argc, num, reg_cfp->sp + 1);
 
-	val = call_cfunc(def->body.cfunc.func, recv, (int)def->body.cfunc.argc, num, reg_cfp->sp + 1);
+    if (reg_cfp != th->cfp + 1) {
+	rb_bug("cfp consistency error - send");
+    }
 
-	if (reg_cfp != th->cfp + 1) {
-	    rb_bug("cfp consistency error - send");
-	}
+    vm_pop_frame(th);
 
-	vm_pop_frame(th);
-    }
-    TH_POP_TAG();
-    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
-    if (state) TH_JUMP_TAG(th, state);
+    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
 
     return val;
 }
@@ -512,7 +498,7 @@
 	      }
 	      case VM_METHOD_TYPE_NOTIMPLEMENTED:
 	      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;
 	      }
 	      case VM_METHOD_TYPE_ATTRSET:{
Index: test/ruby/test_settracefunc.rb
===================================================================
--- test/ruby/test_settracefunc.rb	(revision 26394)
+++ test/ruby/test_settracefunc.rb	(revision 26395)
@@ -263,8 +263,31 @@
     assert_equal([], events)
   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
-    assert_raise(TypeError) { set_trace_func(1) }
+      assert_raise(TypeError) { set_trace_func(1) }
   end
 
   def test_raise_in_trace

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]