[Feature:trunk] argument delegation

Yuguie$B$G$9e(B

2010/6/17 Yukihiro M. [email protected]:

e$B$,!“$b$H$b$H$NF05!$H$OJL$H$7$F!”!Ve(B&e$B!We(B1e$BJ8;z$G$=$N%3%s%F%-%9%He(B
e$B$N%V%m%C%/$rEO$9$N$O!“LLGr$$%”%$%G%#%"$@$H;W$$$^$9!#$3$N>l9ge(B
e$B$O!“2>0z?t%j%9%H$N%V%m%C%/0z?t$,$J$/$F$b!”%V%m%C%/$rEO$9$3$He(B
e$B$K$J$k$s$G$9$+$M!#e(B

e$B?<$$8F$S=P$73,AX$G%V%m%C%/$r<u$1<h$k$?$a$K!“>e0L$N%a%=%C%I$,1d!9$H%V%m%C%/$r0z$-EO$7B3$1$k$C$F$$$&%1!<%9$O<B:]$K%W%m%0%i%`$7$F$$$F$h$/=P2q$$$^$9!#$G$9$+$i!”$3$N$H$-2<0L8F$S=P$7$N<B0z?t$Ke(B&blocke$B$rB-$7$F!“2>0z?t$K$bK:$l$:$Ke(B&blocke$B$rB-$7$F$H$$$&$N$OLLE]$G!”$3$N%“%$%G%#%”$OJXMx$=$&$G$9!#e(B

e$B$7$+$7!“$”$^$j$K$bC;$9$.$k!#e(B&e$B#1J8;z$O8+Mn$H$7$=$&$G$9!#e(B
foo(a, b, &yield)
e$B$J$s$F$N$OBLL$G$7$g$&$+!#e(Byield e$B$He(B
block.calle$B$NN;w@-$+$i$NN?d$G$9!#e(B

e$B1sF#$G$9!#e(B

2010e$BG/e(B8e$B7ne(B25e$BF|e(B3:23 SASADA Koichi [email protected]:

e$B!!$G$-$l$P!$e(BVM_CALL_ARGS_BLOCKTRGH_BIT e$B$rA}$d$9$s$8$c$J$/e(B
e$B$F!$e(BVM_CALL_ARGS_BLOCKARG_BIT e$B$@$1$I!$e(Bblockiseqe$B!!$+$J$s$+$NCM$rFC<l$K$7e(B
e$B$F$*$/$H$+!$$=$&$$$&<BAu$K$7$F$b$i$($k$H$$$$$s$8$c$J$$$+$H;W$$$^$9!%e(B

e$B!JL?Na%*%Z%i%s%I$N%P%j%(!<%7%g%s$,8:$C$?J}$,?'!9$&$l$7$$!Ke(B

e$B%3%a%s%H$"$j$,$H$&$4$6$$$^$9!#$G$b!“8+$+$1>e%P%j%(!<%7%g%s$rA}$d$5$J$$e(B
e$B$H$3$m$G!“e(BVM_CALL_ARGS_BLOCKTRGH_BIT e$B$K7k9=0[$J$ke(B 2
e$B$D$N0UL#$rFM$C9~$`e(B
e$B$3$H$K$J$ke(B (e$B%9%?%C%/$Ke(B Proc
e$B$r:$;$k!&:$;$J$$$N0c$$$,$”$k$N$G!”:Y!9>re(B
e$B7oH=Dj$,I,MW$K$J$ke(B)
e$B$N$G!"Bg$7$F4r$7$/$J$$$H;W$$$^$9!#%a%s%F%J%s%9@-$be(B
e$B2<$,$j$^$9$N$G!"85$N%Q%C%A$NJ}$,$$$$$H;W$$$^$9!#e(B

e$B0l1~e(B blockiseq e$B$Ke(B -1 e$B$,F~$C$F$?$ie(B BLOCKTRGH
e$B07$$$K$9$k%Q%C%A$b=q$$$F$_e(B
e$B$^$7$?$,!"$+$J$jK<AE*$G$J$$%3!<%I$G$$$C$Q$$$K$J$j$^$7$?!#e(B

e$B:#e(B trunk e$B$,2u$l$F$k$h$&$J$N$G!"e(Btest-all

e$B$O$G$-$F$^$;$s!#e(B

diff --git a/compile.c b/compile.c
index 2fd804c…1c04640 100644
— a/compile.c
+++ b/compile.c
@@ -1411,11 +1411,18 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR
anchor)
case TS_ISEQ: /
iseq */
{
VALUE v = operands[j];

  •      rb_iseq_t *block = 0;
    
  •      VALUE block = 0;
         if (v) {
    
  •    GetISeqPtr(v, block);
    
  •    if (v == Qundef) {
    
  •        block = (VALUE)-1;
    
  •    }
    
  •    else {
    
  •        rb_iseq_t *blk;
    
  •        GetISeqPtr(v, blk);
    
  •        block = (VALUE)blk;
    
  •    }
         }
    
  •      generated_iseq[pos + 1 + j] = (VALUE)block;
    
  •      generated_iseq[pos + 1 + j] = block;
         break;
     }
         case TS_VALUE:  /* VALUE */
    

@@ -2853,7 +2860,7 @@ add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t
*iseq, int is_return)
}

static VALUE
-setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned
long *flag)
+setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, VALUE
*blockiseq, unsigned long *flag)
{
VALUE argc = INT2FIX(0);
int nsplat = 0;
@@ -2863,7 +2870,13 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args,
NODE *argn, unsigned long *flag)
INIT_ANCHOR(arg_block);
INIT_ANCHOR(args_splat);
if (argn && nd_type(argn) == NODE_BLOCK_PASS) {

  • COMPILE(arg_block, “block”, argn->nd_body);
  • if ((VALUE)argn->nd_body != (VALUE)-1) {
  •  COMPILE(arg_block, "block", argn->nd_body);
    
  • }
  • else {
  •  arg_block = 0;
    
  •  if (blockiseq) *blockiseq = Qundef;
    
  • }
    *flag |= VM_CALL_ARGS_BLOCKARG_BIT;
    argn = argn->nd_head;
    }
    @@ -2932,7 +2945,7 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args,
    NODE *argn, unsigned long *flag)
    ADD_SEQ(args, args_splat);
    }
  • if (*flag & VM_CALL_ARGS_BLOCKARG_BIT) {
  • if ((*flag & VM_CALL_ARGS_BLOCKARG_BIT) && arg_block) {
    ADD_SEQ(args, arg_block);
    }
    return argc;
    @@ -3776,7 +3789,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
    *ret, NODE * node, int poped)
    boff = 1;
    default:
    INIT_ANCHOR(args);
  •  argc = setup_args(iseq, args, node->nd_args->nd_head, &flag);
    
  •  argc = setup_args(iseq, args, node->nd_args->nd_head, 0, &flag);
     ADD_SEQ(ret, args);
    

    }
    ADD_INSN1(ret, nd_line(node), dupn, FIXNUM_INC(argc, 1 + boff));
    @@ -4083,7 +4096,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
    *ret, NODE * node, int poped)

    /* args */
    if (nd_type(node) != NODE_VCALL) {

  •  argc = setup_args(iseq, args, node->nd_args, &flag);
    
  •  argc = setup_args(iseq, args, node->nd_args, &parent_block, 
    

&flag);
}
else {
argc = INT2FIX(0);
@@ -4121,7 +4134,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
*ret, NODE * node, int poped)
INIT_ANCHOR(args);
iseq->compile_data->current_block = Qfalse;
if (nd_type(node) == NODE_SUPER) {

  •  argc = setup_args(iseq, args, node->nd_args, &flag);
    
  •  argc = setup_args(iseq, args, node->nd_args, &parent_block, 
    

&flag);
}
else {
/* NODE_ZSUPER */
@@ -4294,7 +4307,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
*ret, NODE * node, int poped)
}

if (node->nd_head) {

  •  argc = setup_args(iseq, args, node->nd_head, &flag);
    
  •  argc = setup_args(iseq, args, node->nd_head, 0, &flag);
    

    }
    else {
    argc = INT2FIX(0);
    @@ -4906,7 +4919,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
    *ret, NODE * node, int poped)

    INIT_ANCHOR(recv);
    INIT_ANCHOR(args);

  • argc = setup_args(iseq, args, node->nd_args, &flag);
  • argc = setup_args(iseq, args, node->nd_args, 0, &flag);

    if (node->nd_recv == (NODE *) 1) {
    flag |= VM_CALL_FCALL_BIT;
    diff --git a/insns.def b/insns.def
    index fcd97ae…10b99be 100644
    — a/insns.def
    +++ b/insns.def
    @@ -989,7 +989,7 @@ DEFINE_INSN
    send
    (ID op_id, rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag, IC ic)
    (…)
    -(VALUE val) // inc += - (int)(op_argc + ((op_flag &
    VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
    +(VALUE val) // inc += - (int)(op_argc + (((op_flag &
    VM_CALL_ARGS_BLOCKARG_BIT) && (VALUE)blockiseq != (VALUE)-1) ? 1 :
    0));
    {
    const rb_method_entry_t *me;
    VALUE recv, klass;
    @@ -1017,7 +1017,7 @@ DEFINE_INSN
    invokesuper
    (rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag)
    (…)
    -(VALUE val) // inc += - (int)(op_argc + ((op_flag &
    VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
    +(VALUE val) // inc += - (int)(op_argc + (((op_flag &
    VM_CALL_ARGS_BLOCKARG_BIT) && (VALUE)blockiseq != (VALUE)-1) ? 1 :
    0));
    {
    rb_block_t *blockptr = !(op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ?
    GET_BLOCK_PTR() : 0;
    int num = caller_setup_args(th, GET_CFP(), op_flag,
    diff --git a/node.c b/node.c
    index 65bc541…85574b4 100644
    — a/node.c
    +++ b/node.c
    @@ -621,7 +621,12 @@ dump_node(VALUE buf, VALUE indent, int comment,
    NODE *node)
    ANN(“example: foo(x, &blk)”);
    F_NODE(nd_head, “other arguments”);
    LAST_NODE;

  • F_NODE(nd_body, “block argument”);
  • if ((VALUE)node->nd_body != (VALUE)-1) {

  •  F_NODE(nd_body, "block argument");
    
  • }

  • else {

  •  F_MSG(nd_body, "block argument", "-1 (anonymous)");
    
  • }
    break;

    case NODE_DEFN:
    

diff --git a/parse.y b/parse.y
index e085088…b0b946b 100644
— a/parse.y
+++ b/parse.y
@@ -2459,6 +2459,14 @@ block_arg : tAMPER arg_value
$$ = $2;
%*/
}

  • | tAMPER
  •    {
    
  •    /*%%%*/
    
  •  $$ = NEW_BLOCK_PASS(-1);
    
  •    /*%
    
  •  $$ = dispatch0(anonymous_block_arg);
    
  •    %*/
    
  •    }
    
    ;

opt_block_arg : ‘,’ block_arg
diff --git a/tool/instruction.rb b/tool/instruction.rb
index 4fd2127…4ce219f 100755
— a/tool/instruction.rb
+++ b/tool/instruction.rb
@@ -66,13 +66,12 @@ class RubyVM
ret = “int inc = 0;\n”

     @opes.each_with_index{|(t, v), i|
  •      if t == 'rb_num_t' && ((re = /\b#{v}\b/n) =~ @sp_inc ||
    
  •                             @defopes.any?{|t, val| re =~ val})
    
  •      if ((re = /\b#{v}\b/n) =~ @sp_inc || @defopes.any?{|t, val|
    

re =~ val})
ret << " int #{v} = FIX2INT(opes[#{i}]);\n"
end
}
@defopes.each_with_index{|((t, var), val), i|

  •      if t == 'rb_num_t' && val != '*' && /\b#{var}\b/ =~ @sp_inc
    
  •      if val != '*' && /\b#{var}\b/ =~ @sp_inc
           ret << "        #{t} #{var} = #{val};\n"
         end
       }
    

diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 985a2fb…f6418b7 100644
— a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -240,25 +240,31 @@ caller_setup_args(const rb_thread_t *th,
rb_control_frame_t *cfp, VALUE flag,

 if (block) {

if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {

  •  rb_proc_t *po;
    
  •  VALUE proc;
    
  •  proc = *(--cfp->sp);
    
  •  if (proc != Qnil) {
    
  • if (!rb_obj_is_proc(proc)) {
  •    VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", 
    

“to_proc”);

  •    if (NIL_P(b) || !rb_obj_is_proc(b)) {
    
  •  rb_raise(rb_eTypeError,
    
  •     "wrong argument type %s (expected Proc)",
    
  •     rb_obj_classname(proc));
    
  •  if ((VALUE)blockiseq != (VALUE)-1) {
    
  • rb_proc_t *po;
  • VALUE proc;
  • proc = *(–cfp->sp);
  • if (proc != Qnil) {
  •    if (!rb_obj_is_proc(proc)) {
    
  •  VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
    
  •  if (NIL_P(b) || !rb_obj_is_proc(b)) {
    
  •      rb_raise(rb_eTypeError,
    
  •        "wrong argument type %s (expected Proc)",
    
  •        rb_obj_classname(proc));
    
  •  }
    
  •  proc = b;
       }
    
  •    proc = b;
    
  •    GetProcPtr(proc, po);
    
  •    blockptr = &po->block;
    
  •    RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
    
  •    *block = blockptr;
    
    }
  • GetProcPtr(proc, po);
  • blockptr = &po->block;
  • RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc;
  • *block = blockptr;
  •  }
    
  •  else {
    
  • rb_control_frame_t *reg_cfp = cfp;
  • *block = GET_BLOCK_PTR();
    }
    }
    else if (blockiseq) {

e$B1sF#$G$9!#e(B

2010e$BG/e(B8e$B7ne(B26e$BF|e(B23:28 Yugui [email protected]:

e$B$7$+$7!“$”$^$j$K$bC;$9$.$k!#e(B&e$B#1J8;z$O8+Mn$H$7$=$&$G$9!#e(B

e$B$$$d$"!"9M$($9$.$G$7$g$&!#e(B
func(foo + bar, baz * qux, i) e$B$Ge(B i
e$B$r8+Mn$H$9$H$+$J$$$G$9$h!#e(B
& e$B$Oe(B i e$B$h$jL\N)$D$7!#e(B

foo(a, b, &yield)
e$B$J$s$F$N$OBLL$G$7$g$&$+!#e(Byield e$B$He(B block.calle$B$NN;w@-$+$i$NN?d$G$9!#e(B

e$B$=$l$O8_49@-$KLdBj$,$"$j$^$9!#e(B