あおきです。

  In mail "[ruby-dev:18139] Re: autoload patch for ruby-1.7"
    "Yoshinori K. Okuji" <okuji / enbug.org> wrote:

> > なり遅くなるんです。Bison が使えるなら ruby.c の load_file() に
> > ある rb_gc() を消してみてください。一気にロードしてもかなり速く
> > なると思います。(ただし Bison 以外でこれをやると最悪 SEGV します)
> 
> なるほど。試してみると、おっしゃる通り、相当速くなりますね! よく事情が
> 分かってないんですが、Bisonでコンパイルしたparse.cを配布する、あるいは、
> Bisonでコンパイルすることを前提にするのは良くないんでしょうか?Bisonは
> 1.24から出力には何の制限もしないという方針に変更したので、ライセンス的
> には問題ないように思えるのですけど。

ライセンス的には問題ないと思います。ただ、なにかのはずみで
yacc が動いてしまうと酷いめにあう、ということからサポート
コードは外せないのでしょう。

ちなみにGCしている理由を簡単に説明すると、

  * RubyのGCはマシンスタックをスキャンしてRubyオブジェクトを探す
    (ので、マシンスタック上にあるオブジェクトは安全。)

  * しかしヒープはまずい

  * yaccのセマンティックスタックには構文木のノード
    (Rubyオブジェクト NODE) が入ることがある

  * bisonはセマンティックスタックをallocaでスタックに取るが
    他のyaccはそうとも限らない → ノードが回収される危険がある

  * そこでコンパイル中はノードは回収せず、
    かわりにコンパイルのあとに明示的にGCする

ということです。

そういえば前にぼくがうだうだ言ったときに中田さんがパッチを
作ってくれたな…… [ruby-dev:16215] か。でもあのパッチの
方向だと まつもとさんが躊躇しそうな気がするので、思いきり
単純なパッチを作ってみました。
-------------------------------------------------------------------
青木峰郎

Index: gc.c =================================================================== RCS file: /home/aamine/cvs/ruby/ruby/gc.c,v retrieving revision 1.99 diff -u -p -r1.99 gc.c --- gc.c 29 Aug 2002 09:08:16 -0000 1.99 +++ gc.c 2 Sep 2002 06:32:18 -0000 @@ -863,7 +863,7 @@ gc_sweep() int freed = 0; int i, used = heaps_used; - if (ruby_in_compile) { + if (ruby_in_compile && !rb_parser_use_alloca()) { /* should not reclaim nodes during compilation */ for (i = 0; i < used; i++) { p = heaps[i]; pend = p + heaps_limits[i]; Index: intern.h =================================================================== RCS file: /home/aamine/cvs/ruby/ruby/intern.h,v retrieving revision 1.92 diff -u -p -r1.92 intern.h --- intern.h 19 Aug 2002 05:56:05 -0000 1.92 +++ intern.h 2 Sep 2002 06:27:42 -0000 @@ -291,6 +291,7 @@ int yyparse _((void)); ID rb_id_attrset _((ID)); void rb_parser_append_print _((void)); void rb_parser_while_loop _((int, int)); +int rb_parser_use_alloca _((void)); int rb_is_const_id _((ID)); int rb_is_instance_id _((ID)); int rb_is_class_id _((ID)); Index: parse.y =================================================================== RCS file: /home/aamine/cvs/ruby/ruby/parse.y,v retrieving revision 1.206 diff -u -p -r1.206 parse.y --- parse.y 21 Aug 2002 15:47:54 -0000 1.206 +++ parse.y 2 Sep 2002 06:23:02 -0000 @@ -2284,6 +2284,16 @@ static char *lex_pbeg; static char *lex_p; static char *lex_pend; +int +rb_parser_use_alloca() +{ +#if defined(YYBISON) && !defined(C_ALLOCA) + return Qtrue; +#else + return Qfalse; +#endif +} + static int yyerror(msg) char *msg; Index: ruby.c =================================================================== RCS file: /home/aamine/cvs/ruby/ruby/ruby.c,v retrieving revision 1.65 diff -u -p -r1.65 ruby.c --- ruby.c 27 Aug 2002 11:00:24 -0000 1.65 +++ ruby.c 2 Sep 2002 06:26:40 -0000 @@ -856,7 +856,10 @@ load_file(fname, script) else if (f != rb_stdin) { rb_io_close(f); } - rb_gc(); + + if (!rb_parser_use_alloca()) { + rb_gc(); + } } void