ひとり勉強会

ひとり楽しく勉強会

ruby_init @ eval.c

初期化関数、ruby_init のメインな部分を抜き出してみました。

void
ruby_init()
{
  ... 略 ...
    Init_yarv();
    Init_stack((void *)&state);
    Init_heap();

    PUSH_TAG(PROT_NONE);
    if ((state = EXEC_TAG()) == 0) {
	rb_call_inits();
	ruby_prog_init();
	ALLOW_INTS;
    }
    POP_TAG_INIT();
  ... 略 ...
}

Init_yarvYARVが出てきました!

でもその前に、すぐあとのif文の条件が、はじめてRubyのソースを見る目には謎です。

    PUSH_TAG(PROT_NONE);
    if ((state = EXEC_TAG()) == 0) {
      ...
    }
    POP_TAG_INIT();

うーん?EXEC_TAGの定義を見てみよう。

#define TH_EXEC_TAG() \
  (FLUSH_REGISTER_WINDOWS, ruby_setjmp(_th->tag->buf))

#define EXEC_TAG() \
  TH_EXEC_TAG()

ruby_setjmpはsetjmpか_setjmpの#defineでした。ということで、ここではsetjmpが呼ばれているみたいです。setjmpは、最初は0を返して、中でlongjmpが呼ばれると0以外の値で戻ってくるはずです。

    if ((state = EXEC_TAG()) == 0) { // ※
      // 最初はEXEC_TAG==setjmpが0を返すので、ここに来る
      ... 
        // この辺りでエラーが起きたときは中でlongjmpが呼ばれる
        // すると※にジャンプして EXEC_TAG が 0 以外を返すので
      ...
    }
    // ここに処理がうつることになる

これは、begin〜rescue みたいな例外処理を、C言語でやってるってことでしょう。例外状態まで気にすると大変そうなので、ひとまずここの if (...) は見なかったことにして先に進みます。エラーなんて起きません!

(※ Ruby Hacking Guideをちょっと見てみたところ、この ***_TAG でいろいろジャンプする「ジャンプタグ」という仕組みはRuby評価期ではたっぷりと使われているそうです。YARVでどうなっているのかはまだわかりません。使っていそうだったら、その時にまた戻ってきて調べようと思います。)

さて、ruby_initが呼び出す初期化ルーチンのうち、YARVに直接関係ありそうな部分は二つしかありません。最初に呼ばれているInit_yarvと、rb_call_initsの中で呼ばれているInit_yarvcoreです。

  • Init_yarv
  • rb_call_inits
    • ...
    • Init_yarvcore
    • ...

他はふつうのRubyの組み込みオブジェクトやモジュールの初期化っぽかったので、この勉強会ではどんどん飛ばしてっちゃいます。