とほほ

オーバーロード宣言をしつつ、がんばってみる。
以下、自分メモ。
Scm_VMThrowException() はざっくりベースで三つ

  • vm->exceptionHandler が DEFAULT_EXCEPTION_HANDLER でない
    • これはユーザ定義のエラーハンドラがあるという事か
    • ハンドラを ApplyRec し戻りを vm0 に設定して戻す
  • vm->exceptionHandler が DEFAULT_EXCEPTION_HANDLER なんだけど、exception が SCM_SERIOUS_CONDITION_P でない
    • escapePoint オブジェクトを走査して DEFAULT_EXCEPTION_HANDLER 以外のものがあればハンドラを ApplyRec して戻す
  • それ以外 (これがおそらくデフォルト)
    • Scm_VMDefaultExeptionHandler 呼び出し (戻らない)

Scm_VMDefaultExeptionHandler も概要の記述が無ひ。ざっくりなソレはこんなカンジで良いのかなぁ。Scm_Error によれば Scm_VMDefaultExeption は戻らないように読める。
てーか異常系ってやっぱ全般が見えてないと微妙。もう少し修行か。Scm_VMThrowException で grep したナニを全部見てみる、とか??

Gauche-0.8.11/src 以下を grep

$ find -name '*.c'|xargs grep VMThrowException
./error.c: *   Scm_VMThrowException() in vm.c.   These routines provide
./error.c:        Scm_VMThrowException(vm, e);
./error.c:    Scm_VMThrowException(vm, e);
./error.c:    Scm_Panic("Scm_Error: Scm_VMThrowException returned.  something wrong.");
./error.c:    Scm_VMThrowException(vm, e);
./error.c:    Scm_Panic("Scm_Error: Scm_VMThrowException returned.  something wrong.");
./error.c:    Scm_VMThrowException(vm, e);
./error.c:    Scm_Panic("Scm_Error: Scm_VMThrowException returned.  something wrong.");
./error.c:/* An external API to hide Scm_VMThrowException. */
./error.c:    return Scm_VMThrowException(Scm_VM(), condition);
./vm.c:ScmObj Scm_VMThrowException(ScmVM *vm, ScmObj exception)
$

それほどでも無いのか、とは言えこの関数直にタタく方が微妙か。error.c の中を確認。呼び出し元は

  • Scm_Error()
  • Scm_SysError()
  • Scm_PortError()
  • Scm_Raise()

になっている。こんなコメントもあり

/* An external API to hide Scm_VMThrowException. */

てーコトは上記のそれぞれで grep してみりゃ良いのか。いや Scm_VMThrowException() のユーザ定義の例外セットなソレかな。exceptionHandler で grep してみる

$ find -name '*.c'|xargs grep exceptionHandler
./vm.c:    v->exceptionHandler = DEFAULT_EXCEPTION_HANDLER;
./vm.c:    if (vm->exceptionHandler != DEFAULT_EXCEPTION_HANDLER) {
./vm.c:        vm->val0 = Scm_ApplyRec(vm->exceptionHandler, SCM_LIST1(exception));
./vm.c:            vm->exceptionHandler = DEFAULT_EXCEPTION_HANDLER;
./vm.c:    vm->exceptionHandler = DEFAULT_EXCEPTION_HANDLER;
./vm.c:    vm->exceptionHandler = ep->xhandler;
./vm.c:    ep->xhandler = vm->exceptionHandler;
./vm.c:    theVM->exceptionHandler = SCM_OBJ(data);
./vm.c:    ScmObj current = theVM->exceptionHandler;
./exclib.c:(Scm_VM())->exceptionHandler);
$

見事に構造体メンバの操作を閉じ込めている。テーマ限定だと見るのが楽。値を設定しているポイントとしては

  • コンストラクタ (Scm_NewVM()) ではデフォルト値が設定
  • install_ehandler() という内部手続きでデフォルト値を設定しているが、ここでは引数で受け取ったポインタを vm->escapePoint に代入している。
  • discard_ehandler() という内部手続きでは引数で受け取った escapePoint の xhandler 属性が代入されている
  • install_xhandler() という内部手続きでは引数で受け取ったオブジェクトを代入

