コンパイラの解析 (4) 例外処理.

Slides:



Advertisements
Similar presentations
1 B10 CPU を作る 1 日目 解説 TA 高田正法
Advertisements

独習JAVA Chapter 6 6.6 クラスの修飾子 6.7 変数の修飾子 結城 隆. 6.6 クラスの修飾 abstract インスタンス化できないクラス。1つまたは複数のサブクラスで 実装してはじめてインスタンス化できる。 final 継承されたくないことを明示する。これ以上機能拡張 / 変更でき.
6.4継承とメソッド 6.5継承とコンストラクタ 11月28日 時田 陽一
2006/10/26 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/11/9 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
コンパイラ 2011年11月14日
とても使いやすい Boost の serialization
実行時のメモリ構造(1) Jasminの基礎とフレーム内動作
とても使いやすい Boost の serialization
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
App. A アセンブラ、リンカ、 SPIMシミュレータ
2006年度 計算機システム演習 第4回 2005年5月19日.
コンパイラ 2011年11月24日
2006/12/7 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
2006/10/19 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井英二郎
プログラミング論 II 電卓,逆ポーランド記法電卓
第4回放送授業.
の まとめ 2007/04/02 (Mon) / d;id:hzkr
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
Tokuda Lab. NISHIMURA Taichi
アルゴリズムとデータ構造 2011年6月20日
コンパイラ 2012年11月19日
コンパイラの解析 (2) GCJのデータ構造 - 1.
型付きアセンブリ言語を用いた安全なカーネル拡張
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
8.1 例外処理 8.2 catchブロックの検索 8.3 throwステートメント 8.4 例外とエラークラス 8.6 独自の例外
ちょっとした練習問題① 配列iroを['R', 'W', 'R', 'R', 'W' , 'W' , 'W']を宣言して、「W」のときの配列の番号をprintfで表示するようなプログラムを記述しなさい。
プログラミング言語入門 手続き型言語としてのJava
プログラミング2 関数
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
独習Java ・ 8.1  例外処理 ・ 8.2  catch ブロックの検索  12月 5日    小笠原 一恵.
第9章 例外処理,パッケージ 9.1 例外処理 9.2 ガーベッジコレクション.
オブジェクト指向 プログラミング 第八回 知能情報学部 新田直也.
独習JAVA 6.8 コンストラクタの修飾子 6.9 メソッドの修飾子 6.10 ObjectクラスとClassクラス 11月28日(金)
オブジェクト指向 プログラミング 第十一回 知能情報学部 新田直也.
リファレンスの復習と例外処理 2005年6月14日 海谷 治彦.
コンパイラの解析 (3) クラスとインスタンスの初期化.
最適化の方法 中田育男著 コンパイラの構成と最適化 朝倉書店, 1999年 第11章.
オブジェクト指向 プログラミング 第七回 知能情報学部 新田直也.
10-1 SAXの概要 10-2 Saxプログラミングの基礎 10-3 saxのプログラム例
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
アルゴリズムとデータ構造 補足資料5-1 「メモリとポインタ」
Recoveryアドバイスをもつ アスペクト指向システム
演習1の解答例の解説 2006年11月8日 海谷 治彦.
コンパイラ資料 実行時環境.
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
フロントエンドとバックエンドのインターフェース
オブジェクト指向プログラミングと開発環境
アルゴリズムとプログラミング (Algorithms and Programming)
文字列へのポインタの配列 static char *lines[MAXLINES]; lines[0] NULL
アルゴリズムとデータ構造演習(7月1日) 例外処理 2019/5/8.
オブジェクト指向 プログラミング 第八回 知能情報学部 新田直也.
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
同期処理のモジュール化を 可能にする アスペクト指向言語
ポインタとポインタを用いた関数定義.
アルゴリズムとデータ構造1 2009年6月15日
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
アルゴリズムとデータ構造 2012年6月21日
コンパイラ 第12回 実行時環境 ― 変数と関数 ― 38号館4階N-411 内線5459
アルゴリズムとデータ構造 2010年6月17日
フレンド関数とフレンド演算子.
Javaとは Javaとはオブジェクト指向言語でJava VM(Java仮想マシン)と呼ばれるプログラム上で動作します。
情報処理Ⅱ 2005年11月25日(金).
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
情報処理Ⅱ 小テスト 2005年2月1日(火).
プログラミング 3 ポインタ(1).
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング 2 静的変数.
Presentation transcript:

コンパイラの解析 (4) 例外処理

例外処理 通常のコントロールフローではない 言語の実装からは隠蔽されている 大域脱出をおこなう どこからでもジャンプする可能性がある 何か特殊な仕掛けが必要!

例外処理の実装方法 二返戻値法 setjmp法 表引き法 正常値と例外値の両方を返す 通常のコーリングシーケンス+例外検査 例外が発生したら大域脱出 大域脱出のジャンプ先をあらかじめ指定 表引き法 例外が発生したら表を元にジャンプ 正常実行時にほとんどコストが掛からない

