- 追加された行はこの色です。
- 削除された行はこの色です。
#contents
*はじめに [#w8061f24]
ここでは[[YARVコードへのコンパイル>Ruby1.9/YARVコードへのコンパイルを読む]]で生成したYARVコードを実行する処理を読解したいと思います。
*rb_iseq_eval(vm.c) [#sbe548a9]
YARVコード実行のエントリーポイントとなるのはrb_iseq_eval関数ですがこの関数はrb_vm_set_stack_top関数を呼んだ上でvm_eval_body関数を呼んでいるだけです。
*vm_set_stack_top(vm.c) [#fe5d2de5]
vm_set_stack_topではまずrb_vm_set_finish_env関数を呼んでフレームを生成しています。どうやらこのフレームはfinish命令を実行してYARVを終了するためのものなようです。
次にvm_push_frame関数を呼んで実行するYARVコードの情報をフレームに積んでいます。vm_push_frame関数は初期化のときもちらっと見ましたが再掲します。
vm_push_frame(th, iseq, FRAME_MAGIC_TOP,
th->top_self, 0, iseq->iseq_encoded,
th->cfp->sp, 0, iseq->local_size);
vm_push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE type,
VALUE self, VALUE specval, VALUE *pc,
VALUE *sp, VALUE *lfp, int local_size)
{
...
/* nil initialize */
for (i=0; i < local_size; i++) {
*sp = Qnil;
sp++;
}
/* set special val */
*sp = GC_GUARDED_PTR(specval);
dfp = sp;
if (lfp == 0) {
lfp = sp;
}
cfp = th->cfp = th->cfp - 1;
cfp->pc = pc;
cfp->sp = sp + 1;
cfp->bp = sp + 1;
cfp->iseq = iseq;
cfp->flag = type;
cfp->self = self;
cfp->lfp = lfp;
cfp->dfp = dfp;
cfp->proc = 0;
例のmontecarlo.rbのiseqをフレームを積んだ後のスタックは以下のような感じになります。
|Qnil
|GC_GUARDED_PTR(0)
|Qnil
|GC_GUARDED_PTR(GC_GUARDED_PTR(0))
|Qnil # for n
|Qnil # for pi
|Qnil # for svar
dfp,lfp→|GC_GUARDED_PTR(0)
sp,bp→|
|
...
|
cfp→|今積んだフレーム情報
|rb_vm_set_finish_env関数で積んだフレーム情報
|th_init2関数で積んだフレーム情報
*vm_eval_body(vm.c) [#p238920a]
この関数はvm_eval関数を実行します。例外やbreakなどが起こるとこの関数に戻ってきて適切な再開アドレスを計算し、再びvm_eval関数を呼び出しています。
*vm_eval(vm_evalbody.c) [#d039a4cf]
この関数がYARV命令実行の肝です。いい感じに難解なコードになっています。YARV命令はコンパイルオプションにより以下のいずれかの形式で実行されます。
:OPT_CALL_THREADED_CODE|関数呼び出し
:OPT_DIRECT_THREADED_CODE|goto
:指定なし|switch文
詳しいからくりはvm.hを眺めてください。
*vm.inc [#f5f2fa78]
各命令の処理ルーチンはどこに書かれているかですがvm.incに書かれています。
*insns.def [#ac978c10]
各命令の動きが知りたい場合はinsns.defを見ると書いてあります。見るとわかりますがinsns.defに書かれているのはCではありません。tool/insns2vm.rbを実行することで各種incファイルが生成されるようです。各命令は以下のフォーマットになっているようです。
DEFINE_INSN
命令名
(引数...)
(スタックから拾う値)
(スタックに積む値)
{
Cのソース
}
*実行してみる [#j083507b]
それでは[[YARVコードへのコンパイル>Ruby1.9/YARVコードへのコンパイルを読む]]でコンパイルしたコードを実行してみます。
**まだ実行してみてません [#m8002228]
とりあえず気になる命令を挙げておきます。
**send [#sb58cb02]
**getinlinecache [#kc7daca9]
*おわりに [#xc80c0b6]