2006/12/7 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎

Slides:



Advertisements
Similar presentations
コンパイラ演習 第 6 回 2005/11/17 大山 恵弘 佐藤 秀明. 今回の内容 実マシンコード生成 – アセンブリ生成 (emit.ml) – スタブ、ライブラリとのリンク 末尾呼び出し最適化 – 関数呼び出しからの効率的なリターン (emit.ml) –[ 参考 ]CPS 変換 種々の簡単な拡張.
Advertisements

コンパイラ演習 第 6 回 (2011/11/17) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴 潮田 資秀 小酒井 隆広 山下 諒蔵 佐藤 春旗 大山 恵弘 佐藤 秀明 住井 英二郎.
コンパイラ演習 第 12 回 (2012/01/05) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴 潮田 資秀 小酒井 隆広 山下 諒蔵 佐藤 春旗 大山 恵弘 佐藤 秀明 住井 英二郎.
2006/10/26 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
(Rubyistのための) 超音速:ML入門
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
This slide was a material for the “Reading PLDI Papers (PLDIr)” study group written by Kazuhiro Inaba ( ), under my own understanding of.
2006/11/9 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
コンパイラ 2011年11月14日
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第4回 配列(2) 情報・知能工学系 山本一公
プログラミング基礎I(再) 山元進.
ML 演習 第 8 回 2007/07/17 飯塚 大輔, 後藤 哲志, 前田 俊行
2006/10/5 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/11/30 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
実行時のメモリ構造(1) Jasminの基礎とフレーム内動作
コンパイラ演習番外編 (その2): JVM コンテスト
コンパイラ演習番外編 (その1): min-rt 改 コンテスト
プログラミング演習Ⅱ 第12回 文字列とポインタ(1)
2006/10/12 山下 諒蔵 佐藤 春旗 前田俊行 大山 恵弘 佐藤 秀明 住井 英二郎
オブジェクト指向プログラミング(2) OOPの三大要素 「クラス」「ポリモーフィズム」「継承」
コンパイラ演習 第 9 回 (2011/12/08) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴
2006年度 計算機システム演習 第4回 2005年5月19日.
情報処理Ⅱ 2005年12月9日(金).
コンパイラ演習 第12回 2006/1/26 大山 恵弘 佐藤 秀明.
2007/1/18 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/10/19 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井英二郎
2006/11/02 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/11/16 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
配列の扱い、探索 有効範囲と記憶域期間 第12回 [7月10日、H.15(‘03)] 今日のメニュー 1 前回の課題の復習
コンパイラ演習 第 4 回 (2011/10/27) 中村 晃一 野瀬 貴史 前田 俊行 秋山 茂樹 池尻 拓朗 鈴木 友博 渡邊 裕貴
  【事例演習6】  数式インタプリタ      解 説     “インタプリタの基本的な仕組み”.
プログラムはなぜ動くのか.
の まとめ 2007/04/02 (Mon) / d;id:hzkr
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
2007/1/11 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
Tokuda Lab. NISHIMURA Taichi
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
コンパイラの解析 (2) GCJのデータ構造 - 1.
型付きアセンブリ言語を用いた安全なカーネル拡張
コンパイラの解析 (4) 例外処理.
暗黙的に型付けされる構造体の Java言語への導入
プログラミング言語入門.
コンパイラ演習 第11回 2006/1/19 大山 恵弘 佐藤 秀明.
C-- Mizukami Tatsuo 2001/07/18.
コンパイラ資料 実行時環境.
アスペクト指向言語のための 独立性の高いパッケージシステム
オブジェクト指向プログラミングと開発環境
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
2007/6/12(通信コース)2007/6/13(情報コース) 住井
実装について 前田俊行.
ポインタとポインタを用いた関数定義.
コンピュータアーキテクチャ 第 5 回.
~sumii/class/proenb2010/ml2/
アルゴリズムとデータ構造1 2009年6月15日
コンピュータアーキテクチャ 第 4 回.
2006/6/27(通信コース)2006/7/5(情報コース) 住井
2008/7/16(情報コース)2008/7/22(通信コース) 住井
コンピュータアーキテクチャ 第 5 回.
~sumii/class/proenb2009/ml6/
コンパイラ 2012年10月11日
コンパイラ 第12回 実行時環境 ― 変数と関数 ― 38号館4階N-411 内線5459
アルゴリズムとデータ構造 2010年6月17日
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
プログラミング演習I 2003年6月11日(第9回) 木村巌.
プログラミング演習II 2003年12月10日(第7回) 木村巌.
プログラミング演習II 2004年11月 2日(第3回) 理学部数学科・木村巌.
情報処理Ⅱ 小テスト 2005年2月1日(火).
プログラミング演習II 2003年10月29日(第2,3回) 木村巌.
情報処理Ⅱ 第8回:2003年12月9日(火).
6.5 最終コード生成 (1)コードの形式 ①絶対2進コード(AB : absolute binary) 命令後のオペランドが絶対番地指定。
Presentation transcript:

