  /* other frame flag */
  #define VM_FRAME_FLAG_PASSED 0x0100
  
-@@ -691,13 +706,29 @@
- void
- rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass);
- 
--#define EXEC_EVENT_HOOK(th, flag, self, id, klass) do { \
--    rb_event_flag_t wait_event__ = th->event_flags; \
--    if (UNLIKELY(wait_event__)) { \
--	if (wait_event__ & (flag | RUBY_EVENT_VM)) { \
--	    rb_threadptr_exec_event_hooks(th, flag, self, id, klass); \
--	} \
--    } \
--} while (0)
-+#define EXEC_EVENT_HOOK(th, flag, self, id, klass)			\
-+  if (LIKELY(0 == th->tracing)) {					\
-+	rb_event_flag_t wait_event__ = th->event_flags;			\
-+	if (UNLIKELY(wait_event__)) {					\
-+	    if (wait_event__ & (flag | RUBY_EVENT_VM)) {		\
-+		rb_threadptr_exec_event_hooks(th, flag, self, id, klass); \
-+	    }								\
-+	}								\
-+    }
- 
-+/* Customized version of EXEC_EVENT_HOOK for RUBY_EVENT_RETURN events */
-+#define EXEC_EVENT_RETURN_HOOK(th, flag, self, id, klass)		\
-+    if (LIKELY(0 == th->tracing &&					\
-+	       (!(th->cfp->tracing & VM_FRAME_TRACE_OFF)		\
-+		|| (th->cfp->tracing & VM_FRAME_TRACE_RETURN)))) {	\
-+	rb_event_flag_t wait_event__ = th->event_flags;			\
-+	if (UNLIKELY(wait_event__)) {					\
-+	    if (wait_event__ & (flag | RUBY_EVENT_VM)) {		\
-+	        th->tracing = 1;					\
-+		rb_threadptr_exec_event_hooks(th, flag, self, id, klass); \
-+		th->tracing = 0;					\
-+	    }								\
-+	}								\
-+    }
-+
- #endif /* RUBY_VM_CORE_H */
 Index: iseq.c
 ===================================================================
 --- iseq.c	(revision 28682)

+    rb_event_flag_t event_flags;
+    int tracing;  /* 0 if not tracing. If less than 0, skip that many
+		     C call/return pairs */
+    int exec_event_tracing;  /* 0 if not in rb_threadptr_evec_event_hooks. */
+
+    /* misc */
+    int method_missing_reason;

     }
     else {
 	th->event_flags &= (~RUBY_EVENT_VM);
@@ -3784,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
@@ -3875,19 +3904,48 @@
     return ST_CONTINUE;
 }
 
