SlideShare une entreprise Scribd logo
1  sur  26
言語処理系入門
第 10 回:コンパイラ III :コード生成,実
行時ライブラリ, GC
2010 年 1 月 8 日(金)
服部 健太
コンパイラのバックエンド
ソース
プログラム 字句・構文解析 型検査 CPS 変換
Cps.convTyping.checkparse
クロージャ変換コード生成
目的
コード
実行時
ライブラリ
中間言語
抽象構文木
GC など実行時に必要な処理
実行時にロード・リンクされる
C 言語で実装されることが多い
C 言語,アセンブリコード,
VM の中間言語(バイトコード) etc 今日のトピックス
2010/1/8 2言語処理系入門 10
クロージャ変換した後
 K ::= def x1 = E1 and … and xn = En
 | let x1 = E1 and … and xn = En in K
 | let rec x1 = E1 and … and xn = En in K
 | if V then K1 else K2
 | case V of l1 -> K1 | … | ln -> Kn
 | V (V1, … ,Vn)
 E ::= V
 |{V1;…; Vn }
 | code f (x1,…,xn) = K in E
 | V#l | V1#l <- V2
 | op(V1, … ,Vn)
 V ::= c | x∈Var
 l ∈ Nat
大域変数の定義
2010/1/8 3言語処理系入門 10
コード生成の前処理
 let rec の除去
 let 式とフィールド更新の組み合わせに変換する
[[let rec x = { …, li = x,… } in E]] ⇒
let x = { …, li = null,… }
in let _ = x#i<-x in E
 レコード生成,フィールド参照・更新をプリミティブ演算に変
換
[[{V1,…, Vn}]]  ⇒
let r = record(n) in
let _ = setfld(r,1,V1) and … _ = setfld(r,n,Vn)
in r
 code のリフトアップ
 式の中に散らばった code 定義を抜き出して集める
 残りの式は,最初に実行される code の本体となる
2010/1/8 4言語処理系入門 10
コード生成の元言語
 C ::= code f (x1,…,xn) = K
 K ::= def x1 = E1 and … and xn = En
 | let x1 = E1 and … and xn = En in K
 | if V then K1 else K2
 | case V of l1 -> K1 | … | ln -> Kn
 | V (V1, … ,Vn)
 E ::= V
 | op(V1, … ,Vn)
 V ::= c | x∈Var
 l ∈ Nat
2010/1/8 5言語処理系入門 10
末尾呼び出しの処理
 CPS では,関数呼び出しはすべて末尾呼び出し
 これをそのまま C 言語の関数呼び出しに変換すると,
いずれスタックオーバーフローとなりうまくいかない
 解決方法
 ラベルと goto 文を使う
 switch 文を使う
 ディスパッチャから関数を呼び出す( Trampoline ス
タイル)
code f(x) =
…
g(x’)
code g(y) =
…
h(y’)
code h(z) =
…
j(z’)
2010/1/8 6言語処理系入門 10
Trampoline Style
 ディスパッチャの構造
void dispatch(func_t f) {
while ((f = f()) != NULL);
}
 f は関数ポインタ
 f を呼び出すと次に実行すべき関数のポインタを
返す
void *some_func(void) {
…
return next_func;
}
2010/1/8 7言語処理系入門 10
コード生成(1)
 変換関数
 [[ ・ ]] は変換元の式 Kclosure と環境 ρ を受け取り, C 言語の
コードを出力する
 環境 ρ は,変数からその変数に割り当てられたインデック
スを返す関数
 変数,定数
 [[x]]ρ⇒
locals[ρ(x)] x DOM(ρ)∈
x otherwise
 [[n]]ρ⇒ CONST_INT(n) n∈Integer
 [[b]]ρ⇒ CONST_BOOL(b) b∈{true,false}
 プリミティブ演算子適用
 [[op(V1,…, Vn)]]ρ ⇒ op([[V1]]ρ,…,[[Vn]]ρ)
2010/1/8 8言語処理系入門 10
コード生成(2)
 def 式
 大域変数としてそのまま使用する
[[def x1 = E1 and … xn = En]]ρ ⇒
x1 = [[E1]]ρ;
…
xn = [[En]]ρ;
 let 式
 局所変数の空いてる場所に代入していく
[[let x1 = E1 and … xn = En in K]]ρ ⇒
locals[l1] = [[E1]]ρ;
…
locals[ln] = [[En]]ρ;
[[K]]ρ{x1→l1,x2→l2,…,xn→ln}
where li = ρ.size + i - 1 for each 1≦i≦n
2010/1/8 9言語処理系入門 10
コード生成(3)
 if 式
[[if V then K1 else K2]]ρ ⇒
if ([[V]]ρ == CONST_TRUE)
{ [[K1]]ρ } else { [[K2]]ρ }
 case 式
