GC in C++0x

28
GC in C++0x 2010/8/8 GC本読書会 新 康孝 yak_ex

Transcript of GC in C++0x

Page 1: GC in C++0x

GC in C++0x

2010/8/8 GC本読書会

新 康孝yak_ex

Page 2: GC in C++0x

自己紹介

氏名: 新 康孝 (あたらし やすたか) Twitter ID: yak_ex Web: http://yak3.myhome.cx:8080/junks

C++ / Perl が主戦場 某自動車部品メーカーから某自動車メーカーへ出向中 現在、仕事でコードに触れていない 競技プログラミング(TopCoder、Codeforces)で潤い補充

GC は「ど素人」

Page 3: GC in C++0x

渡る世間は GC ばかり

Google Code Jam 2010 Qualifier 使用言語

1位 C++ 4911 6位 Ruby 221

2位 Java 2762 7位 PHP 170

3位 Python 1459 8位 Perl 146

4位 C 751 9位 Haskell 118

5位 C# 648 10位 Pascal 95

Page 4: GC in C++0x

渡る世間は GC ばかり

Google Code Jam 2010 Qualifier 使用言語

黄色ハイライト=GC有り言語

1位 C++ 4911 6位 Ruby 221

2位 Java 2762 7位 PHP 170

3位 Python 1459 8位 Perl 146

4位 C 751 9位 Haskell 118

5位 C# 648 10位 Pascal 95

Page 5: GC in C++0x

渡る世間は GC ばかり

Google Code Jam 2010 Qualifier 使用言語

黄色ハイライト=GC有り言語

1位 C++ 4911 6位 Ruby 221

2位 Java 2762 7位 PHP 170

3位 Python 1459 8位 Perl 146

4位 C 751 9位 Haskell 118

5位 C# 648 10位 Pascal 95

超一線級言語でありながら GC 無し : C++は孤高

Page 6: GC in C++0x

C++は孤高

そんな C++ を支える C++er 達

Page 7: GC in C++0x

C++は孤高

そんな C++ を支える C++er 達

Page 8: GC in C++0x

C++は孤高

そんな C++ を支える C++er 達

Page 9: GC in C++0x

C++は孤高

そんな C++ を支える C++er 達

Page 10: GC in C++0x

C++は孤高

そんな C++ を支える C++er 達

Page 11: GC in C++0x

C++は孤高

そんな C++ を支える C++er 達

闇へ

の ん

軍た

団い

Page 12: GC in C++0x

マルチパラダイム変態言語C++

次期標準規格 C++ 0x では

Garbage Collection

and

Reachability-Based Leak Detection

Support for

Page 13: GC in C++0x

マルチパラダイム変態言語C++

次期標準規格 C++ 0x では

Minimal

Garbage Collection

and

Reachability-Based Leak Detection

Support for

Page 14: GC in C++0x

Minimal Support for GC 以下略

いくつかの概念

Traceable pointer object

Safely-derived pointer (value)

5つの関数

get_pointer_safety()

(un)declare_no_pointers()

(un)declare_reachable()

Page 15: GC in C++0x

いくつかの概念(1)

Traceable pointer object

ポインタobj

ポインタを格納するのに十分なサイズの整数obj

キャラクタ型の配列の一部分キャラクタ型だけな理由は恐らく strict aliasing rule

→ポインタ値が入っているかもしれないと処理系に認識してもらえるobject

=他の部分にはポインタ値が入っていない前提

Page 16: GC in C++0x

いくつかの概念(2)

Safely-derived pointer (value) ::operator new で返ってきた値 (例: new T)

Safely-derived pointer value に対する

逆参照→参照の結果 (例: &*p)

ポインタ値の well-defined な演算結果 (例: p+1)

ポインタ間の well-defined な変換結果(例: static_cast<void*>(p))

ポインタ・整数値間の reinterpret_cast による変換結果(例: reinterpret_cast<intptr_t>(p))

→::operator new で確保された領域でかつ有効であることが処理系から確実に追跡可能なポインタ値

Page 17: GC in C++0x

いくつかの概念(3)

Safely-derived pointer (value)

T *p = new T;intptr_t x = reinterpret_cast<intptr_t>(p) ^ 0x555a:T *q = reinterpret_cast<T*>(x ^ 0x555);T y = *q;

これは safely-derived pointer value

こっちは safely-derived pointer value ではない

これも safely-derived pointer value ではない!※値としては p と同じだが、結果ではなくて過程で判断

Page 18: GC in C++0x

Minimal Support for GC 以下略

いくつかの概念

Traceable pointer object

Safely-derived pointer (value)

5つの関数

get_pointer_safety()

(un)declare_no_pointers()

(un)declare_reachable()