サンプルプログラム – Add public static void main(String[] args) { try { int result = add(args[0], args[1]); System.out.println("result = " + result); } catch (NumberFormatException e) { System.out.println(e.getMessage()); System.out.println("unknown result"); } } static int add(String a, String b) { return Integer.parseInt(a) + Integer.parseInt(b); }

二返戻値法における実装 (概要) 関数は常に2つの値を返す 例外情報が存在(=例外が発生)しているか関数呼び出しのたびに調査 通常の関数の戻り値 (正常値) 例外情報 例外情報が存在(=例外が発生)しているか関数呼び出しのたびに調査 通常のコーリングシーケンスを利用できる 関数コールのたびに例外検査を行う

二返戻値法における実装 (throw) フラグと情報を用意してリターンすればよい int parseInt(const char *s) { char *end; int a = strtol(s, &end, 10); if (end[0] != '\0') { sprintf(exc.message, "parse error: %s", s); exc.occurred = 1; return 0; } return a; }

二返戻値法における実装 (throws) 例外を通過させる場合も明示的に 関数呼び出しのたびに行う int add(const char *a, const char *b) { int ia, ib; ia = parseInt(a); if (exc.occurred) return 0; ib = parseInt(b); if (exc.occurred) return 0; return ia + ib; }

二返戻値法における実装 (catch) 例外が発生していた場合にその処理を行う 正常終了時も検査だけは必須! int main(int argc, char **argv) { int result = add(argv[1], argv[2]); if (!exc.occurred) { printf("result = %d\n", result); } else { puts(exc.message); puts("unknown result"); } return 0; }

二返戻値法における実装の特徴 可搬性が高い 高級言語で明示的に例外パスを記述 遅い 正常終了でも例外検査が必要

setjmp法における実装 (概要) setjmp/longjmpを用いて大域脱出 そもそも、setjmpって有名? 例外情報は別に保管される そもそも、setjmpって有名?

setjmp/longjmpとは (1) longjmpを呼ぶとsetjmpへワープ result = 0 begin jump() 08: int main(int argc, char **argv) { 09: int result = setjmp(jmp); 10: printf("result = %d\n", result); 11: if (result == 0) 12: jump(); 13: return 0; 14: } 16: void jump() { 17: puts("begin jump()"); 18: longjmp(jmp, 6502); 19: puts("end jump()"); 20: } main:09 int result = setjmp(jmp); main:10 printf("result = %d\n", ); main:11 if (result == 0) main:12 jump(); jump:17 puts("begin jump()"); jump:18 longjmp(jmp, 6502); main:10 printf("result = %d\n",…); main:11 if (result == 0) main:13 return 0; result = 0 begin jump() result = 6502

setjmp/longjmpとは (2) setjmpの実装 longjmpの実装 一部、volatileでないレジスタは消失 その時点のレジスタを保存する 最初に呼ばれたときには0を返す longjmpの実装 setjmpで保存したレジスタを復帰 PCやスタックフレーム(SP, FP)なども巻き戻す setjmpの結果として引数の値を返す 一部、volatileでないレジスタは消失

setjmp法における実装 (catch) try~の部分でif (setjmp(…) == 0) int main(int argc, char **argv) { if (setjmp(jmp) == 0) { int result = add(argv[1], argv[2]); printf("result = %d\n", result); } else { puts(message); puts("unknown result"); } return 0; }

setjmp法における実装 (throws) longjmpで大域脱出するのでなにもしない スキップする int add(const char *a, const char *b) { return parseInt(a) + parseInt(b); }

setjmp法における実装 (throw) 値だけ準備してlongjmpすればよい 第2引数で例外の番号を指定できる int parseInt(const char *s) { char *end; int a = strtol(s, &end, 10); if (*end != '\0') { sprintf(message, "parse error: %s", s); longjmp(jmp, 1); } return a; }

setjmp法における実装の特徴 可搬性が高い コンパイラが混乱する 遅い 大抵のC言語はsetjmpをサポートしている volatileの指定がない変数は消失するかも コンパイラによってはsetjmpがあると最適化抑止 遅い tryの度にレジスタを退避する

表引き法における実装 (概要) プログラムは次のものを含む 実行可能な部分 (本来のプログラム) 例外表 ------ ------------ ----- ------ ------------ ----- ------ ------------ ----- ------ ------------ ----- ------ ------------ ----- ------ ------------ -----

表引き法に必要な情報 適用範囲 着陸地点 レジスタ情報 その他 どこで発生した例外に対応するか どのアドレスにジャンプするか(catchの位置) レジスタ情報 Spillしたレジスタはどこに格納されているか その他 どの種類の例外をキャッチできるか、など

