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 できるかいな。