Scm_VMCallCC (2)
の前に以下の一連のナニを復 (予) 習。
3 PRE-CALL(1) 9 5 CLOSURE #<lambda 0> ; (lambda (c) (set! cont c) 4) 7 PUSH-GREF-CALL(1) #<identifier user#call/cc>; (call/cc (lambda (c) (set! cont c) 4)) 9 PUSH
以下にポイント列挙
PRE-CALL
4 にあたる PC に上記であれば 7 の call/cc から RET (あるいは 5 な CLOSURE からの RET?) する時の戻りである 9 なソレが格納されてて、PRE-CALL の中の PUSH_CONT で ScmContFrame 型の pc 属性にセットされてスタックに push される。
PUSH_CONT マクロは以下なカンジ
/* Push a continuation frame. next_pc is the PC from where execution will be resumed. */ #define PUSH_CONT(next_pc) \ do { \ ScmContFrame *newcont = (ScmContFrame*)SP; \ newcont->prev = CONT; \ newcont->env = ENV; \ newcont->argp = ARGP; \ newcont->size = SP - ARGP; \ newcont->pc = next_pc; \ newcont->base = BASE; \ CONT = newcont; \ SP += CONT_FRAME_SIZE; \ ARGP = SP; \ } while (0)
定義は vm.c の中。ちなみに ScmContFrame 型は gauche/vm.h で定義されてて以下。
typedef struct ScmContFrameRec { struct ScmContFrameRec *prev; /* previous frame */ ScmEnvFrame *env; /* saved environment */ ScmObj *argp; /* saved argument pointer */ int size; /* size of argument frame */ SCM_PCTYPE pc; /* next PC */ ScmCompiledCode *base; /* base register value */ } ScmContFrame;
CLOSURE
ここでも 6 にあたる次のナニに ScmObj なコンパイル済みの lambda 手続きなオブジェクトのポインタが格納されていると思われる。それを取り出して Scm_MakeClosure 手続きな戻りを val0 に格納。
PUSH-GREF-CALL
- val0 を push
- 8 にあたる次のナニから束縛を解決して val0 に
- CALL する
- ここで CALL される call/cc の中身がどうなっているか、がある意味今のテーマ
PUSH
- 戻りな val0 をスタックに push
CALL?
む。とりあえず call/cc は subr なナニなので
gosh> call/cc #<subr call-with-current-continuation> gosh>
CALL の以下な分岐を辿るはず。
/* * We process the common cases first */ 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; }
これって func の呼び出し部分が正にソレ、なのでしょうか ...
SCM_SUBR
ScmSubr 型 (ScmSubrRec 構造体) な定義が以下 (gauche.h)
/* Subr - C defined procedure */ struct ScmSubrRec { ScmProcedure common; ScmSubrProc *func; void *data; };
ええと、ScmSubrProc 型の定義は gauche.h で以下。
typedef ScmObj ScmSubrProc(ScmObj *, int, void*);
むむ。call/cc だとどうなってるか、ってどうやって調べる?
# それが stdlib.{c, stub} な気もするな ...
あった
stdlib.c に以下な記述を発見。
static ScmObj stdlib_call_with_current_continuation(ScmObj *SCM_FP, int SCM_ARGCNT, void *data_) { ScmObj proc_scm; ScmObj proc; SCM_ENTER_SUBR("call-with-current-continuation"); proc_scm = SCM_ARGREF(0); proc = (proc_scm); { { ScmObj SCM_RESULT; SCM_RESULT = Scm_VMCallCC(proc); SCM_RETURN(SCM_OBJ_SAFE(SCM_RESULT)); } } } static SCM_DEFINE_SUBR(stdlib_call_with_current_continuation__STUB, 1, 0, SCM_OBJ(&scm__sc.d633[149]), stdlib_call_with_current_continuation, NULL, NULL);
自動生成ちっくなナニですな。引数とか戻りが一緒なのでこれが func 属性にセットされている、という事にしときます。
あ、下の SCM_DEFINE_SUBR で実体作ってるのかな? そゆ事にしときます。(を
一応
紐がついたカンジなんで割り込み受け付け。続きは別途で。