Scm_VMDynamicWind
起点が何だったのか、が段々微妙になってきていますがどんどん続ける。
shiro さんからご教示頂いたナニも参考にしつつ
gosh> (disasm (lambda () (dynamic-wind a b c))) main_code (name=#f, code=0x8163f78, size=9, const=4, stack=6): args: #f 0 GREF-PUSH #<identifier user#a>; a 2 GREF-PUSH #<identifier user#b>; b 4 GREF-PUSH #<identifier user#c>; c 6 GREF-TAIL-CALL(3) #<identifier user#dynamic-wind>; (dynamic-wind a b c) 8 RET #<undef> gosh>
を元に掘削。途中は略で
- 一旦 dynamic-wind に束縛されてる関数ポインタ値が val0 格納
- PC に RET を仕込んで val0 な関数 (stdlib_dynamic_wind) 呼び出して戻りを val0 格納
- 末尾呼び出しなので継続を pop して NEXT
という流れ。もう少し細かく見てみる。上記二番目以降の処理が以下。
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_VMDynamicWind() の戻りが val0 に格納されるんですが shiro さんからのフォローの通り、
Scm_VMPushCC(dynamic_before_cc...); // 次のRETでdynamic_before_ccを呼んでね
return Scm_VMApply0(before); // 戻ったらbeforeを呼んでねしたがってこのルーチンからVM loopに戻った後に、
- beforeが呼ばれ
- beforeがRETする際にdynamic_before_ccが呼ばれる
という事になるのか。作成者な shiro さんからのフォローですがツッコんで確認してみると
- 次のRETでdynamic_before_ccを呼んでね
- 継続フレームに_dynamic_before_ccを呼んでね_なナニを push
- 戻ったらbeforeを呼んでね
- PC レジスタに TAIL_CALL と RET な配列の先頭ポインタをセット
- proc (before ですね) を return して val0 に格納
という事でまず_before が呼ばれ_るんですね。で、RET する時に継続フレームが pop されるので_beforeがRETする際にdynamic_before_ccが呼ばれる_という事になる、と。
む
だらだら見てたら月曜になった。ここから先、順ぐりにめくってく感じなのはイメージできてるんですが、dynwind_before_cc あたりで vm->handlers を弄ってるのが微妙。あ、でも dynwind_body_cc で戻してますな。
うー。このあたり色々な操作を見越してるんでしょうが、意図しているナニを読み切れないのがとても腹立たしいカンジ。ってか引数に何が渡るか、も含めてきちんと精査した方が良さげ。