throw_continuation() 手続き
現実トウヒという訳ではないんですが、こちらもこつこつ進める方向で。
とりあえず vm->cstack と ep->cstack が異なるケイスのナニはスルーな方向。要点を以下に控えつつ情報投入予定。
基本的に vm->cstack と ep->cstack が同一な場合は R5RS の dynamic-wind に関するエントリで定義されてる before や after の呼び出し順に沿った形で作られたリストと argframe の最初の要素と data を ScmEscapePoint にキャストしたナニを throw_cont_body に渡してその戻りを戻せば良い。
ちなみにこの throw_continuation ですが以下なコメントがあって
/* Body of the continuation SUBR */
基本的に
gosh> (list 1 2 3 (call/cc (lambda (c) (set! cont c) 4)) 5 6) (1 2 3 4 5 6) gosh> (cont -1)
って捕捉した継続を呼び出した瞬間に呼び出されるのが throw_continuation になります。cont に束縛されている手続きオブジェクトは Scm_VMCallCC() 手続きの以下の部分で
save_cont(vm); ep = SCM_NEW(ScmEscapePoint); ep->prev = NULL; ep->ehandler = SCM_FALSE; ep->cont = vm->cont; ep->handlers = vm->handlers; ep->cstack = vm->cstack; contproc = Scm_MakeSubr(throw_continuation, ep, 0, 1, SCM_MAKE_STR("continuation"));
ep にパケジされて (あるいは継続フレームが heap に退避されて) オブジェクトの属性として保管されてます。で、上記でナニされたものがどう
static ScmObj throw_continuation(ScmObj *argframe, int nargs, void *data)
に渡されるか、という事で SCM_VM_CALL なインストラクションの処理を見てみると以下。
proctype = SCM_PROCEDURE_TYPE(VAL0); if (proctype == SCM_PROC_SUBR) { /* We don't need to complete environment frame. Just need to adjust sp, so that stack-operating procs called from subr won't be confused. */ ADJUST_ARGUMENT_FRAME(VAL0, argc); SP = ARGP; PC = PC_TO_RETURN; SCM_PROF_COUNT_CALL(vm, VAL0); VAL0 = SCM_SUBR(VAL0)->func(ARGP, argc, SCM_SUBR(VAL0)->data); /* the subr may substituted pc, so we need to check if we can pop the continuation immediately. */ if (TAIL_POS()) RETURN_OP(); NEXT; }
あ、先に Scm_MakeSubr() 見ないと微妙か。以下ッス。
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); }
手続きオブジェクトの data 属性に ep が格納されてます。ので throw_continuation() にて以下なナニ。
static ScmObj throw_continuation(ScmObj *argframe, int nargs, void *data) { ScmEscapePoint *ep = (ScmEscapePoint*)data;
このあたり、キメ打ちで良いのでアレですね。ただ、微妙なのが cstack 属性のナニ。とりあえずスルーで何とかなりそうな方向で (を
投入
してみよう。概要説明下書きが以下。
call/cc で捕捉した継続を呼び出した時点で呼び出されるのがこの手続きとなる。
vm->cstack と ep->cstack が同一な場合は R5RS の dynamic-wind に関するエントリで定義されてる before や after の呼び出し順に沿った形で作られたリストと argframe の最初の要素と data を ScmEscapePoint にキャストしたナニを throw_cont_body に渡してその戻りを戻せば良い。
vm と ep で cstack が異なるケースについては完全に理解できていませんので、加筆をお願いします。
弱い。でもとりあえずこれで入れちゃえ (を
って
キャストしたナニ
は駄目だな。