表引き法における実装 (throw) 例外を発生させ、キャッチするフレームを探す 自分と呼び出し元の表を参照 キャッチするフレームまで巻き戻す ------ catch(…) { ---- } ------ ------------ ----- ------ raise Exception ----- ------ ------------ ----- ------ ------------ ----- ------ ------------ -----

表引き法における実装 (throws) 表に「例外を通過させる」ことを記述する 何も書かないとthrowsになる実装もある リソースの解放が必要になる場合が多いので、通常はリソース解放コードに着地させる Frap From Trap To Type Landing Point try_begin try_end <any> unwind

表引き法における実装 (catch) 表に「例外をキャッチする」ことを記述する キャッチできる型、ハンドラのアドレスを記述 実装によってはキャッチできる型を記述しない Frap From Trap To Type Landing Point try_begin try_end Exception catch1 Error catch2 <any> <unwind>

表引き法における実装の特徴 高速 可搬性が低い 正常処理時にコストが掛からない ライブラリ/アーキテクチャごとに仕様が異なる (通常は)高級言語レベルで記述できない

gcjの例外 基本的には表引き法を使う 言語ごとに別の記法を取る 高度な記述ができる C++/gccも一部同じ機構を利用 スピルされたレジスタの復帰 インライン関数の擬似フレーム記述

gcjの例外情報 LSDA (Language Specific Data Address) トラップ範囲、着地地点、トラップ型のテーブル FDE (Frame Description Entry) 構築されたフレームに関する情報 退避されたレジスタなどが保存されている位置 詳しくは後述 CIE (Common Information Entry) 幾つかのFDEに共通する情報 FDEと同じような記述もできる

LSDAの情報 Header Call Site Table Action Table Trap Type Table キャッチ開始位置, 範囲, 着地地点 使用するAction Tableのエントリ Action Table Trap Type Tableのエントリを解釈する順序 Trap Type Table キャッチする型の情報

LSDAの記述 例外処理のサンプルプログラム.doc 図 11. bridge関数本体 (i386 - #1) 図 18. LSDAの差分 (i386 - #2) 図 24. LSDA (SPARC - #1) 図 30. LSDAの差分 (SPARC - #2)

CIEの情報 ヘッダ 拡張情報 フレーム情報 (CFA) 使用する拡張情報 コードの整列単位 (i386=1) 戻り値の擬似レジスタ番号 (i386=%eip(8)) 拡張情報 フレーム情報 (CFA) 関数開始時のスタックポインタ、リターンアドレス スタックは上方向に伸びていくので不の値になる

CIEの記述 例外処理のサンプルプログラム.doc 図 13. CIE (i386 - #1) 図 25. CIE (SPARC - #1)

FDEの情報 ヘッダ フレーム情報 (CFA) このFDEを使用する関数の範囲 対応するCIEの位置 対応するLSDAの位置 退避されたレジスタなど、全ての情報

FDEの記述 例外処理のサンプルプログラム.doc 図 14. FDE (i386 - #1) 図 26. FDE (SPARC - #2)

CFA (Canonical Frame Address) フレーム内のレジスタの位置を記述する レジスタごとに擬似レジスタ番号が振られ、それらがフレーム内のどこにあるか記述できる 例外が発生したPCごとに細かく指定できる 記述用のインタープリタが内蔵されている

CFAの記述能力 レジスタの位置を記憶するインタープリタ 現在のPCにおける、スピルされたレジスタの退避先を記述できる // 古いフレームポインタを退避した以降ならば advanve_loc4 .LbridgePrologue1 // フレームアドレスの位置は offset(8) def_cfa_offset offset=8 // レジスタebpをoffset(2)へ退避 offset reg=%ebp(5) offset=2 // プロローグ終了後 advanve_loc4 .LbridgeBody // フレームアドレスの位置は レジスタ%ebp内 def_cfa_register reg=%ebp(5)

資料 http://vtable.rat.cis.k.hosei.ac.jp/nakata/ 解析>例外処理 報告資料 libgcjを用いた例外処理に関する報告.doc 例外処理のサンプルプログラム.doc

二返戻値法ブリッジ (1) 表引き法はコンパイラやアーキテクチャに依存するため、実装が困難 それでも高速に実行できるので利用されている 表引き法のコンパイラを二返戻値法に変換する方法を紹介

二返戻値法ブリッジ (2) 常に例外をハンドルして、第二値として返せばよい ただしThread Local Storageを利用すること public Object bridge(Method m, Object obj, Object[] args) { try { return m.invoke(args); } catch (Throwable t) { exc.occurred = t; return null; } }

二返戻値法ブリッジ (3) メソッドを呼び出す場合は必ずブリッジ経由 戻ったら必ず第二値の検査 // 実際にはJavaではこの書き方はできない Object result = bridge( &Hoge.main, null, new String[]{}); if (exc.occurred != null) { // 例外処理 }