Scm_VMCallCC (17)

もう少し。
(16) なエントリにて_contproc に格納される手続きオブジェクトは退避された継続フレームへのポインタを属性として持つ ScmEscapePoint なポインタを属性として持つ_と書いた。
投入直後に確認したんですが、凄く分かりにくい。ってか多分違うと思うのできちっと確認してみる事に。

まず

以下をナニ。

    contproc = Scm_MakeSubr(throw_continuation, ep, 0, 1,
                            SCM_MAKE_STR("continuation"));

Scm_MakeSubr 手続きから確認。基本的には ScmSubr 型のオブジェクトを戻す。定義は以下 (proc.c にて定義)。

ScmObj Scm_MakeSubr(ScmSubrProc *func,
                    void *data,
                    int required, int optional,
                    ScmObj info)
{
    ScmSubr *s = SCM_NEW(ScmSubr);
    SCM_SET_CLASS(s, SCM_CLASS_PROCEDURE);
    SCM_PROCEDURE_INIT(s, required, optional, SCM_PROC_SUBR, info);
    s->func = func;
    s->data = data;
    return SCM_OBJ(s);
}

領域を確保して属性をセットしている。ScmSubr 型も以下に引用。

/* Subr - C defined procedure */
struct ScmSubrRec {
    ScmProcedure common;
    ScmSubrProc *func;
    void *data;
};

ScmSubrProc って何だば、と言いつつ以下。

typedef ScmObj ScmSubrProc(ScmObj *, int, void*);

ええと、subr として登録可能な C の手続きは上記なプロトタイプでないと NG なのか。ってか微妙に気になるのが required に 0、optional に 1 がセットされてるソレ。ちなみに ScmProcedure 型の定義は以下で

struct ScmProcedureRec {
    SCM_INSTANCE_HEADER;
    unsigned char required;     /* # of required args */
    unsigned char optional;     /* 1 if it takes rest args */
    unsigned char type;         /* procedure type  */
    unsigned char locked;       /* setter locked? */
    ScmObj info;                /* source code info */
    ScmObj setter;              /* setter, if exists. */
    ScmObj inliner;             /* inliner.  NB: for backward compatibility,
                                   this may be initialized by NULL. */
};

なんか微妙。call/cc の引数は 1 引数の手続き、なはずなんですが、このあたりの属性の値ってスルーされちゃってるんでしょうか ...
# ってか一旦スルーします
とりあえず、ScmSubrProc な関数ポインタとその時点の cont と handlers と cstack が格納されたオブジェクトを持つ手続きオブジェクトが作られて contproc に設定される、と。その継続が捕捉されて再度呼び出された時のナニは別途確認します。

最後

例えば

(call/cc (lambda (c) (set! cont c) 4))

なナニは最終的に引数で渡された lambda な手続きがその時点の継続 (上記で作られた手続きオブジェクトですね) を引数に呼び出される。それが Scm_VMCallCC 手続きのいっちゃんケツのこれ。

    return Scm_VMApply1(proc, contproc);

Scm_VMApply1 の定義は vm.c で以下。

ScmObj Scm_VMApply1(ScmObj proc, ScmObj arg)
{
    ScmVM *vm = theVM;
    CHECK_STACK(1);
    PUSH_ARG(arg);
    PC = apply_calls[1];
    return proc;
}

引数 push しといて以下な配列の先頭アドレスが PC にナニ。

    { SCM_VM_INSN1(SCM_VM_TAIL_CALL, 1),
      SCM_VM_INSN(SCM_VM_RET) },

で、proc が戻る。戻されたソレは VAL0 に格納されてます。よくできてるなぁ。ってかそうするためにこーゆー作り (proc を戻す形) になってるのか。
ええと、割り込み入ったので捕捉された継続が呼び出された時のナニのトレイスは別途エントリ投入します。