[[case V of l1 -> K1 | … | ln -> Kn]]ρ ⇒
switch (GET_LABEL([[V]]ρ)) {
case l1: { [[K1]]ρ }
…
case ln: { [[Kn]]ρ }
}
2010/1/8 10言語処理系入門 10
コード生成(4)
 関数定義
[[code f (x1,…,xn) = K]]φ ⇒
  void* f(void) {
locals[0] = args[0]; …
locals[n-1] = args[n-1];
  [[K]]{x1→0,…,xn→n-1}
}
 関数呼び出し
[[V(V1,…,Vn)]]ρ ⇒
args[0] = [[V1]]ρ; …
args[n-1] = [[Vn]]ρ;
return [[V]]ρ;
関数に与える引数を args にセット
受け取った引数を locals にセット
2010/1/8 11言語処理系入門 10
生成コードの例
#include <tfunlc.h>
obj_t __g_fact__;
static void *__t16__(void);
static void *__t23__(void);
static void *__t19__(void);
static obj_t args[] __attribute__((unused));
static obj_t locals[] __attribute__((unused));
static obj_t *globals[] __attribute__((unused));
static void *__t16__(void) {
locals[0] = args[0];
locals[1] = args[1];
locals[2] = args[2];
locals[3] = OP_GETFLD(locals[0],CONST_LBL(1));
locals[4] = OP_EQ(locals[2],CONST_INT(0));
locals[5] = OP_RECORD(CONST_LBL(2));
OP_SETFLD(locals[5],CONST_LBL(0),__t23__);
OP_SETFLD(locals[5],CONST_LBL(1),locals[1]);
if (locals[4] == CONST_TRUE) {
locals[6] = OP_GETFLD(locals[5],CONST_LBL(0));
args[0] = locals[5];
args[1] = CONST_INT(1);
return locals[6];
} else {
locals[6] = OP_SUB(locals[2],CONST_INT(1));
locals[7] = OP_RECORD(CONST_LBL(3));
OP_SETFLD(locals[7],CONST_LBL(0),__t19__);
OP_SETFLD(locals[7],CONST_LBL(1),locals[5]);
OP_SETFLD(locals[7],CONST_LBL(2),locals[2]);
locals[8] = OP_GETFLD(locals[3],CONST_LBL(0));
args[0] = locals[3];
args[1] = locals[7];
args[2] = locals[6];
return locals[8];
}
return (void*)HALT;
}
static void *__t23__(void) {
locals[0] = args[0];
locals[1] = args[1];
locals[2] = OP_GETFLD(locals[0],CONST_LBL(1));
locals[3] = OP_GETFLD(locals[2],CONST_LBL(0));
args[0] = locals[2];
args[1] = locals[1];
return locals[3];
}
static void *__t19__(void) {
locals[0] = args[0];
locals[1] = args[1];
locals[2] = OP_GETFLD(locals[0],CONST_LBL(2));
locals[3] = OP_GETFLD(locals[0],CONST_LBL(1));
locals[4] = OP_MUL(locals[2],locals[1]);
locals[5] = OP_GETFLD(locals[3],CONST_LBL(0));
args[0] = locals[3];
args[1] = locals[4];
return locals[5];
}
static void *__def_0__(void) {
locals[0] = OP_RECORD(CONST_LBL(2));
OP_SETFLD(locals[0],CONST_LBL(0),__t16__);
OP_SETFLD(locals[0],CONST_LBL(1),locals[0]);
__g_fact__ = locals[0];
return (void*)HALT;
}
int main() {
globals[0] = &__g_fact__;
gc_init(globals, 1, locals, 9);
exn_init();
if (tfl_run(__def_0__) < 0) return -1;
return 0;
}
static obj_t args[3];
static obj_t locals[9];
static obj_t *globals[1];
2010/1/8 12言語処理系入門 10
実行時ライブラリ
 以下のように,実行時に必要な定義をあらかじめ C
言語でライブラリとして実装しておく
 strcat, print_int, など一部のプリミティブ演算子の実装
 デフォルトの例外ハンドラ定義
 ディスパッチャ定義
 GC
 etc…
 生成したコードと実行時ライブラリをリンクするこ
とで実行ファイルが出来上がる.
 サンプルプログラムでは, rtlib/ の下に実行時ライ
ブラリのソースがある
2010/1/8 13言語処理系入門 10
ゴミ集め( Garbage Collection )
 使われないオブジェクトを回収する
 「使われない」の定義
 ルート集合から到達できないオブジェクト
 ルート集合={レジスタ,大域変数,スタック上の局所変数, etc }
 代表的な手法
 参照カウント
 各オブジェクトが被参照数を表すカウンタを保持
 被参照数が 0 になったら解放される
 マーク&スイープ
 ゴミ集め時にルート集合からオブジェクトを辿って,印をつけておく
 ヒープ領域をスキャンし,印のついていないオブジェクトを回収する
 コピー GC
 ヒープを 2 つの領域に分割し,片方だけ使う.
 一方の領域が満杯になったら,ルート集合からオブジェクトを辿りなが
