組み込みC言語プログラマのためのmruby入門(後編) ―― mrubyの組み込み方とJavaとの違い
●mrbcで得られたバイトコードをアプリケーションに組み込む
mrubyは,実行環境をmrb_stateという構造体に閉じ込めています.単なる構造体ですので,一つのアプリケーションで,mrb_stateを二つ以上持つことができます.mrb_stateが二つ以上あった場合,それぞれのmrb_stateは互いに独立な実行環境と見なされます.
mrbcで出力したバイトコードがRite形式とC言語形式のいずれであっても,mrb_stateを軸としてバイトコードを実行するというのは同じです.mrb_stateのライフ・サイクルをリスト5に示します.
リスト5 mrb_stateのライフ・サイクル
{
/* バイトコードの読み取り */
}
mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb)); /* 仮想マシンの実行 */
リスト5で「バイトコードの読み取り」とした部分は,以下の(1)~(3)のいずれかのようになります.
(1)Rite形式のバイトコードを読み取る場合
Rite形式の読み取りについて,現時点のAPIではファイルから読み取ることが想定されています.読み取りの例をリスト6に示します.
リスト6 Rite形式の読み取り
int n = mrb_load_irep_file(mrb, fp);
n(mrb_load_irep関数からの戻り値)が正数のとき,mrb_run関数を呼び出せます.なお,小規模の組み込みシステムの場合は,フラッシュ・メモリ領域などアドレス空間上にあるデータから読み取りたい例があるはずなのですが,本稿執筆時点のmrubyでは,サポートするAPIが存在しないようです.
(2)C言語配列形式のバイトコードを読み取る場合
mrbcで-Bオプションを付けて出力した場合の,C言語配列形式のバイトコードの読み取りは,API一つで行えます.リスト7に例を示します.
リスト7 C言語配列形式の読み取り
n(mrb_read_irep関数からの戻り値)が正数のとき,mrb_run関数を実行できます.前述したように,アドレス空間上にあるデータからの読み取りはRite形式では難しいのですが,mrb_read_irep関数を応用することで実現できます.
(3)C言語関数形式の読み取り
mrbcで-Cオプションを付けて出力した場合の,C言語関数形式のバイトコードの場合は,既に出力の中にmrb_run関数が含まれています.そのため,mrb_open関数で得られたmrb_state構造体(へのポインタ)を引き数として,関数を呼び出すことになります.
●mrubyバイトコードの代表的な利用例はmruby
mrubyのバイトコードは,新規に開発された独自のものです.初物にバグの心配があるのは,どのソフトウェアでも同じです.特にテストの組み合わせが爆発しがちなバイトコード・インタプリタともなれば,心配はひとしおでしょう.しかし,mrubyでは,バイトコードに関してある程度の品質を期待することができます.
なぜならば,mrubyの一部に,Rubyで記述されバイトコード・コンパイルされたものが組み込まれているからです.ブート・ストラップの問題でmrbc動作に必要なコードはC言語で記述されていますし,速度やメモリの効率に大きな影響があるものも同様ですが,それ以外のものは,積極的にRubyでの記述が行われています.これらのRubyコードは,ソース・リポジトリのmrblib/配下に存在しています.
また,mrubyコア自身のテスト・スイートもRubyで記述されており,バイトコード・コンパイラを介してリンク,実行されます.テスト・スイートは,ソース・リポジトリのmrbtest/配下に存在しています.
このように,mrubyはそれ自身がバイトコードを積極的に活用しているため,ある程度の品質を期待することができます.しかし率直に言って,本稿執筆時点でのテスト・スイートの網羅度はさほど高くありません.網羅度を高めるようなテスト・ケースへの貢献は歓迎されるはずです.