実装確認

明日からは 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() 手続きで、きっちり呼び出されるのは理解できたのですが、ちょっと限界ッス。