うーん

へろへろなので、と信じたいんですがよく分からん。
VMのスタック操作(未完) なるドキュメントをニラミつつナニ。
_通常の関数呼び出し_なマンガ見ながら色々検討した記憶があるような無いような。
とりあえず色々見てたんですが CALL なインストラクションは今の理解では微妙。きっかけが何かは忘れましたが、とりあえず PUSH_CONT マクロ。

/* Push a continuation frame.  next_pc is the PC from where execution
   will be resumed.  */
#define PUSH_CONT(next_pc)                              \
    do {                                                \
        ScmContFrame *newcont = (ScmContFrame*)SP;      \
        newcont->prev = CONT;                           \
        newcont->env = ENV;                             \
        newcont->argp = ARGP;                           \
        newcont->size = SP - ARGP;                      \
        newcont->pc = next_pc;                          \
        newcont->base = BASE;                           \
        CONT = newcont;                                 \
        SP += CONT_FRAME_SIZE;                          \
        ARGP = SP;                                      \
    } while (0)

これは正に_1. push cont_なソレですな。ええと、vm.c で M-x occur PUSH_CONT したら以下なナニが列挙 (ちなみに Gauche-0.8.11)。

TAIL_CALL_INSTRUCTION マクロ

以下。

/* used for the inlined instruction which is supposed to be called at
   tail position (e.g. SLOT-REF).  This checks whether we're at the tail
   position or not, and if not, push a cont frame to make the operation
   a tail call. */
#define TAIL_CALL_INSTRUCTION()                 \
    do {                                        \
        if (!TAIL_POS()) {                      \
            CHECK_STACK(CONT_FRAME_SIZE);       \
            PUSH_CONT(PC);                      \
            PC = PC_TO_RETURN;                  \
        }                                       \
    } while (0)

コメントは後で見るとして、このマクロをナニしてるのが以下のインストラクション。

  • APPLY
  • SLOT_REF
  • SLOT_SET
  • SLOT_REFC
  • SLOT_SETC

うーん。なんなんだ。SLOT_* は略として APPLY されて末尾呼び出しでなければ、

  • スタックに継続フレーム push するナニがあるかチェキ
  • 継続フレーム push
  • PC に RET をナニ

という事ッスか。末尾呼び出しでなければ apply する時には継続フレームが push される、ってとりあえず参考コンテンツに書いてある通り?
# 問題になってるのは次以降なんですが ...

PRE_CALL インストラクション

            CASE(SCM_VM_PRE_CALL) {
                ScmWord *next;
                CHECK_STACK_PARANOIA(CONT_FRAME_SIZE);
                FETCH_LOCATION(next);
                PUSH_CONT(next);
                INCR_PC;
                NEXT;
            }

むむ。PRE_CALL は CALL した直後にある命令のための継続の処理?

色々雑念が入ってワケワカんなくなり始めてるので機械的に。以下、簡単に PUSH_CONT マクロをナニしているインストラクションとか。

  • RECEIVE
  • IS_A
  • run_loop のいっちゃんケツ

いっちゃんケツのソレが微妙。

      process_queue:
        CHECK_STACK(CONT_FRAME_SIZE);
        PUSH_CONT(PC);
        process_queued_requests(vm);
        POP_CONT();
        NEXT;
    }
}
/* End of run_loop */

正に末端。しかもぱっと見ワケワカ。

PUSH_ENV_HDR ぽいナニを見つけた。

/* push environment header to finish the environment frame.
   env, sp, argp is updated. */
#define FINISH_ENV(info_, up_)                  \
    do {                                        \
        ScmEnvFrame *e__ = (ScmEnvFrame*)SP;    \
        e__->up = up_;                          \
        e__->info = info_;                      \
        e__->size = SP - ARGP;                  \
        SP += ENV_HDR_SIZE;                     \
        ARGP = SP;                              \
        ENV = e__;                              \
    } while (0)

あ、引数とかツむのってこの後になるのか。ちょっと限界気味なんで、明日これを見つつ復習予定ですが、時間が確保できるかどうかは微妙ッス。