ワナベと申します。 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); } } -- ワナベ