いくつか不明点 (いくつも、か

  • ehandler と xhandler の違い (これは VM の構造体のメンバではないな
  • 上記の内部手続きはどこから呼ばれているのか
  • とりあえず escapePoint ってモノが何なのか、が微妙 (コメントが和訳されている模様。ScmEscapePoint

うーん (困
材料が微妙なのは *.c で find かけてるからかなぁ。とりあえず ehandler と xhandler で grep

$ find -name '*.c'|xargs grep ehandler
./vm.c:            result = Scm_ApplyRec(ep->ehandler, SCM_LIST1(e));
./vm.c:static ScmObj install_ehandler(ScmObj *args, int nargs, void *data)
./vm.c:static ScmObj discard_ehandler(ScmObj *args, int nargs, void *data)
./vm.c:    ep->ehandler = handler;
./vm.c:    vm->escapePoint = ep; /* This will be done in install_ehandler, but
./vm.c:    before = Scm_MakeSubr(install_ehandler, ep, 0, 0, SCM_FALSE);
./vm.c:    after  = Scm_MakeSubr(discard_ehandler, ep, 0, 0, SCM_FALSE);
./vm.c:    ep->ehandler = SCM_FALSE;
./vm.c:                   ep, ep->cont, ep->ehandler);
./repl.c:    ScmObj ehandler, reploop;
./repl.c:    ehandler = Scm_MakeSubr(repl_error_handle, packet, 1, 0, SCM_FALSE);
./repl.c:    return Scm_VMWithErrorHandler(ehandler, reploop);
$ find -name '*.c'|xargs grep xhandler
./vm.c:            if (ep->xhandler != DEFAULT_EXCEPTION_HANDLER) {
./vm.c:                return Scm_ApplyRec(ep->xhandler, SCM_LIST1(exception));
./vm.c:    vm->exceptionHandler = ep->xhandler;
./vm.c:    ep->xhandler = vm->exceptionHandler;
./vm.c:static ScmObj install_xhandler(ScmObj *args, int nargs, void *data)
./vm.c:    ScmObj before = Scm_MakeSubr(install_xhandler, handler, 0, 0, SCM_FALSE);
./vm.c:    ScmObj after  = Scm_MakeSubr(install_xhandler, current, 0, 0, SCM_FALSE);
$

ヤバい。何か拡散している。ちょっと元に戻そう。ええと

  • install_ehandler() と discard_ehandler() は with_error_handler() で使われている
  • 具体的には with_error_handler() で作られる ep オブジェクトと install あるいは discard なソレで subr を作って Scm_VMDynamicWind() に渡す
  • with_error_handler() を呼び出している公開手続きは
    • Scm_VMWithErrorHandler()
    • Scm_VMWithGuardHandler()
  • install_xhandler() は Scm_VMWithExceptionHandler() で直接 subr にして Scm_VMDynamicWind() に渡している

これらの公開手続きを見てみると自動生成されている exclib.c 方面に行き当たる。

続々

むむ。何してるのかワケワカに。とりあえず Scm_Error() から呼び出された Scm_VMThrowException() では以下の_戻る_形

  • vm->exceptionHandler は DEFAULT_EXCEPTION_HANDLER 以外
  • exception が SCM_SERIOUS_CONDITION_P でなく vm->escapePoint なリストの xhandler 属性に DEFAULT_EXCEPTION_HANDLER ではない要素がある

にはなり得ない、という判断で良いのかなぁ。(多分違う
ってか、Scm_VMDefaultExceptionHandler() が何をしているか、も不明。とりあえずざっくりと、は見えてきた気がするので作業再開してみよう。自分が微妙に感じてる部分はコメントで残しておけば良いのかも。

追記

SCM_UNWIND_PROTECTにある_C スタックの巻戻し_という記述なイメージ不能。vm 云々に関するドキュメント読んだ方が良さげ。