Rubyのtop self、あるいはmainオブジェクトについて

Rubyの初期化について昔調べたので書きます。

## Rubyのtop self、あるいはmainオブジェクトについて

琉球大学の学生([@_attonさん](https://twitter.com/_atton))が立ち上げたGitHubのOrganization、ie-developersに以下の質問が立っていた。

個人的にも気になっていたので色々な実装を読んでいた。

[mainオブジェクト · Issue #8 · ie-developers/ie-questions](https://github.com/ie-developers/ie-questions/issues/8)

## MRI

``` c
void
Init_top_self(void)
{
    rb_vm_t *vm = GET_VM();

    vm->top_self = rb_obj_alloc(rb_cObject);
    rb_define_singleton_method(rb_vm_top_self(), "to_s", main_to_s, 0);
    rb_define_alias(rb_singleton_class(rb_vm_top_self()), "inspect", "to_s");

    /* initialize mark object array, hash */
    vm->mark_object_ary = rb_ary_tmp_new(1);
}
```

https://github.com/ruby/ruby/blob/v2_1_5/vm.c#L2836,L2838

CRubyでは`Init_`のプレフィックスがついているものは初期化時によばれる。
Ruby界でのクラスはCではだいたい`rb_c`のプレフィックスがついている。
RubyのメソッドはCレベルでは`rb_<ここにクラス名>_<メソッド名>`みたいになってることが多い。
トップレベルで
``` ruby
puts self
```
したときの動作もこれをみれば一目瞭然ですね。

起動まではたぶんusaさんのブログでめっちゃ書かれてる

http://www.garbagecollect.jp/~usa/d/201411c.html#id20141130_P1

## Rubinius

かいつまむとこのあたり。コメントから溢れ出る天地創造感。

``` c
  /* Creates the rubinius object universe from scratch. */
  void VM::bootstrap_ontology(STATE) {
    /* (中略) */
    Object* main = new_object<Object>(G(object));
    GO(main).set(main);
    G(object)->set_const(state, "MAIN", main); // HACK test hooking up MAIN
    /* (後略) */
  }
```
https://github.com/rubinius/rubinius/blob/v2.4.0/vm/ontology.cpp#L404,L406

たどるとこんな感じ。環境があって、状態があって、そこに世界がハマる。
https://github.com/rubinius/rubinius/blob/v2.4.0/vm/vm.cpp#L134
https://github.com/rubinius/rubinius/blob/v2.4.0/vm/environment.cpp#L460
https://github.com/rubinius/rubinius/blob/v2.4.0/vm/environment.cpp#L800
https://github.com/rubinius/rubinius/blob/v2.4.0/vm/drivers/cli.cpp#L55

mainオブジェクト自体の定義はこのあたり。
世界を作る際に定数としてMAINが作られていてそこに足される感じですね。
https://github.com/rubinius/rubinius/blob/v2.4.0/kernel/common/main.rb

## JRuby
実装がいくつかある。

### Truffle
Truffleについては以下
https://github.com/jruby/jruby/wiki/Truffle

``` java
// CoreLibraryのinitializeの中
mainObject = new RubyBasicObject(objectClass);
```
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java#L268

たどると
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/truffle/runtime/RubyContext.java#L94
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/truffle/TruffleBridgeImpl.java#L48
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Ruby.java#L899,L900
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Ruby.java#L831

(略)

https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Main.java

### Truffleじゃないほう
``` java
    private void initRoot() {
        // Object is ready, create top self
        topSelf = TopSelfFactory.createTopSelf(this);
```
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Ruby.java#L1365

`Ruby. newInstance`でインスタンスができ、そのときinit、initRootとよばれtopSelfがうまれる。
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Ruby.java#L1199
https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Ruby.java#L315

(略)

https://github.com/jruby/jruby/blob/f66d751a35e8dda462489a6d402114b2e42d1c40/core/src/main/java/org/jruby/Main.java

## MRuby
MRubyだけめっちゃ新鮮で、topselfあるかないかチェックしてないときだけ初期化してる。

``` c
MRB_API mrb_value
mrb_top_self(mrb_state *mrb)
{
  if (!mrb->top_self) {
    mrb->top_self = (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mrb->object_class);
    mrb_define_singleton_method(mrb, mrb->top_self, "inspect", inspect_main, MRB_ARGS_NONE());
    mrb_define_singleton_method(mrb, mrb->top_self, "to_s", inspect_main, MRB_ARGS_NONE());
  }
  return mrb_obj_value(mrb->top_self);
}
```
https://github.com/mruby/mruby/blob/master/src/state.c#L272,L281

たぶん`mrb_state`は使い回されるんだろうな。で毎回初期化処理は通るんだけどすでに初期化されていればなにもしない、みたいな。

https://github.com/mruby/mruby/blob/09c6ca936c965d63752276aa3203b3e7534874ae/src/vm.c#L2379,L2402

このコミットでなんかスタックの位置保存するみたいなやつはいってて、stack_keepの分だけさすスタック伸ばしてから実行してるっぽい(くわしくはしらない)
https://github.com/mruby/mruby/commit/6bf1ee78c8cdc5c1b0265694c404ada0ec32cb28

## まとめ
Ruby実装いっぱいあって面白い