データ構造について自分メモ

ScmVM、ScmEscapePoint、ScmContFrame、ScmCompiledCode とか。

  • ScmVM 型は ScmEscapePoint 型の属性を持っている
  • ScmVM 型は ScmCompiledCode 型の属性を持っている
  • よく見たら ScmVM 型は ScmContFrame 型の属性も持っている

というコトは ScmVMRec 構造体を少なくともざっくり理解するのは必要不可欠。

by sixth sense

構造体定義を見てて cstack というメンバの記述が微妙に気になる

    ScmCStack *cstack;          /* current escape point.  see the comment of
                                   "C stack rewinding" below. */

ScmCStack 型ってどっかで見たな、と思いつつ下にある、というコメントを発見。もしかするとこれも Reading Gauche 方面では記述がありそげ。

このあたりはなんとなくイメージできるんですが、Scm_VMDefaultExceptionHandler() では vm->escapePoint を元に巻き戻しをしてるんだよなぁ。これも Reading Gauche にあるか

escapePoint と cstack の違いって何だろ。

    ScmEscapePoint *escapePoint;/* chain of escape points (a kind of one-shot
                                   continuation).  used by system's default
                                   exception handler to escape from the error
                                   handlers. */

よく見てみると SCM_UNWIND_PROTECT 関連のマクロ定義の中身で使われてるのが cstack でマクロの中の sigsetjmp() の戻りが 0 の処理 (longjmp() の飛び先) は escapePoint が使われているのは分かるんですがそっから先がまだ暗い。
とは言え、Scm_VMDefaultExceptionHandler() はちょっとだけイメージできたカンジかも。ここを手がかりにもう少し掘る事ができるかどうか。

Scm_Error() を見てみる

引用しつつ微妙な点を挙げつらう

void Scm_Error(const char *msg, ...)
{
    ScmObj e;
    ScmVM *vm = Scm_VM();
    va_list args;

    if (SCM_VM_RUNTIME_FLAG_IS_SET(vm, SCM_ERROR_BEING_HANDLED)) {
        e = Scm_MakeError(SCM_MAKE_STR("Error occurred in error handler"));
        Scm_VMThrowException(vm, e);
    }

最初のこれは ScmVM の Runtime flags を見てスデに HANDLED な状態であればエラーハンドラの中でエラーが発生したと見て、な処理に見える。
で、そうでなければ HANDLED な状態にして

    SCM_VM_RUNTIME_FLAG_SET(vm, SCM_ERROR_BEING_HANDLED);
    
    SCM_UNWIND_PROTECT {
        va_start(args, msg);
        e = Scm_MakeError(Scm_Vsprintf(msg, args, TRUE));
        va_end(args);
    }
    SCM_WHEN_ERROR {
        /* TODO: should check continuation? */
        e = Scm_MakeError(SCM_MAKE_STR("Error occurred in error handler"));
    }
    SCM_END_PROTECT;

ここで SCM_UNWIND_PROTECT マクロが出てくる。ちょっと誤解してたんですが

#define SCM_UNWIND_PROTECT                      \
    do {                                        \
       ScmCStack cstack;                        \
       cstack.prev = Scm_VM()->cstack;          \
       cstack.cont = NULL;                      \
       Scm_VM()->cstack = &cstack;              \
       if (sigsetjmp(cstack.jbuf, FALSE) == 0) {

の最後の条件式によれば longjmp() からの戻り先は SCM_WHEN_ERROR 以降になるはずなんですが、ちょっとワケワカらんくなってるな。何かカンチガいしてますかねぇ。
あと ScmVM の cstack にローカル変数なアドレスぶち込んじゃってますが大丈夫なんだろうか。このあたりの語彙があまり無いから弱いんですが、こうしたヤリ方がデフォルトだったりするんだろうな。まだまだイメージするソレからは遠い。
とりあえず setjmp されて cstack な chain には追加されるのは間違いない、んだろうか。