From: Nobuyoshi Nakada Date: 2007-09-26T05:04:20+09:00 Subject: [ruby-dev:31864] Re: meta programming might dump core なかだです。 At Tue, 25 Sep 2007 02:49:24 +0900, Yusuke ENDOH wrote in [ruby-dev:31850]: > 約 100 万エントリのハッシュリテラル: key=>valueの値を先にVMスタックにすべて積んでからnewhashを実行す るので、そこでオーバーフローしています。一組ずつ追加していくとい うのは、速度的な問題からささださんが気に入らないようで。 思い付くのはこのあたり。 (a) 速度は少々あきらめて、一組ずつ追加 (b) VMスタックを確保できるか確認する命令を追加 > 約 100 万変数の多重代入: これもexpandarrayで100万個に展開するときにオーバーフローしていま す。expandarrayはサイズがわかっているので、チェックを入れればい いのではないかと。 > 約 100 万引数のメソッド呼び出し: これも引数を一度スタックに全部積むので以下同文。 > false が || で 25000 個連なった式: > > $ time ./ruby -ve 'eval("false||" * 25000 + "true")' > ruby 1.9.0 (2007-09-24 patchlevel 0) [i686-linux] > セグメンテーション違反です こっちはbytecodeにコンパイルするところでマシンスタックオーバーフ ローしています。 この例については回避するのは簡単ですが、もっと複雑にネストしてい たりするとお手上げでしょう。 Index: compile.c =================================================================== --- compile.c (revision 13509) +++ compile.c (working copy) @@ -1795,9 +1795,14 @@ compile_branch_condition(rb_iseq_t *iseq LABEL *then_label, LABEL *else_label) { + again: switch (nd_type(cond)) { case NODE_NOT: - compile_branch_condition(iseq, ret, cond->nd_body, else_label, - then_label); - break; + { + LABEL *tmp = else_label; + else_label = then_label; + then_label = tmp; + cond = cond->nd_body; + goto again; + } case NODE_AND: @@ -1807,7 +1812,6 @@ compile_branch_condition(rb_iseq_t *iseq else_label); ADD_LABEL(ret, label); - compile_branch_condition(iseq, ret, cond->nd_2nd, then_label, - else_label); - break; + cond = cond->nd_2nd; + goto again; } case NODE_OR: @@ -1817,7 +1821,6 @@ compile_branch_condition(rb_iseq_t *iseq label); ADD_LABEL(ret, label); - compile_branch_condition(iseq, ret, cond->nd_2nd, then_label, - else_label); - break; + cond = cond->nd_2nd; + goto again; } case NODE_LIT: /* NODE_LIT is always not true */ @@ -3187,18 +3190,20 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ case NODE_OR:{ LABEL *end_label = NEW_LABEL(nd_line(node)); - COMPILE(ret, "nd_1st", node->nd_1st); - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - if (type == NODE_AND) { - ADD_INSNL(ret, nd_line(node), branchunless, end_label); - } - else { - ADD_INSNL(ret, nd_line(node), branchif, end_label); - } - if (!poped) { - ADD_INSN(ret, nd_line(node), pop); - } - COMPILE_(ret, "nd_2nd", node->nd_2nd, poped); + do { + COMPILE(ret, "nd_1st", node->nd_1st); + if (!poped) { + ADD_INSN(ret, nd_line(node), dup); + } + if (type == NODE_AND) { + ADD_INSNL(ret, nd_line(node), branchunless, end_label); + } + else { + ADD_INSNL(ret, nd_line(node), branchif, end_label); + } + if (!poped) { + ADD_INSN(ret, nd_line(node), pop); + } + } while ((node = node->nd_2nd) != 0 && nd_type(node) == type); + COMPILE_(ret, "nd_2nd", node, poped); ADD_LABEL(ret, end_label); break; -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