ら,もう片方の領域にコピーしていく.
2010/1/8 14言語処理系入門 10
オブジェクト(ポインタ)の識別
方法
 GC で回収されるもの
 文字列バッファ,レコード
 GC で回収されないもの
 (ヒープに割り付けられないもの)
 整数値,真偽値, Unit
 文字列定数
 ポインタと非ポインタをどうやって識別するか?
 Exact 方式
 下位 1 ビット分をタグとして使用する
 Conservative GC
 それっぽいものはすべてポインタとみなす
ヒープ領域x: 123
truey:
z:
“hello”
w:
5 true
レジスタ等
25 “b”
2010/1/8 15言語処理系入門 10
データ表現
 基本型
 Unit,Bool,Int,etc.
 下位 1 ビット分をタグとして使用
 レコード型
 複数のデータを含むオブジェクト
 ヒープに確保される
 バッファ型
 可変文字列に使用
 ヒープに確保される
int
sz
sz “hello,worldn”
bool
2010/1/8 16言語処理系入門 10
Cheney’s Algorithm
 エレガントなコピー GC のアルゴリズム
 余分な記憶領域が不要
 free と scan の 2 つのポインタだけで OK
 処理の概要
 オブジェクトを移動先の空き領域 (free ポインタの指す先 )
にコピーし, free ポインタを先に進める
 コピー先のオブジェクトの中をスキャンし,ポインタが含
まていたら,その先のオブジェクトをチェックし, scan
ポインタを進める
 もし,まだ移動してなかったら,そのオブジェクトを移動し
,新しいポインタをセット
 すでに移動済みなら,移動先のポインタをセット
 scan ポインタが free ポインタに追いついたら終了
2010/1/8 17言語処理系入門 10
Cheney’s Algorithm の動作
A
B C
D E F G
Fromspace
Tospace
free
scan
2010/1/8 18言語処理系入門 10
Cheney’s Algorithm の動作
A’A
B C
D E F G
Fromspace
Tospace
free
scan
A’
移動先のアド
レスを入れて
おく
2010/1/8 19言語処理系入門 10
Cheney’s Algorithm の動作
A’
B’ C’
A
B C
D E F G
Fromspace
Tospace
free
scan
A’
B’ C’
2010/1/8 20言語処理系入門 10
Cheney’s Algorithm の動作
A’
B’
D’ E’
C’
F’ G’
A
B C
D E F G
Fromspace
Tospace
free
scan
A’
B’ C’ D’ E’ F’
G’
2010/1/8 21言語処理系入門 10
Cheney’s Algorithm の動作
A’
B’
D’ E’
C’
F’ G’
A
B C
D E F G
Fromspace
Tospace
free
scan
A’
B’ C’ D’ E’ F’
G’
2010/1/8 22言語処理系入門 10
Cheney’s Algorithm の実装(1)
flip() =
to_space, from_space = from_space, to_space;
heap_top = to_space + space_size;
scan = free = to_space;
foreach (r in route_set)
r = copy(r);
while (scan < free) {
sz = size(scan);
for (p = scan + 1; p < scan + sz; p++)
*p = copy(*p);
scan += sz;
}
2010/1/8 23言語処理系入門 10
Cheney’s Algorithm の実装(2)
copy(p) =
if (is_noptr(p)) return p;
if (is_forwarded(p))
return forward_address(p);
else
addr = free;
sz = size(p);
memcpy(heap_free,p,sizeof(obj_t)*sz);
free += sz;
forward_address(p) = addr;
return addr;
2010/1/8 24言語処理系入門 10
本講座で触れられなかった話題
 モジュールシステムと分割コンパイル
 トップレベルの(大域)環境を分割して扱えるように
する
 パターンマッチコンパイル
 複雑なパターンマッチ式を,単純な case 式の組み合
わせに変換する
 エスケープ解析
 変数の指し示すオブジェクトがその変数の静的スコー
プを抜けて,生存しうるかどうかを解析する
 型付き中間言語
 中間言語にも型情報を持たせることで,生成コードを
最適化しやすくなる
 その他たくさん...
2010/1/8 25言語処理系入門 10
演習課題
 今週のサンプルプログラムを動かしてみよ
 簡単なプログラムをコンパイルし,生成され
たコードを確かめよ
 以下のようなプリミティブ演算子を追加せよ
 read_line
 int_to_str, str_to_int, etc.
 文字列が適切な形式でなかったら例外を投げる
