とほほ
オーバーロード宣言をしつつ、がんばってみる。
以下、自分メモ。
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 したナニを全部見てみる、とか??
続
$ 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 云々に関するドキュメント読んだ方が良さげ。