shiro さんからフォロー頂いた
曰く
VMEvalとかVMApplyの戻り値はevalやapplyの結果ではないことに注意してください。
これらの手続きはVMのスタックに引数を積み、*次にVMが制御が戻った時点で*
「VAL0に格納された手続きを、スタックに積まれた値を引数として呼び出す」という
コードが実行されるように手筈を整えます。そして呼びだい手続きを戻り値として
返します。VMEvalなどを呼んでるC手続きはもともとVMから呼び出されてるので、VMEvalの
戻り値であるところの手続きオブジェクトは巡り巡ってVMに戻り、VAL0に格納されます。
そこからVMが実行を再開し、その手続きオブジェクトが呼び出されるという寸法です。C Continuationはその手続きオブジェクトがRETインストラクションを実行する
タイミングで起動され、その手続きオブジェクトの結果をresult引数で受けとります。
_repl.c あたり_というエントリのコメントより引用
との事。ふむふむ。
なかなか興味深い
_VMEvalなどを呼んでるC手続きはもともとVMから呼び出されてる_という件。VM から呼び出されてる手続きのエントリポイントは repl_main 手続きなのかな。あ、違うな。Scm_Repl 手続き (というか Scm_ApplyRec 手続きから) で VM 突入なのか。
む、てコトは C から無理矢理呼びだしちゃうようなケイスって
- SCM_DEFINE_SUBR マクロで wrap して
- Scm_ApplyRec 手続きにお願い
すれば良いのか? って思ったらそれはアマい事に気づく (早
# あら? でも val0 が戻ってるなぁ
閑話休題
話を元に戻す。user_eval_inner 手続きのコメントが以下。
/* Border gate. All the C->Scheme calls should go through here. * * The current C stack information is saved in cstack. The * current VM stack information is saved (as a continuation * frame pointer) in cstack.cont. */
うーん、と言いつつ vmcall.c を見る。どっかで見たコトありますな。と、言いつつ repl_STUB を呼びだしてるのはどこだっけ、と言いつつ見てたらあった。
VAL0 = SCM_SUBR(VAL0)->func(ARGP, argc, SCM_SUBR(VAL0)->data); /* the subr may have substituted pc, so we need to check if we can pop the continuation immediately. */ if (TAIL_POS()) RETURN_OP(); NEXT;
これこれ。引数もカンペキにマッチ。てコトはエントリポイントは Scm_Repl 手続きで呼び出されてる Scm_ApplyRec って言えば良いのだろうか。
とりあえずエントリポイント調べるのが本題ではないのでスルー。
現時点での理解
- Scm_ApplyRec 手続きから呼び出される apply_rec で APPLY - RET なインストラクションと C な SUBR 手続きがナニ
- C な SUBR の中では repl_loop_cc が継続 push されて reploop を呼び出す with_error_handler が起動
- repl_loop_cc って #t が戻ってこないと SCM_FALSE 戻すんスけど、ってどきどきしたんですが、そっから先で呼ばれる repl_read_cc で継続 push されてる repl_eval_cc で repl_main が呼ばれてます
ちょっとだけ VM 云々の理解ができた気がします。非常に解りやすいコメントをありがとうございます。> shiro さん
ReadingGauche 方面に output できるかいな。