[Bug #982] stack level too deep for long Array initialization

Bug #982: stack level too deep for long Array initialization
http://redmine.ruby-lang.org/issues/show/982

e$B5/I<<Te(B: Martin De$(D+de(Brst
e$B%9%F!<%?%9e(B: Open, e$BM%@hEYe(B: Normal
e$BC4Ev<Te(B: Koichi Sasada, e$B%+%F%4%je(B: YARV, Target version: 1.9.2

e$B<!$N%9%/%j%W%H$,e(B stack level too deep (SystemStackError)
e$B$G=*$o$j$^$9!#e(B

ruby -e ‘puts “A=[”; 0.upto(1000000) { puts " [22, 55]," }; puts “]”’ |
ruby

e$B$3$l$Oe(B Bug #943 [ruby-dev:37646]
e$B$N%3%T!<$G!"D94|E*$K$I$&$9$k$N$+e(B
e$B$r9M$($k$H$a$N%P%0$G$9!#e(B

ruby -e ‘puts “A=[]”; 0.upto(1000000) { puts “A<<[22, 55]” }’ | ruby

e$B$G0U?^$N$b$N$,$G$-$k$,!"$I$&$7$F$b%G!<%?$N=i4|2=$r@k8@E*$G$G$-$J$/!“e(B
e$B<jB3E*$K$7$J$$$H$$$1$J$$$N$O$h$/$J$$$H;W$C$F$$$^$9!#%f!<%6$+$i8+$k$He(B
e$B%a%>%I$N?<$$8F$S=P$7$J$I$,%9%?%C%/%*!<%P%U%m!<$K$J$k$N$OJ,$+$k$O$:e(B
e$B$G$9$,!”%G!<%?$N=i4|2=$@$1$G$=$&$$$&LdBj$K$J$k$N$O%S%C%/%j$9$ke(B
e$B$G$7$g$&!#e(B

e$B:{ED$5$s$K$h$j$^$9$H!"e(B

e$B!!>e5-Nc$N$h$&$K!$6u$NG[Ns$r:n$C$F!$$=$l$Ke(B push e$B$9$k$h$&$KJQ99$9$k$3$H$be(B
e$B2DG=$G$9$,!$$=$l$r=PMh$k$h$&$K$7$?$[$&$,$$$$$G$9$+$M$'!%$9$k$K$7$F$b!$e(B
1.9.2 e$B$GL?NaDI2C$C$F$3$H$K$J$k$H;W$$$^$9$,!%$=$&JQ99$7$?$i!$$A$g$C$HB.EYe(B
e$B$,CY$/$J$k$C$F$/$i$$$+$J$!!%e(B

e$B$b$&0l$D$N$d$jJ}$Oe(B stack level too deep
e$B$K$J$C$?$H$-$K!“%9%?%C%/$K$”$ke(B
e$BG[Ns$NMWAG$r0l5$$KG[Ns$KDI2C$7!“<!$NMWAG$+$i$^$@%9%?%C%/$K:$;$k$3$He(B
e$B$,9M$($i$l$k!#$G$b!”$3$&$$$&$N$r<BAu$9$k$N$O$I$N$0$i$$Fq$7$$$G$7$g$&$+!#e(B

e$B$h$m$7$/$*4j$$$7$^$9!#e(B Martin.

e$B%A%1%C%He(B #982 e$B$,99?7$5$l$^$7$?!#e(B (by Yusuke E.)

Target version 1.9.2e$B$+$ie(B1.9.xe$B$KJQ99e(B
ruby -v -e$B$K%;%C%He(B

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

e$B$5$5$@$5$s$,!Ve(B1.9.2
e$B$K$OITMW$G$O$J$$$G$7$g$&$+!W$H$N8+2r$r=P$7$?$N$G!"e(B
target e$B$re(B 1.9.x e$B$H$7$^$9!#EvLL$Oe(B Array#<<
e$B$J$I$r;H$C$F$/$@$5$$!#e(B

e$B2?$H$+$7$FM_$7$$$H8@$&@<$,B??t$"$l$P!"Aa$a$KD>$5$l$k$+$b$7$l$^$;$s!#e(B


Yusuke E. [email protected]

http://redmine.ruby-lang.org/issues/show/982

e$B%A%1%C%He(B #982 e$B$,99?7$5$l$^$7$?!#e(B (by Yusuke E.)

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

e$B<!$N%9%/%j%W%H$,e(B stack level too deep (SystemStackError) e$B$G=*$o$j$^$9!#e(B

ruby -e ‘puts “A=[”; 0.upto(1000000) { puts " [22, 55]," }; puts “]”’ | ruby

e$B$I$&$$$&$H$-$K$3$l$,I,MW$K$J$C$?$N$+6=L#$,$"$j$^$9!#e(B

e$B$=$l$O$=$l$H$7$F!"%Q%C%A$r=q$$$F$_$^$7$?!#e(B

  • concatarray e$BL?Na$rGQ;_$7$F!"0z?t$r$H$ke(B concatarrays
    e$BL?Na$rF3F~$7$?e(B
  • checkints e$BL?Na$rF3F~$7$?e(B
  • e$B5pBg$JG[Ns%j%F%i%k$Oe(B 1000 e$B8D$4$H$Ke(B newarray
    e$B$7$F:G8e$Ke(B concatarrays e$B$9$ke(B

e$B$H$j$"$($:G[Ns$@$1$NBP=h$J$N$G!"5pBg$J%O%C%7%e%j%F%i%k$r=q$/$H$?$V$sMn$A$^$9!#e(B

Index: insns.def

— insns.def (revision 21356)
+++ insns.def (working copy)
@@ -40,6 +40,20 @@
/* none */
}

+/**

  • @c check interrupts
  • @e check interrupts
  • @j
  • */
    +DEFINE_INSN
    +checkints
    +()
    +()
    +()
    +{
  • RUBY_VM_CHECK_INTS();
    +}

//
/
deal with variables /
/
/
@@ -486,31 +500,27 @@

/**
@c put

  • @e concat two arrays
  • @j e$BFs$D$NG[Nse(B ary1, ary2 e$B$rO"7k$7%9%?%C%/$X%W%C%7%e$9$k!#e(B
  • @e put concatenate arrays
  • @j e$B%9%?%C%/%H%C%W$NG[Ns$re(B n
    e$B8DO"7k$7!$7k2L$r%9%?%C%/$K%W%C%7%e$9$k!#e(B
    */
    DEFINE_INSN
    -concatarray
    -()
    -(VALUE ary1, VALUE ary2st)
    -(VALUE ary)
    +concatarrays
    +(rb_num_t num)
    +(…)
    +(VALUE val) // inc += 1 - num;
    {
  • const VALUE ary2 = ary2st;
  • VALUE tmp1 = rb_check_convert_type(ary1, T_ARRAY, “Array”, “to_a”);
  • VALUE tmp2 = rb_check_convert_type(ary2, T_ARRAY, “Array”, “to_a”);
  • int i;
  • if (NIL_P(tmp1)) {
  • tmp1 = rb_ary_new3(1, ary1);
  • val = rb_ary_new();
  • for (i = num - 1; i >= 0; i–) {
  • const VALUE v = TOPN(i);
  • VALUE tmp = rb_check_convert_type(v, T_ARRAY, “Array”, “to_a”);
  • if (NIL_P(tmp)) {
  •  tmp = rb_ary_new3(1, v);
    
  • }
  • rb_ary_concat(val, tmp);
    }
  • if (NIL_P(tmp2)) {
  • tmp2 = rb_ary_new3(1, ary2);
  • }
  • if (tmp1 == ary1) {
  • tmp1 = rb_ary_dup(ary1);
  • }
  • ary = rb_ary_concat(tmp1, tmp2);
  • POPN(num);
    }

/**
Index: compile.c

— compile.c (revision 21356)
+++ compile.c (working copy)
@@ -2195,12 +2195,14 @@
return COMPILE_OK;
}

+#define ARRAY_LITERAL_SPLIT_THRESHOLD 1000
+
static int
-compile_array_(rb_iseq_t *iseq, LINK_ANCHOR ret, NODE node_root,

  •     VALUE opt_p, int poped)
    

+compile_array(rb_iseq_t *iseq, LINK_ANCHOR ret, NODE node_root, int
poped)
{
NODE *node = node_root;

  • int len = node->nd_alen, line = nd_line(node), i=0;
  • int len = node->nd_alen, line = nd_line(node), i=0, split = 0;

  • VALUE opt_p = Qtrue;
    DECL_ANCHOR(anchor);

    INIT_ANCHOR(anchor);
    @@ -2211,6 +2213,11 @@
    ruby_node_name(nd_type(node)));
    }

  •  if (i > 0 && i % ARRAY_LITERAL_SPLIT_THRESHOLD == 0 && !poped) {
    
  • ADD_INSN1(anchor, line, newarray,
    INT2FIX(ARRAY_LITERAL_SPLIT_THRESHOLD));

  • ADD_INSN(anchor, line, checkints);

  • split++;

  •  }
     i++;
     if (opt_p && nd_type(node->nd_head) != NODE_LIT) {
    

    opt_p = Qfalse;
    @@ -2243,17 +2250,36 @@
    }
    else {
    if (!poped) {

  •  ADD_INSN1(anchor, line, newarray, INT2FIX(len));
    
  •  if (len % ARRAY_LITERAL_SPLIT_THRESHOLD) {
    
  • ADD_INSN1(anchor, line, newarray, INT2FIX(len %
    ARRAY_LITERAL_SPLIT_THRESHOLD));
  • split++;
  •  }
    
  •  if (split >= 2) ADD_INSN1(anchor, line, concatarrays, 
    

INT2FIX(split));
}
APPEND_LIST(ret, anchor);
}
return len;
}

-static VALUE
-compile_array(rb_iseq_t *iseq, LINK_ANCHOR ret, NODE node_root, VALUE
opt_p)
+static long
+compile_list(rb_iseq_t *iseq, LINK_ANCHOR ret, NODE node_root)
{

  • return compile_array_(iseq, ret, node_root, opt_p, 0);
  • NODE *node = node_root;
  • int i = 0;
  • if (nd_type(node) != NODE_ZARRAY) {
  • while (node) {
  •  if (nd_type(node) != NODE_ARRAY) {
    
  • rb_bug(“compile_list: This node is not NODE_ARRAY, but %s”,
  •       ruby_node_name(nd_type(node)));
    
  •  }
    
  •  i++;
    
  •  COMPILE(ret, "list element", node->nd_head);
    
  •  node = node->nd_next;
    
  • }
  • }
  • return i;
    }

static VALUE
@@ -2841,8 +2867,7 @@
*flag |= VM_CALL_ARGS_SPLAT_BIT;

   if (next_is_array) {
  • argc = INT2FIX(compile_array(iseq, args, argn->nd_head, Qfalse) +
    1);
  • POP_ELEMENT(args);
  • argc = INT2FIX(compile_list(iseq, args, argn->nd_head) + 1);
    }
    else {
    argn = argn->nd_head;
    @@ -2851,8 +2876,7 @@
    break;
    }
    case NODE_ARRAY: {
  •  argc = INT2FIX(compile_array(iseq, args, argn, Qfalse));
    
  •  POP_ELEMENT(args);
    
  •  argc = INT2FIX(compile_list(iseq, args, argn));
     break;
    

    }
    default: {
    @@ -2862,10 +2886,7 @@
    }

    if (nsplat > 1) {

  • int i;
  • for (i=1; i<nsplat; i++) {
  •  ADD_INSN(args_splat, nd_line(args), concatarray);
    
  • }
  • ADD_INSN1(args_splat, nd_line(args), concatarrays, INT2FIX(nsplat));
    }

    if (!LIST_SIZE_ZERO(args_splat)) {
    @@ -3746,7 +3767,7 @@
    COMPILE(ret, "NODE_OP_ASGN1 args->head: ",
    node->nd_args->nd_head);
    if (flag & VM_CALL_ARGS_SPLAT_BIT) {
    ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));

  • ADD_INSN(ret, nd_line(node), concatarray);
  • ADD_INSN1(ret, nd_line(node), concatarrays, INT2FIX(2));
    ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
    argc, Qfalse, LONG2FIX(flag));
    }
    @@ -3769,7 +3790,7 @@
    ADD_SEND(ret, nd_line(node), ID2SYM(id), INT2FIX(1));
    if (flag & VM_CALL_ARGS_SPLAT_BIT) {
    ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
  • ADD_INSN(ret, nd_line(node), concatarray);
  • ADD_INSN1(ret, nd_line(node), concatarrays, INT2FIX(2));
    ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET),
    argc, Qfalse, LONG2FIX(flag));
    }
    @@ -4070,7 +4091,7 @@
    ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx));
    }
    ADD_INSN1(args, nd_line(node), newarray, INT2FIX(j));
  •  ADD_INSN (args, nd_line(node), concatarray);
    
  •  ADD_INSN1(args, nd_line(node), concatarrays, INT2FIX(2));
     /* argc is setteled at above */
       }
       else {
    

@@ -4098,7 +4119,7 @@
break;
}
case NODE_ARRAY:{

  • compile_array_(iseq, ret, node, Qtrue, poped);
  • compile_array(iseq, ret, node, poped);
    break;
    }
    case NODE_ZARRAY:{
    @@ -4127,8 +4148,7 @@
    INIT_ANCHOR(list);
    switch (type) {
    case NODE_ARRAY:{
  •  compile_array(iseq, list, node->nd_head, Qfalse);
    
  •  size = OPERAND_AT(POP_ELEMENT(list), 0);
    
  •  size = INT2FIX(compile_list(iseq, list, node->nd_head));
     ADD_SEQ(ret, list);
     break;
    
    }
    @@ -4426,14 +4446,14 @@
    case NODE_ARGSCAT:{
    COMPILE(ret, “argscat head”, node->nd_head);
    COMPILE(ret, “argscat body”, node->nd_body);
  • ADD_INSN(ret, nd_line(node), concatarray);
  • ADD_INSN1(ret, nd_line(node), concatarrays, INT2FIX(2));
    break;
    }
    case NODE_ARGSPUSH:{
    COMPILE(ret, “arsgpush head”, node->nd_head);
    COMPILE(ret, “argspush body”, node->nd_body);
    ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1));
  • ADD_INSN(ret, nd_line(node), concatarray);
  • ADD_INSN1(ret, nd_line(node), concatarrays, INT2FIX(2));
    break;
    }
    case NODE_SPLAT:{


Yusuke ENDOH [email protected]


http://redmine.ruby-lang.org/issues/show/982

チケット #982 が更新されました。 (by Martin Dürst)

どういうときにこれが必要になったのか興味があります。

具体的に言いますと、GB-18030 の変換テーブルのためです。