実装確認
明日からは kernel シリーズな二日間なのでキリが良いあたりまで片付けておきたいな、と言いつつ R5RS にて例示されているナニから確認。
disasm してみたら出力が一枚に収まらなくて (当たり前) 困る。
とりあえず
(dynamic-wind (lambda () (add '1)) (lambda () (add '2)) (lambda () (add '3)))
でどうなるか、という事を確認しといて thunk で捕まえた継続を呼び出した時のソレを確認する方向で。
Scm_VMDynamicWind() 手続き
- 引数で受けとった手続きなポインタを void * な配列に格納して VMPushCC に渡す
- 継続な手続きは dynwind_before_cc 手続き
- before を呼び出すように操作
- val0 に呼び出す手続きをセットして pc に TAIL-CALL, RET なセットを格納
before が呼び出された時点では handlers とかは全然スルー状態。
む
dynwind_before_cc() 手続きの引数の並びを見て、どうなってたんだったか、と思い POP_CONT マクロを再確認。詳細は略しますが核心が以下。
VAL0 = CALL_CCONT(after__, VAL0, data__); \
いっちゃん最後のソレです。CALL_CCONT もマクロで定義が以下。
#define CALL_CCONT(p, v, d) p(v, d)
整理しとくと dynwind_*_cc な手続きの例えば以下なナニだと
static ScmObj dynwind_before_cc(ScmObj result, void **data)
val0 な値が result で継続 push した時に渡したポインタ配列の先頭アドレスが data に格納されて呼び出される、と。ここがイメージできればバケツリレー方式なのが理解できます。
# 理解が正しければ、ですが (を
dynwind_before_cc() 手続き
なんで before が必要なんだろ、と思ったんですが handlers に格納しなきゃダメなんですね。ヤッてる事は
- 引数の data から手続きなポインタを復帰
- after な手続きポインタと現在の vm->handlers を Scm_VMPushCC() に渡す引数なポインタ配列に退避
- vm->handlers を更新
- (cons (cons before after) handlers) する
後は dynwind_body_cc を継続に push して body (thunk) を呼び出すように操作。
という事は body の実行時には handlers に何かがある、という状態なのか。ちょっと考慮が浅い気がしますが進めてみます。
dynwind_body_cc() 手続き
ここから後は始末に終始。
- vm->handlers を元に戻す
- body (thunk) が戻す val0 を退避
- 多値を戻すケースの処理
をしておいて after 及びその継続のナニ
dynwind_after_cc() 手続き
ここまで来ると値を戻す処理に終始してますな。核心は過ぎてるのでナニ。あまり gdgd ヤッてないで body (thunk) で継続が、なソレを確認します。確認対象はとりあえず以下のナニ。
(let ((add (lambda (s) (set! path (cons s path))))) (dynamic-wind (lambda () (add '1)) (lambda () (add (call-with-current-continuation (lambda (c0) (set! c c0) '2)))) (lambda () (add '3))) (if (< (length path) 4) (c '-1) (reverse path)))
蛇足かもしれませんが (c '-1) した瞬間のソレ。
継続が呼び出されて起動されるのは基本的に throw_continuation() なナニ。現時点で理解が微妙なナニは throw_cont_calculate_handlers() 手続き。
とりあえず vm->handlers が空だとすると戻るのは以下なのでしょうか。
(before . '())
うーん ...
でもとりあえずこっから throw_cont_body() 手続きで、きっちり呼び出されるのは理解できたのですが、ちょっと限界ッス。