祝! 軽量Rubyが公開

チョット目を離している隙に、軽量Ruby(mruby)が公開された様ですね。
 Rails Hub情報局: ついに軽量Rubyの「mruby」のソースコードが公開!
 軽量Rubyことmrubyのソースコードが公開されました - miyohide's blog


早速、GitHubからスナップショットを拾って来てビルドしてみました。
ビルド環境はCygwinです。make一発でインタプリタ(mruby)、コンパイラ(mrbc)、組込みサンプル(mrubysample)ができるようです。

$ ls -l bin
合計 5952
 -rwxr-xr-x 1 shoz なし 1994838 4月  23 07:22 mrbc.exe
 -rwxr-xr-x 1 shoz なし 2025635 4月  23 07:22 mruby.exe
 -rwxr-xr-x 1 shoz なし 2022095 4月  23 07:22 mrubysample.exe

コンパイラmrbcでは次のオプションが使えます。

ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
Usage: ./mrbc [switches] programfile
  switches:
  -c           check syntax only
  -o  place the output into 
  -v           print version number, then trun on verbose mode
  -B   binary  output in C language format
  -C     function  output in C language format
  --verbose    run at verbose mode
  --version    print the version
  --copyright  print the copyright

オプション-Cは、RubyのコードをC言語の関数にトランスレートするようです。できたC言語ソースコードをmrubyのライブラリと合わせてコンパイル/リンクすることで、ターゲットのアプリに組み込めるようにしているのでしょう。

puts "hello world!"

このRubyのコードから下のようなC言語ソースコードができます。mrb_open()で得たmrb_state構造体をhello()の引数に渡せば動くようです。

#include "mruby.h"
#include "irep.h"
#include "mruby/string.h"
#include "mruby/proc.h"

static mrb_code iseq_0[] = {
  0x01000006,
  0x0180003d,
  0x02000005,
  0x010000a0,
  0x0000004a,
};

void
hello(mrb_state *mrb)
{
  int n = mrb->irep_len;
  int idx = n;
  mrb_irep *irep;

  mrb_add_irep(mrb, idx+1);

  irep = mrb->irep[idx] = mrb_malloc(mrb, sizeof(mrb_irep));
  irep->idx = idx++;
  irep->flags = 0 | MRB_ISEQ_NOFREE;
  irep->nlocals = 2;
  irep->nregs = 4;
  irep->ilen = 5;
  irep->iseq = iseq_0;
  irep->slen = 1;
  irep->syms = mrb_malloc(mrb, sizeof(mrb_sym)*1);
  irep->syms[0] = mrb_intern(mrb, "puts");
  irep->plen = 1;
  irep->pool = mrb_malloc(mrb, sizeof(mrb_value)*1);
  irep->pool[0] = mrb_str_new(mrb, "hello world!", 12);

  mrb->irep_len = idx;

  extern mrb_value mrb_top_self(mrb_state *mrb);
  mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb));
}
int
main()
{
  mrb_state *mrb = mrb_open();
  hello(mrb);
  return 0;
}

オプション-Bを指定すると下の様なソースコードが得られます。Riteのバイトコードでしょうか? はっきりしたことは分かりません。

const char hello[] = {
0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x39,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x39,
0x30,0x30,0x30,0x30,0x4d,0x41,0x54,0x5a,0x20,0x20,0x20,0x20,0x30,0x30,0x30,0x39,
0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x83,0x00,0x01,0x00,0x00,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0xb3,0xd8,0x00,0x00,0x00,0x45,0x53,0x43,0x00,0x02,0x00,0x04,
0x00,0x02,0x6f,0x28,0x00,0x00,0x00,0x05,0x01,0x00,0x00,0x06,0x01,0x80,0x00,0x3d,
0x02,0x00,0x00,0x05,0x01,0x00,0x00,0xa0,0x00,0x00,0x00,0x4a,0xf5,0x07,0x00,0x00,
0x00,0x01,0x0f,0x00,0x0c,0x68,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,0x6c,0x64,
0x21,0x2b,0xac,0x00,0x00,0x00,0x01,0x00,0x04,0x70,0x75,0x74,0x73,0x24,0x89,0x00,
0x00,0x00,0x00,
};

さて、仮想マシンソースコードはsrc/vm.cにあります。中身をちょこっと見たところ、バイトコードの分岐はswich/case文による実装とDirect Threaded codeによる実装の2種類が用意されています‥‥"goto *optable[ほにゃら];"の書き方は gcc拡張機能でしたっけ? デフォールトではDirect Threaded code版になっているようです。