ワナベと申します。

Fiber のトップフレームに ISeq を加えるパッチを書きました。
ついでなので Thread も同様にしました。
test_knownbug.rb の [ruby-dev:34128] とあるテストが通るようになります。

バックトレース対策で iseq->filename に nil を入れてしまいましたが
(普通に filename を入れると、Fiber.new(method(:load)).resume で
 ファイル名が空文字列、行番号が 0 などと表示される)
本来はどう対処するのがスマートなのでしょうか。

Index: eval_error.c
===================================================================
--- eval_error.c	(revision 15933)
+++ eval_error.c	(working copy)
@@ -10,11 +10,11 @@
     rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp);

     if (cfp) {
-	return RSTRING_PTR(cfp->iseq->filename);
+	if (!NIL_P(cfp->iseq->filename)) {
+	    return RSTRING_PTR(cfp->iseq->filename);
+	}
     }
-    else {
-	return 0;
-    }
+    return 0;
 }

 int
Index: cont.c
===================================================================
--- cont.c	(revision 15933)
+++ cont.c	(working copy)
@@ -501,6 +501,8 @@
     rb_context_t *cont = fiber_alloc(klass);
     VALUE contval = cont->self;
     rb_thread_t *th = &cont->saved_thread;
+    VALUE filename = rb_str_new2("<dummy fiber toplevel>");
+    VALUE iseq = rb_iseq_new(0, filename, Qnil, 0, ISEQ_TYPE_TOP);

     /* initialize */
     cont->vm_stack = 0;
@@ -509,18 +511,7 @@
     th->stack_size = FIBER_VM_STACK_SIZE;
     th->stack = ALLOC_N(VALUE, th->stack_size);

-    th->cfp = (void *)(th->stack + th->stack_size);
-    th->cfp--;
-    th->cfp->pc = 0;
-    th->cfp->sp = th->stack + 1;
-    th->cfp->bp = 0;
-    th->cfp->lfp = th->stack;
-    *th->cfp->lfp = 0;
-    th->cfp->dfp = th->stack;
-    th->cfp->self = Qnil;
-    th->cfp->flag = 0;
-    th->cfp->iseq = 0;
-    th->cfp->proc = 0;
+    vm_set_branch_frame(th, iseq);
     th->cfp->block_iseq = 0;
     th->tag = 0;
     th->local_storage = st_init_numtable();
Index: vm.c
===================================================================
--- vm.c	(revision 15933)
+++ vm.c	(working copy)
@@ -1666,6 +1666,17 @@
     return obj;
 }

+void
+vm_set_branch_frame(rb_thread_t *th, VALUE iseqval)
+{
+    rb_iseq_t *iseq;
+
+    th->cfp = (void *)(th->stack + th->stack_size);
+    GetISeqPtr(iseqval, iseq);
+    vm_push_frame(th, iseq, FRAME_MAGIC_TOP, th->top_self, 0,
+		  iseq->iseq_encoded, th->stack, 0, iseq->local_size);
+}
+
 static void
 th_init2(rb_thread_t *th)
 {
@@ -1687,24 +1698,37 @@
 }

 static void
-th_init(rb_thread_t *th)
+th_init(rb_thread_t *th, VALUE iseq)
 {
-    th_init2(th);
+    /* allocate thread stack */
+    th->stack_size = RUBY_VM_THREAD_STACK_SIZE;
+    th->stack = thread_recycle_stack(th->stack_size);
+
+    vm_set_branch_frame(th, iseq);
+
+    th->status = THREAD_RUNNABLE;
+    th->errinfo = Qnil;
+
+#if USE_VALUE_CACHE
+    th->value_cache_ptr = &th->value_cache[0];
+#endif
 }

 static VALUE
 ruby_thread_init(VALUE self)
 {
+    VALUE filename = rb_str_new2("<dummy thread toplevel>");
+    VALUE iseq = rb_iseq_new(0, filename, Qnil, 0, ISEQ_TYPE_TOP);
     rb_thread_t *th;
     rb_vm_t *vm = GET_THREAD()->vm;
     GetThreadPtr(self, th);

-    th_init(th);
     th->self = self;
     th->vm = vm;

     th->top_wrapper = 0;
     th->top_self = rb_vm_top_self();
+    th_init(th, iseq);
     return self;
 }

Index: vm_dump.c
===================================================================
--- vm_dump.c	(revision 15933)
+++ vm_dump.c	(working copy)
@@ -102,7 +102,12 @@
 	    line = vm_get_sourceline(cfp);
 	    if (line) {
 		char fn[MAX_POSBUF+1];
-		snprintf(fn, MAX_POSBUF, "%s", RSTRING_PTR(cfp->iseq->filename));
+		VALUE filename = cfp->iseq->filename;
+
+		if (NIL_P(filename)) {
+		    filename = cfp->iseq->name;
+		}
+		snprintf(fn, MAX_POSBUF, "%s", RSTRING_PTR(filename));
 		snprintf(posbuf, MAX_POSBUF, "%s:%d", fn, line);
 	    }
 	}


-- 
ワナベ