wiki:例外処理の実装方法

Version 1 (modified by dai, 13 years ago) (diff)

--

例外処理、即ちTry-Catch-Finallyの実装方法をここに記す。

まず始めに、実装に向けて抑えておきたいポイント。

  • 大域ジャンプ
  • Try専用コールスタック
  • スタック領域専用の動的型情報

大域ジャンプとは、ローカル関数を飛び越したGotoのようなもの。一般的に実行ポインタはローカル領域内でのみ変化するものだが、例外に関してはその限りではない。

Try専用コールスタックとは、違う言い方をすればCatch専用コールスタックともとれる。ようは、Catchを検索するためのリスト。スレッド固有な情報であり、Throwされたときのジャンプ先が明記されている。

この2点に関しては、どちらかというと実行制御の問題なので実装に関しては、あまり大きな労力は必要としない。問題となるのは、最後に残った動的型情報。ABコンパイラはコード生成のすべてを静的型情報に頼った形で実現している。実行時、どのような順序で関数が呼び出され、とあるタイミングで構築されるスタック内の詳細情報は不明である。それは、静的に生成した実行コードが自動的に処理してくれるものであり、本来それを知る必要はない。しかし、Throwされたとき、この情報は無くてはならない情報へと扱いが変わる。例外が投げられると、適切なCatchコードへ大域ジャンプすると同時に、スタックが巻き戻される。言ってみみればジャンプ対象となるCatch階層の状態を復元しなければならないのである。そのためには、スタックポインタを巻き戻すだけではなく、そこに蓄積されたオブジェクトインスタンスを解放しなければならない。解放の具体的な手法はデストラクタを呼び出すこと。

スレッド内部は、様々な関数及びメソッドが呼び出されることで常に変化が生じている。そこを静的な覗くことは事実上不可能なので、別途動的型情報として実行時に自動生成しなければならない。

ABコンパイラは、すべての関数に関してその関数が必要なローカル領域の情報をデータ片として管理し、実行時にスレッド固有の動的型情報ストレージに蓄積する。

こうすることで、例外が投げられた場合、安全にローカルオブジェクトの破棄が行われ、スタックは巻き戻される。あとはCatchに実行が遷移するので、その中で適切な例外処理をしていただきたい。

まとめとして、今一度、例外処理のイメージ手順を記しておく。

  1. Throwされる。
  2. 遷移先のCatchを検索。
  3. スタックをどれだけ巻き戻すのかを計算する。
  4. ロールバック対処のスタック領域内に存在するオブジェクトのデストラクタを新しい順に呼び出す。
  5. スタックポインタを減算し、Catchのコード位置と同等にする。
  6. 例外パラメータをスタックに積む。
  7. 大域ジャンプを行い、Catchコードに実行を移す。

この他、関数やメソッドの入り口と出口では自身のローカル領域に関する型情報を動的に把握するための措置が必要になる。よって、例外処理とは別次元の問題として、下記のような働きを提供しなければならない。

  • ローカル領域に配属される実体オブジェクトの型情報とその位置
  • 確保されたオブジェクトなのか、未確保のオブジェクトなのかを見分けるためのフラグ管理(モジュールコードの途中でThrowされた場合に必要な情報)