From: wanabe Date: 2008-04-16T20:55:53+09:00 Subject: [ruby-dev:34431] patch for ruby-core:14813 ワナベと申します。 [ruby-core:14813] に対するパッチを書きました。 ブロック引数が与えられたブロック、および define_method のブロック中での given_block? と yield の挙動が変わります。 ブロックフレームの bp を押し上げ、できた隙間に強引にブロック引数を持たせています。 Index: vm_core.h =================================================================== --- vm_core.h (revision 15984) +++ vm_core.h (working copy) @@ -608,6 +608,7 @@ VALUE vm_yield(rb_thread_t *th, int argc, VALUE *argv); VALUE vm_call0(rb_thread_t *th, VALUE klass, VALUE recv, VALUE id, ID oid, int argc, const VALUE *argv, NODE *body, int nosuper); +rb_block_t *vm_get_block(rb_control_frame_t *cfp); int vm_get_sourceline(rb_control_frame_t *); Index: eval.c =================================================================== --- eval.c (revision 15984) +++ eval.c (working copy) @@ -837,11 +837,10 @@ JUMP_TAG(tag); } -int -rb_block_given_p(void) +static inline VALUE +block_given_p(rb_control_frame_t *cfp) { - rb_thread_t *th = GET_THREAD(); - if (GC_GUARDED_PTR_REF(th->cfp->lfp[0])) { + if (vm_get_block(cfp)) { return Qtrue; } else { @@ -850,6 +849,12 @@ } int +rb_block_given_p(void) +{ + return block_given_p(GET_THREAD()->cfp); +} + +int rb_iterator_p() { return rb_block_given_p(); @@ -882,13 +887,9 @@ { rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp; + cfp = vm_get_ruby_level_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)); - if (GC_GUARDED_PTR_REF(cfp->lfp[0])) { - return Qtrue; - } - else { - return Qfalse; - } + return block_given_p(cfp); } VALUE rb_eThreadError; Index: vm.c =================================================================== --- vm.c (revision 15984) +++ vm.c (working copy) @@ -539,6 +539,30 @@ return vm_call_super(GET_THREAD(), argc, argv); } +rb_block_t * +vm_get_block(rb_control_frame_t *cfp) { + rb_block_t *block = 0; + + if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { + if (cfp->iseq->type == ISEQ_TYPE_BLOCK) { + block = ((rb_block_t *)(GC_GUARDED_PTR_REF(cfp->dfp[1]))); + if (cfp->iseq->defined_method_id) { + return block; + } + } + else if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq->local_iseq)) { + if (cfp->iseq->local_iseq->type != ISEQ_TYPE_METHOD) { + return 0; + } + } + } + if (!block) { + block = ((rb_block_t *)(GC_GUARDED_PTR_REF(cfp->lfp[0]))); + } + + return block; +} + /* C -> Ruby: block */ static VALUE @@ -568,6 +592,7 @@ self, GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp, iseq->local_size - arg_size); + vm_add_specval(th, GC_GUARDED_PTR(blockptr)); val = vm_eval_body(th); } @@ -1316,6 +1341,7 @@ vm_push_frame(th, catch_iseq, FRAME_MAGIC_BLOCK, cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded, cfp->sp + 1, cfp->lfp, catch_iseq->local_size - 1); + vm_add_specval(th, 0); state = 0; th->errinfo = Qnil; Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 15984) +++ vm_insnhelper.c (working copy) @@ -68,6 +68,14 @@ } static inline void +vm_add_specval(rb_thread_t *th, VALUE specval) +{ + *th->cfp->bp = specval; + th->cfp->sp++; + th->cfp->bp++; +} + +static inline void vm_pop_frame(rb_thread_t *th) { #if COLLECT_PROFILE @@ -792,11 +800,12 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag) { VALUE val; - rb_block_t *block = GET_BLOCK_PTR(); + rb_block_t *block = 0; rb_iseq_t *iseq; int argc = num; - if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0) { + block = vm_get_block(reg_cfp); + if (block == 0) { vm_localjump_error("no block given (yield)", Qnil, 0); } iseq = block->iseq; @@ -817,6 +826,7 @@ FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp, iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp, iseq->local_size - arg_size); + vm_add_specval(th, 0); return Qundef; } -- ワナベ