2010/1/8 26言語処理系入門 10

Contenu connexe

Tendances

Polyphony IO まとめ
Polyphony IO まとめPolyphony IO まとめ
Polyphony IO まとめryos36
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプKohsuke Yuasa
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11えぴ 福田
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性Hibiki Yamashiro
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門natrium11321
 
おいしいLisp
おいしいLispおいしいLisp
おいしいLispKent Ohashi
 
Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」Nagi Teramo
 
GC in C++0x
GC in C++0xGC in C++0x
GC in C++0xyak1ex
 
C++ lecture-0
C++ lecture-0C++ lecture-0
C++ lecture-0sunaemon
 
C++入門?
C++入門?C++入門?
C++入門?tsudaa
 
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesBoost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesShintarou Okada
 
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Yuto Takei
 
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Atsuo Ishimoto
 
Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討Shinya Takamaeda-Y
 
Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)Kohta Ishikawa
 

Tendances (20)

Polyphony IO まとめ
Polyphony IO まとめPolyphony IO まとめ
Polyphony IO まとめ
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
Emcjp item33,34
Emcjp item33,34Emcjp item33,34
Emcjp item33,34
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
 
C++11
C++11C++11
C++11
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
Functional Way
Functional WayFunctional Way
Functional Way
 
おいしいLisp
おいしいLispおいしいLisp
おいしいLisp
 
Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」Tokyo.R 白熱教室「これからのRcppの話をしよう」
Tokyo.R 白熱教室「これからのRcppの話をしよう」
 
GC in C++0x
GC in C++0xGC in C++0x
GC in C++0x
 
C++ lecture-0
C++ lecture-0C++ lecture-0
C++ lecture-0
 
C++入門?
C++入門?C++入門?
C++入門?
 
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core GuidelinesBoost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
Boost.勉強会#19東京 Effective Modern C++とC++ Core Guidelines
 
Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)Hello Dark-Side C# (Part. 1)
Hello Dark-Side C# (Part. 1)
 
Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料Python 3.6 リリースパーティー 発表資料
Python 3.6 リリースパーティー 発表資料
 
Emcjp item21
Emcjp item21Emcjp item21
Emcjp item21
 
Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討Pythonを用いた高水準ハードウェア設計環境の検討
Pythonを用いた高水準ハードウェア設計環境の検討
 
Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)Rでisomap(多様体学習のはなし)
Rでisomap(多様体学習のはなし)
 

Similaire à 言語処理系入門€10

Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Springanyakichi
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーmganeko
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61TATSUYA HAYAMIZU
 
第1回勉強会スライド
第1回勉強会スライド第1回勉強会スライド
第1回勉強会スライドkoturn 0;
 
言語処理系入門€8
言語処理系入門€8言語処理系入門€8
言語処理系入門€8Kenta Hattori
 
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)Shin-ya Koga
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)啓 小笠原
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#信之 岩永
 
20130316 プログラミング言語Go
20130316 プログラミング言語Go20130316 プログラミング言語Go
20130316 プログラミング言語GoYoshifumi Yamaguchi
 
C# linq入門 意図編
C# linq入門 意図編C# linq入門 意図編
C# linq入門 意図編Fujio Kojima
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 

Similaire à 言語処理系入門€10 (20)

C++14 Overview
C++14 OverviewC++14 Overview
C++14 Overview
 
C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
 
第1回勉強会スライド
第1回勉強会スライド第1回勉強会スライド
第1回勉強会スライド
 
言語処理系入門€8
言語処理系入門€8言語処理系入門€8
言語処理系入門€8
 
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
 
Coqでsprintf
CoqでsprintfCoqでsprintf
Coqでsprintf
 
20130316 プログラミング言語Go
20130316 プログラミング言語Go20130316 プログラミング言語Go
20130316 プログラミング言語Go
 
C# linq入門 意図編
C# linq入門 意図編C# linq入門 意図編
C# linq入門 意図編
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 

Plus de Kenta Hattori

オブジェクト指向入門2
オブジェクト指向入門2オブジェクト指向入門2
オブジェクト指向入門2Kenta Hattori
 
オブジェクト指向入門1
オブジェクト指向入門1オブジェクト指向入門1
オブジェクト指向入門1Kenta Hattori
 
オブジェクト指向入門10
オブジェクト指向入門10オブジェクト指向入門10
オブジェクト指向入門10Kenta Hattori
 
オブジェクト指向入門9
オブジェクト指向入門9オブジェクト指向入門9
オブジェクト指向入門9Kenta Hattori
 
オブジェクト指向入門8
オブジェクト指向入門8オブジェクト指向入門8
オブジェクト指向入門8Kenta Hattori
 
オブジェクト指向入門7
オブジェクト指向入門7オブジェクト指向入門7
オブジェクト指向入門7Kenta Hattori
 