2006/12/7 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎 コンパイラ演習 第 9 回 2006/12/7 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎

今日の内容 例外処理 (exception handling)

例外処理機構 エラーが発生したときに、現在の計算を中断してエラー処理用のコードにジャンプする機構 開こうとしているファイルが見つからない 配列の境界を越えてアクセスした ユーザの入力がおかしい 関数に渡されるべきでない値が渡された

O’Caml の 例外処理コンストラクト 例外の宣言: exception decl 例外の明示的スロー: raise exp 例外の捕捉: try exp with | pat1 -> exp1 | … | patn -> expn

例外処理の (わざとらしい) 例 exception Zero_found let prod_list_aux lst = List.fold_left (fun r e -> if e = 0 then raise Zero_found else r * e ) 1 lst let prod_list l = try prod_list_aux l with Zero_found -> 0

例外処理の実装のポイント どうやって制御をハンドラに移すか? let f () = try raise No_file with Div_zero -> … let g () = try f () with No_file -> … try g () raise No_file try … with Div_zero -> … try … with No_file -> … try … with No_file -> …

制御をハンドラに移すやり方 Stack unwinding Stack cutting ハンドラを表現するクロージャを導入する ハンドラが見つかるまで関数のフレームを遡っていく Stack cutting ハンドラが見つかるまで try ... with … を遡っていく ハンドラを表現するクロージャを導入する そもそもスタックを使わず CPS でコンパイルする 関数呼び出しも復帰もクロージャへの値適用で表現 (今回は説明しない)

Stack unwinding その1: Native-code stack unwinding 法 式 try e with … を 「式 e の中で例外が発生した」ら 対応するハンドラが実行されるように 直接コード生成する ハンドラがなければ関数からリターンするようにする let g () = let r = f () in if [f ()で例外が発生した] then if [発生した例外 = No_file] then e’ else [関数からリターン] else r let g () = try f () with No_file -> e’ 非常に大雑把な変換のイメージ

関数呼び出しが例外を発生したかどうかをどうやって知るか? 関数が以下のいずれかを返すようにすればよい 例外なしフラグ + 返り値 例外ありフラグ + 例外情報 関数の呼び出し側では返り値を調べることで 例外が発生したかどうか分かる let g () = let r = f () in match r with |Exc (No_file exn) -> e’ |_-> r let g () = try f () with No_file -> e’ 非常に大雑把な変換のイメージ

Stack unwinding その2: Runtime stack unwinding 法 式 raise … を stack unwinding を行うランタイムライブラリ 呼び出しにコンパイルする あとはランタイムライブラリで何とかする … raise No_file … bl min_caml_stack_unwinding 非常に大雑把な変換のイメージ

ランタイムライブラリが やらなくてはならないこと 例外が発生した PC (プログラムカウンタ) (= ライブラリの呼び出し元) にもとづいて 適切なハンドラを呼び出す 適切なハンドラがなければ 「呼び出し元の関数の呼び出し元」に遡って 適切なハンドラを探す

例外が発生した PC からどうやって 適切なハンドラを探すか try … with … の “try” から “with” までの アドレスの範囲と例外ハンドラの関係を 表す表を作っておく これはコンパイル時に完全に決定できるので コンパイラで行うとよい この表を検索し 適切なハンドラを実行すればよい (注) 呼び出し規約に callee-save レジスタがある場合は 例外ハンドラを実行する前に復旧する必要がある

関数の呼び出し元を どうやって遡っていくか 「フレームポインタ」を 呼び出し規約に導入する フレームポインタ = 呼び出し元の関数のスタックのトップ cf. スタックポインタ = 実行中の関数のスタックのトップ

