      {
 Index: common.mk
 ===================================================================
---- common.mk	(revision 28931)
+--- common.mk	(revision 28972)
 +++ common.mk	(working copy)
 @@ -30,6 +30,7 @@
  

     return trace;
 }
 
@@ -4014,6 +4092,8 @@
 	return "class";
       case RUBY_EVENT_END:
 	return "end";

     }
     else {
 	th->event_flags &= (~RUBY_EVENT_VM);
@@ -3793,22 +3801,34 @@
 void
 rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
 {
-    const VALUE errinfo = th->errinfo;
-    const rb_event_flag_t wait_event = th->event_flags;
+    int do_tracing;
 
     if (self == rb_mRubyVMFrozenCore) return;
-    if (wait_event & flag) {
-	exec_event_hooks(th->event_hooks, flag, self, id, klass);
-    }
-    if (wait_event & RUBY_EVENT_VM) {
-	if (th->vm->event_hooks == NULL) {
-	    th->event_flags &= (~RUBY_EVENT_VM);
+
+    /* Either we haven't turned off tracing via the thread mechanism
+       or we set a return trace and the event is a some kind of return. */
+    do_tracing = UNLIKELY( (th->tracing <= 0 && 
+			    !(th->cfp->tracing & VM_FRAME_TRACE_OFF)) ||
+			   ((flag & (RUBY_EVENT_C_RETURN | RUBY_EVENT_RETURN))
+			    && th->cfp->tracing & VM_FRAME_TRACE_RETURN) );
+    if (do_tracing) {
+	const VALUE errinfo = th->errinfo;
+	const rb_event_flag_t wait_event = th->event_flags;
+	
+	if (wait_event & flag) {
+	    if (UNLIKELY(!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, th->cfp)))
+		exec_event_hooks(th->event_hooks, flag, self, id, klass);
 	}
-	else {
-	    exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
+	if (wait_event & RUBY_EVENT_VM) {
+	    if (th->vm->event_hooks == NULL) {
+		th->event_flags &= (~RUBY_EVENT_VM);
+	    }
+	    else {
+		exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
+	    }
 	}
+	th->errinfo = errinfo;
     }
-    th->errinfo = errinfo;
 }
 
 void
@@ -3884,19 +3904,48 @@
     return ST_CONTINUE;
 }
 