オブジェクト指向入門6
オブジェクト指向入門6オブジェクト指向入門6
オブジェクト指向入門6Kenta Hattori
 
オブジェクト指向入門5
オブジェクト指向入門5オブジェクト指向入門5
オブジェクト指向入門5Kenta Hattori
 
オブジェクト指向入門4
オブジェクト指向入門4オブジェクト指向入門4
オブジェクト指向入門4Kenta Hattori
 
オブジェクト指向入門3
オブジェクト指向入門3オブジェクト指向入門3
オブジェクト指向入門3Kenta Hattori
 
ソフトウェア・テスト入門2
ソフトウェア・テスト入門2ソフトウェア・テスト入門2
ソフトウェア・テスト入門2Kenta Hattori
 
ソフトウェア・テスト入門1
ソフトウェア・テスト入門1ソフトウェア・テスト入門1
ソフトウェア・テスト入門1Kenta Hattori
 
ソフトウェア・テスト入門8
ソフトウェア・テスト入門8ソフトウェア・テスト入門8
ソフトウェア・テスト入門8Kenta Hattori
 
ソフトウェア・テスト入門7
ソフトウェア・テスト入門7ソフトウェア・テスト入門7
ソフトウェア・テスト入門7Kenta Hattori
 
ソフトウェア・テスト入門6
ソフトウェア・テスト入門6ソフトウェア・テスト入門6
ソフトウェア・テスト入門6Kenta Hattori
 
ソフトウェア・テスト入門5
ソフトウェア・テスト入門5ソフトウェア・テスト入門5
ソフトウェア・テスト入門5Kenta Hattori
 
ソフトウェア・テスト入門4
ソフトウェア・テスト入門4ソフトウェア・テスト入門4
ソフトウェア・テスト入門4Kenta Hattori
 
ソフトウェア・テスト入門3
ソフトウェア・テスト入門3ソフトウェア・テスト入門3
ソフトウェア・テスト入門3Kenta Hattori
 
アルゴリズムとデータ構造15
アルゴリズムとデータ構造15アルゴリズムとデータ構造15
アルゴリズムとデータ構造15Kenta Hattori
 
アルゴリズムとデータ構造14
アルゴリズムとデータ構造14アルゴリズムとデータ構造14
アルゴリズムとデータ構造14Kenta Hattori
 

Plus de Kenta Hattori (20)

オブジェクト指向入門2
オブジェクト指向入門2オブジェクト指向入門2
オブジェクト指向入門2
 
オブジェクト指向入門1
オブジェクト指向入門1オブジェクト指向入門1
オブジェクト指向入門1
 
オブジェクト指向入門10
オブジェクト指向入門10オブジェクト指向入門10
オブジェクト指向入門10
 
オブジェクト指向入門9
オブジェクト指向入門9オブジェクト指向入門9
オブジェクト指向入門9
 
オブジェクト指向入門8
オブジェクト指向入門8オブジェクト指向入門8
オブジェクト指向入門8
 
オブジェクト指向入門7
オブジェクト指向入門7オブジェクト指向入門7
オブジェクト指向入門7
 
オブジェクト指向入門6
オブジェクト指向入門6オブジェクト指向入門6
オブジェクト指向入門6
 
オブジェクト指向入門5
オブジェクト指向入門5オブジェクト指向入門5
オブジェクト指向入門5
 
オブジェクト指向入門4
オブジェクト指向入門4オブジェクト指向入門4
オブジェクト指向入門4
 
オブジェクト指向入門3
オブジェクト指向入門3オブジェクト指向入門3
オブジェクト指向入門3
 
ソフトウェア・テスト入門2
ソフトウェア・テスト入門2ソフトウェア・テスト入門2
ソフトウェア・テスト入門2
 
ソフトウェア・テスト入門1
ソフトウェア・テスト入門1ソフトウェア・テスト入門1
ソフトウェア・テスト入門1
 
ソフトウェア・テスト入門8
ソフトウェア・テスト入門8ソフトウェア・テスト入門8
ソフトウェア・テスト入門8
 
ソフトウェア・テスト入門7
ソフトウェア・テスト入門7ソフトウェア・テスト入門7
ソフトウェア・テスト入門7
 
ソフトウェア・テスト入門6
ソフトウェア・テスト入門6ソフトウェア・テスト入門6
ソフトウェア・テスト入門6
 
ソフトウェア・テスト入門5
ソフトウェア・テスト入門5ソフトウェア・テスト入門5
ソフトウェア・テスト入門5
 
ソフトウェア・テスト入門4
ソフトウェア・テスト入門4ソフトウェア・テスト入門4
ソフトウェア・テスト入門4
 
ソフトウェア・テスト入門3
ソフトウェア・テスト入門3ソフトウェア・テスト入門3
ソフトウェア・テスト入門3
 
