LoginSignup
5
2

More than 5 years have passed since last update.

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

Posted at

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

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

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

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

mainオブジェクト · Issue #8 · ie-developers/ie-questions

MRI

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);
}

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

したときの動作もこれをみれば一目瞭然ですね。

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

Rubinius

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

  /* 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/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

// CoreLibraryのinitializeの中
mainObject = new RubyBasicObject(objectClass);

たどると
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

(略)

Truffleじゃないほう

    private void initRoot() {
        // Object is ready, create top self
        topSelf = TopSelfFactory.createTopSelf(this);

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

(略)

MRuby

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

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);
}

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

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

まとめ

Ruby実装いっぱいあって面白い

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2