フレームポインタの例 関数呼び出し直後に 呼び出し元のフレームポインタを保存する場合 let f () = … let g () = … 関数呼び出し直後に 呼び出し元のフレームポインタを保存する場合 スタックポインタ … let f () = … let g () = … f () g () フレームポインタ f の呼び出し元のフレームポインタ 実行時の スタックの状態 返り番地 (f の呼び出し元) … g の呼び出し元のフレームポインタ 返り番地 (g の呼び出し元)

フレームポインタを用いた 関数の呼び出し元の探索 前頁の例の場合 (フレームポインタ + 1ワード) のアドレスに 関数の呼び出し元が保存されている 更に呼び出し元を遡るには フレームポインタが指すアドレスに保存されている 呼び出し元のフレームポインタを用いればよい スタックポインタ … フレームポインタ f の呼び出し元のフレームポインタ 直接の呼び出し元 返り番地 (f の呼び出し元) … 直接の呼び出し元 の呼び出し元 g の呼び出し元のフレームポインタ 返り番地 (g の呼び出し元)

Stack cutting tryの入口で setjmp を実行し、 レジスタの値などの情報をスタックに push raise で longjmp を実行してレジスタの値 (スタックポインタ, PC 含む) を復元 結果的に実行スタックの上部が「切られる」 longjmp による制御の戻り先において ハンドラを実行 実はスタックポインタと PC を保存・復元できればいいので setjmp/longjmp でなくてもよい (例: O’Caml の実装)

Stack cutting スタック longjmp raise try … with … -> … envbuf foo() { jmp_buf env; … if (setjmp(&env) == 0) { /* tryブロックの実行 */ } else { /* ハンドラの実行 */ } try … with … -> … envbuf try … with … -> … envbuf try … with … -> … envbuf

Stack cutting と callee-save レジスタ 関数のフレームごとに処理が行われず try … with … ごとに行われるため スタックのどこに callee-save レジスタが 保存されているか簡単には分からない Callee-save レジスタがなければ 問題なし (例: O’Caml)

より深く知るために N. Ramsey and S. P. Jones, “A Single Intermediate Language That Supports Multiple Implementations of Exceptions” (ACM PLDI 2000) C. de Dinechin, “C++ Exception Handling” (IEEE Concurrency, 2000) T. Ogasawara, H. Komatsu, T. Nakatani, “A Study of Exception Handling and Its Dynamic Optimization in Java” (ACM OOPSLA 2001) 住井英二郎, 大根田裕一, 米澤明憲, 「例外処理機構を備えた命令型言語の変換とその定式化」(情報処理学会 論文誌, 2004年)

共通課題 逆 (setjmp/longjmp を例外処理に改造)でもよい 以下のうちから一問を選択して解答せよ Java バイトコードには例外テーブル と呼ばれる情報が埋め込まれている。 文献の調査や実験などにより、 例外テーブルが提供する情報、および、 それが例外処理の実現にどう役立つかを解説せよ 例外処理を用いて記述された C++ プログラムを 一つ探し、 setjmp/longjmp を用いて 同様の動作を実現するプログラムに改造せよ 逆 (setjmp/longjmp を例外処理に改造)でもよい

共通課題 普通の再帰的なフィボナッチ数列計算関数 好きな計算機と処理系を選び、 以下の C++ プログラムの性能を計測せよ。 普通の再帰的なフィボナッチ数列計算関数 関数先頭で try ブロックに入り、関数からの復帰時にその try ブロックから出るように a を修正した関数 (例外は一度も投げない) 関数先頭で一回 setjmp を無駄に呼び出すように a を修正した関数 (longjmp は一度も呼ばない) 再帰的なフィボナッチ数列計算関数。 ただし例外のスローによって返り値を返し、 例外ハンドラで返り値を受け取るような形で 記述されている

コンパイラ係用選択課題 例外処理を自作コンパイラまたはMinCaml に実装せよ 仕様は自由。最低限 try-with と raise に 相当するものだけあればよい Java の finally みたいなのはなくてもよい 例外とハンドラの間の型照合処理もなくてもよい スタック内で最も上にあるフレームのハンドラに必ずひっかかるという仕様でもよい 実装方式は stack unwinding でも stack cutting でも、その他の方法でもよい

課題の提出先と締め切り 提出先: compiler-enshu@yl.is.s.u-tokyo.ac.jp 共通課題の締め切り: 2 週間後 (12/21) の午後 1 時 コンパイラ係用課題の締め切り: 2007年2月28日 Subject: Report 9 <学籍番号> <アカウント> 本文にも氏名と学籍番号を明記のこと