Page 19: GC in C++0x

関数: get_pointer_safety()

処理系のポインタ安全性(pointer safety)を返す

relaxed:

preferred:

strict:

Safely-derived pointer であるかによって処理が変わらない=C++03相当※relaxed と preferred は処理系定義

preferred だと leak detector があったりするかもしれない

※VC2010 は relaxed 返して他の関数も何もしない

safely-derived pointer でないポインタ値(かつ後述の declare_reachable() が呼ばれていない値)を介して動的確保された領域を逆参照、解放すると未定義動作

Page 20: GC in C++0x

Strict pointer safety

Safely-derived pointer (value)

T *p = new T;intptr_t x = reinterpret_cast<intptr_t>(p) ^ 0x555a:T *q = reinterpret_cast<T*>(x ^ 0x555);T y = *q;

これは safely-derived pointer value

こっちは safely-derived pointer value ではない

これも safely-derived pointer value ではない!※値としては p と同じだが、結果ではなくて過程で判断

未定義動作

Page 21: GC in C++0x

関数: (un)declare_no_pointers()

void declare_no_pointers(char *p, size_t n);

void undeclare_no_pointers(char *p, size_t n);

指定された領域内にポインタ値がないことを指定 or 指定解除する

→GC のスキャン範囲を狭められる

Page 22: GC in C++0x

関数: (un)declare_reachable

void declare_reachable(void *p); safely-derived な pointer 値 p の参照先を

reachable だと宣言する

→参照先を GC 対象からはずす

template<class T>T* undeclare_reachable(T *p); 参照先が reachable な p に対して、

safely-derived な pointer 値(pと同じ値)を返す

→参照先が GC 対象に復帰する

(※返値が safely-derived なので有効である間はGCされない)

Page 23: GC in C++0x

(un)declare_reachable()の使い方

どうして必要なの?

T *p = new T;intptr_t x = reinterpret_cast<intptr_t>(p) ^ 0x555a:T *q = reinterpret_cast<T*>(x ^ 0x555);T y = *q;

これは safely-derived pointer value

こっちは safely-derived pointer value ではない

これも safely-derived pointer value ではない!※値としては p と同じだが、結果ではなくて過程で判断

未定義動作

「ラベル a: の位置で GC がかかると p の参照先が回収される」 ???

Page 24: GC in C++0x

(un)declare_reachable()の使い方

どうして必要なの?

T *p = new T;intptr_t x = reinterpret_cast<intptr_t>(p) ^ 0x555a:T *q = reinterpret_cast<T*>(x ^ 0x555);T y = *q;

これは safely-derived pointer value

こっちは safely-derived pointer value ではない

これも safely-derived pointer value ではない!※値としては p と同じだが、結果ではなくて過程で判断

未定義動作

「ラベル a: の位置で GC がかかると p の参照先が回収される」 問題は最適化

Page 25: GC in C++0x

(un)declare_reachable()の使い方

どうして必要なの?

T *p = new T;intptr_t x = reinterpret_cast<intptr_t>(p) ^ 0x555a:T *q = reinterpret_cast<T*>(x ^ 0x555);T y = *q;

「ラベル a: の位置で GC がかかると p の参照先が回収される」 問題は最適化

以降 p の値は使われない

※ p, x, q を同じレジスタに割り当てることが可能→ラベル a: の時点で p の値がどこにも存在しない→p の参照先 = q の参照先が GC の回収対象になる!!→*q で未定義動作

以降 x の値は使われない

Page 26: GC in C++0x

(un)declare_reachable()の使い方

C++0xでの正しいコード

T *p = new T;declare_reachable(p); // 偽装前に declare_reachable() を呼ぶintptr_t x = reinterpret_cast<intptr_t>(p) ^ 0x555a:// T z = *reinterpret_cast<T*>(x ^ 0x555); // 合法// 偽装終了時に undeclare_reachable() を呼ぶT *q = undeclare_reachable(reinterpret_cast<T*>(x ^ 0x555));T y = *q;

注※ declare_reachable した値と同じであれば safely-derived でなくとも逆参照が可能※ undeclare_reachable の引数は safely-derived でなくとも reachable であれば良い※ declare_reachable については「ポインタ値を偽装する」点が問題

a: で関数が別れている場合を考えれば最適化なしで議論は一緒

*p はreachable=GC対象外

Page 27: GC in C++0x

まとめ

C++0x では最小限の GC サポートがある Safely-derived pointer という概念= GC されていない生きているポインタ値

5 つの関数が追加

C++03相当でも規格合致(relaxed)

しばらくそれ以上の実装はでなさそう?

ポインタ値を偽装するコードはdeclare_reachable() / undeclare_reachable()を使って修正する必要がある