アルゴリズムとデータ構造15
アルゴリズムとデータ構造15アルゴリズムとデータ構造15
アルゴリズムとデータ構造15
 
アルゴリズムとデータ構造14
アルゴリズムとデータ構造14アルゴリズムとデータ構造14
アルゴリズムとデータ構造14
 

言語処理系入門€10

  • 1. 言語処理系入門 第 10 回:コンパイラ III :コード生成,実 行時ライブラリ, GC 2010 年 1 月 8 日(金) 服部 健太
  • 2. コンパイラのバックエンド ソース プログラム 字句・構文解析 型検査 CPS 変換 Cps.convTyping.checkparse クロージャ変換コード生成 目的 コード 実行時 ライブラリ 中間言語 抽象構文木 GC など実行時に必要な処理 実行時にロード・リンクされる C 言語で実装されることが多い C 言語,アセンブリコード, VM の中間言語(バイトコード) etc 今日のトピックス 2010/1/8 2言語処理系入門 10
  • 3. クロージャ変換した後  K ::= def x1 = E1 and … and xn = En  | let x1 = E1 and … and xn = En in K  | let rec x1 = E1 and … and xn = En in K  | if V then K1 else K2  | case V of l1 -> K1 | … | ln -> Kn  | V (V1, … ,Vn)  E ::= V  |{V1;…; Vn }  | code f (x1,…,xn) = K in E  | V#l | V1#l <- V2  | op(V1, … ,Vn)  V ::= c | x∈Var  l ∈ Nat 大域変数の定義 2010/1/8 3言語処理系入門 10
  • 4. コード生成の前処理  let rec の除去  let 式とフィールド更新の組み合わせに変換する [[let rec x = { …, li = x,… } in E]] ⇒ let x = { …, li = null,… } in let _ = x#i<-x in E  レコード生成,フィールド参照・更新をプリミティブ演算に変 換 [[{V1,…, Vn}]]  ⇒ let r = record(n) in let _ = setfld(r,1,V1) and … _ = setfld(r,n,Vn) in r  code のリフトアップ  式の中に散らばった code 定義を抜き出して集める  残りの式は,最初に実行される code の本体となる 2010/1/8 4言語処理系入門 10
  • 5. コード生成の元言語  C ::= code f (x1,…,xn) = K  K ::= def x1 = E1 and … and xn = En  | let x1 = E1 and … and xn = En in K  | if V then K1 else K2  | case V of l1 -> K1 | … | ln -> Kn  | V (V1, … ,Vn)  E ::= V  | op(V1, … ,Vn)  V ::= c | x∈Var  l ∈ Nat 2010/1/8 5言語処理系入門 10
  • 6. 末尾呼び出しの処理  CPS では,関数呼び出しはすべて末尾呼び出し  これをそのまま C 言語の関数呼び出しに変換すると, いずれスタックオーバーフローとなりうまくいかない  解決方法  ラベルと goto 文を使う  switch 文を使う  ディスパッチャから関数を呼び出す( Trampoline ス タイル) code f(x) = … g(x’) code g(y) = … h(y’) code h(z) = … j(z’) 2010/1/8 6言語処理系入門 10
  • 7. Trampoline Style  ディスパッチャの構造 void dispatch(func_t f) { while ((f = f()) != NULL); }  f は関数ポインタ  f を呼び出すと次に実行すべき関数のポインタを 返す void *some_func(void) { … return next_func; } 2010/1/8 7言語処理系入門 10
  • 8. コード生成(1)  変換関数  [[ ・ ]] は変換元の式 Kclosure と環境 ρ を受け取り, C 言語の コードを出力する  環境 ρ は,変数からその変数に割り当てられたインデック スを返す関数  変数,定数  [[x]]ρ⇒ locals[ρ(x)] x DOM(ρ)∈ x otherwise  [[n]]ρ⇒ CONST_INT(n) n∈Integer  [[b]]ρ⇒ CONST_BOOL(b) b∈{true,false}  プリミティブ演算子適用  [[op(V1,…, Vn)]]ρ ⇒ op([[V1]]ρ,…,[[Vn]]ρ) 2010/1/8 8言語処理系入門 10
  • 9. コード生成(2)  def 式  大域変数としてそのまま使用する [[def x1 = E1 and … xn = En]]ρ ⇒ x1 = [[E1]]ρ; … xn = [[En]]ρ;  let 式  局所変数の空いてる場所に代入していく [[let x1 = E1 and … xn = En in K]]ρ ⇒ locals[l1] = [[E1]]ρ; … locals[ln] = [[En]]ρ; [[K]]ρ{x1→l1,x2→l2,…,xn→ln} where li = ρ.size + i - 1 for each 1≦i≦n 2010/1/8 9言語処理系入門 10
  • 10. コード生成(3)  if 式 [[if V then K1 else K2]]ρ ⇒ if ([[V]]ρ == CONST_TRUE) { [[K1]]ρ } else { [[K2]]ρ }  case 式 [[case V of l1 -> K1 | … | ln -> Kn]]ρ ⇒ switch (GET_LABEL([[V]]ρ)) { case l1: { [[K1]]ρ } … case ln: { [[Kn]]ρ } } 2010/1/8 10言語処理系入門 10
  • 11. コード生成(4)  関数定義 [[code f (x1,…,xn) = K]]φ ⇒   void* f(void) { locals[0] = args[0]; … locals[n-1] = args[n-1];   [[K]]{x1→0,…,xn→n-1} }  関数呼び出し [[V(V1,…,Vn)]]ρ ⇒ args[0] = [[V1]]ρ; … args[n-1] = [[Vn]]ρ; return [[V]]ρ; 関数に与える引数を args にセット 受け取った引数を locals にセット 2010/1/8 11言語処理系入門 10
  • 12. 生成コードの例 #include <tfunlc.h> obj_t __g_fact__; static void *__t16__(void); static void *__t23__(void); static void *__t19__(void); static obj_t args[] __attribute__((unused)); static obj_t locals[] __attribute__((unused)); static obj_t *globals[] __attribute__((unused)); static void *__t16__(void) { locals[0] = args[0]; locals[1] = args[1]; locals[2] = args[2]; locals[3] = OP_GETFLD(locals[0],CONST_LBL(1)); locals[4] = OP_EQ(locals[2],CONST_INT(0)); locals[5] = OP_RECORD(CONST_LBL(2)); OP_SETFLD(locals[5],CONST_LBL(0),__t23__); OP_SETFLD(locals[5],CONST_LBL(1),locals[1]); if (locals[4] == CONST_TRUE) { locals[6] = OP_GETFLD(locals[5],CONST_LBL(0)); args[0] = locals[5]; args[1] = CONST_INT(1); return locals[6]; } else { locals[6] = OP_SUB(locals[2],CONST_INT(1)); locals[7] = OP_RECORD(CONST_LBL(3)); OP_SETFLD(locals[7],CONST_LBL(0),__t19__); OP_SETFLD(locals[7],CONST_LBL(1),locals[5]); OP_SETFLD(locals[7],CONST_LBL(2),locals[2]); locals[8] = OP_GETFLD(locals[3],CONST_LBL(0)); args[0] = locals[3]; args[1] = locals[7]; args[2] = locals[6]; return locals[8]; } return (void*)HALT; } static void *__t23__(void) { locals[0] = args[0]; locals[1] = args[1]; locals[2] = OP_GETFLD(locals[0],CONST_LBL(1)); locals[3] = OP_GETFLD(locals[2],CONST_LBL(0)); args[0] = locals[2]; args[1] = locals[1]; return locals[3]; } static void *__t19__(void) { locals[0] = args[0]; locals[1] = args[1]; locals[2] = OP_GETFLD(locals[0],CONST_LBL(2)); locals[3] = OP_GETFLD(locals[0],CONST_LBL(1)); locals[4] = OP_MUL(locals[2],locals[1]); locals[5] = OP_GETFLD(locals[3],CONST_LBL(0)); args[0] = locals[3]; args[1] = locals[4]; return locals[5]; } static void *__def_0__(void) { locals[0] = OP_RECORD(CONST_LBL(2)); OP_SETFLD(locals[0],CONST_LBL(0),__t16__); OP_SETFLD(locals[0],CONST_LBL(1),locals[0]); __g_fact__ = locals[0]; return (void*)HALT; } int main() { globals[0] = &__g_fact__; gc_init(globals, 1, locals, 9); exn_init(); if (tfl_run(__def_0__) < 0) return -1; return 0; } static obj_t args[3]; static obj_t locals[9]; static obj_t *globals[1]; 2010/1/8 12言語処理系入門 10
  • 13. 実行時ライブラリ  以下のように,実行時に必要な定義をあらかじめ C 言語でライブラリとして実装しておく  strcat, print_int, など一部のプリミティブ演算子の実装  デフォルトの例外ハンドラ定義  ディスパッチャ定義  GC  etc…  生成したコードと実行時ライブラリをリンクするこ とで実行ファイルが出来上がる.  サンプルプログラムでは, rtlib/ の下に実行時ライ ブラリのソースがある 2010/1/8 13言語処理系入門 10
  • 14. ゴミ集め( Garbage Collection )  使われないオブジェクトを回収する  「使われない」の定義  ルート集合から到達できないオブジェクト  ルート集合={レジスタ,大域変数,スタック上の局所変数, etc }  代表的な手法  参照カウント  各オブジェクトが被参照数を表すカウンタを保持  被参照数が 0 になったら解放される  マーク&スイープ  ゴミ集め時にルート集合からオブジェクトを辿って,印をつけておく  ヒープ領域をスキャンし,印のついていないオブジェクトを回収する  コピー GC  ヒープを 2 つの領域に分割し,片方だけ使う.  一方の領域が満杯になったら,ルート集合からオブジェクトを辿りなが ら,もう片方の領域にコピーしていく. 2010/1/8 14言語処理系入門 10
  • 15. オブジェクト(ポインタ)の識別 方法  GC で回収されるもの  文字列バッファ,レコード  GC で回収されないもの  (ヒープに割り付けられないもの)  整数値,真偽値, Unit  文字列定数  ポインタと非ポインタをどうやって識別するか?  Exact 方式  下位 1 ビット分をタグとして使用する  Conservative GC  それっぽいものはすべてポインタとみなす ヒープ領域x: 123 truey: z: “hello” w: 5 true レジスタ等 25 “b” 2010/1/8 15言語処理系入門 10
  • 16. データ表現  基本型  Unit,Bool,Int,etc.  下位 1 ビット分をタグとして使用  レコード型  複数のデータを含むオブジェクト  ヒープに確保される  バッファ型  可変文字列に使用  ヒープに確保される int sz sz “hello,worldn” bool 2010/1/8 16言語処理系入門 10
  • 17. Cheney’s Algorithm  エレガントなコピー GC のアルゴリズム  余分な記憶領域が不要  free と scan の 2 つのポインタだけで OK  処理の概要  オブジェクトを移動先の空き領域 (free ポインタの指す先 ) にコピーし, free ポインタを先に進める  コピー先のオブジェクトの中をスキャンし,ポインタが含 まていたら,その先のオブジェクトをチェックし, scan ポインタを進める  もし,まだ移動してなかったら,そのオブジェクトを移動し ,新しいポインタをセット  すでに移動済みなら,移動先のポインタをセット  scan ポインタが free ポインタに追いついたら終了 2010/1/8 17言語処理系入門 10
  • 18. Cheney’s Algorithm の動作 A B C D E F G Fromspace Tospace free scan 2010/1/8 18言語処理系入門 10
  • 19. Cheney’s Algorithm の動作 A’A B C D E F G Fromspace Tospace free scan A’ 移動先のアド レスを入れて おく 2010/1/8 19言語処理系入門 10
  • 20. Cheney’s Algorithm の動作 A’ B’ C’ A B C D E F G Fromspace Tospace free scan A’ B’ C’ 2010/1/8 20言語処理系入門 10
  • 21. Cheney’s Algorithm の動作 A’ B’ D’ E’ C’ F’ G’ A B C D E F G Fromspace Tospace free scan A’ B’ C’ D’ E’ F’ G’ 2010/1/8 21言語処理系入門 10
  • 22. Cheney’s Algorithm の動作 A’ B’ D’ E’ C’ F’ G’ A B C D E F G Fromspace Tospace free scan A’ B’ C’ D’ E’ F’ G’ 2010/1/8 22言語処理系入門 10
  • 23. Cheney’s Algorithm の実装(1) flip() = to_space, from_space = from_space, to_space; heap_top = to_space + space_size; scan = free = to_space; foreach (r in route_set) r = copy(r); while (scan < free) { sz = size(scan); for (p = scan + 1; p < scan + sz; p++) *p = copy(*p); scan += sz; } 2010/1/8 23言語処理系入門 10
  • 24. Cheney’s Algorithm の実装(2) copy(p) = if (is_noptr(p)) return p; if (is_forwarded(p)) return forward_address(p); else addr = free; sz = size(p); memcpy(heap_free,p,sizeof(obj_t)*sz); free += sz; forward_address(p) = addr; return addr; 2010/1/8 24言語処理系入門 10
  • 25. 本講座で触れられなかった話題  モジュールシステムと分割コンパイル  トップレベルの(大域)環境を分割して扱えるように する  パターンマッチコンパイル  複雑なパターンマッチ式を,単純な case 式の組み合 わせに変換する  エスケープ解析  変数の指し示すオブジェクトがその変数の静的スコー プを抜けて,生存しうるかどうかを解析する  型付き中間言語  中間言語にも型情報を持たせることで,生成コードを 最適化しやすくなる  その他たくさん... 2010/1/8 25言語処理系入門 10
  • 26. 演習課題  今週のサンプルプログラムを動かしてみよ  簡単なプログラムをコンパイルし,生成され たコードを確かめよ  以下のようなプリミティブ演算子を追加せよ  read_line  int_to_str, str_to_int, etc.  文字列が適切な形式でなかったら例外を投げる 2010/1/8 26言語処理系入門 10