ちなみに今回ガベージコレクション自体は実装していません。worldガ・ベ・コ・レ、始まりますまずガベージコレクションについて。Wikipediaの記事を読むと良いです。Wikipediaプログラムによって確保されたメモリ領域は、しっかり解放を行わないと闇に飲まれるので良くないのですが、頻繁にメモリ領域を確保するプログラムを書くと、それらをしっかり解放させるのは大変だったりします。そこでガベージコレクションが登場します。ガベージコレクションはこの解放処理を自動で行なってくれるので、あるとそこそこ楽なわけです。ガベージコレクションのアルゴリズムは色々な種類がありますが、大方ルートを辿るような動作をします。ルートとは、メモリ領域を指し示す一番根本の部分のことを指します。このルートを辿っていくと、プログラム中で使われているメモリ領域が分かります。C++で、ルートはスタックとレジスタとします。メモリ領域を指し示すポインタの値は、スタックやレジスタに配置されます。スタックなどにはポインタ以外の値(整数値)も配置されるため、ガベージコレクションを行う際に正しくポインタだけの値をたどる事ができません。そこで、ポインタの値かどうか怪しいときは、その領域に触れない、または、その怪しい値もポインタの値とみなして生存判定をすることがあります。このような振る舞いのガベージコレクションを”保守的なガベージコレクション”といいます。そんな振る舞いのおかげで、プログラムは安全な方向に倒れます。(怪しいポインタや指すメモリ領域が勝手にいじられないため)このガベージコレクションは、言語や処理系のサポートを必要としないのが利点で、実装もしやすいのですが、メモリリークなどが発生する場合あります。一方で、ルート上の値がポインタかその他の値かを厳密に判別するガベージコレクションを”正確なガベージコレクション”といいます。この厳密に判別のためには、言語処理系のサポートが欠かせないため、実装がややこしくなります。処理系による実行時のサポートのため動作が遅くなることもあります。全ての領域を正確に回収することができるので、まあこっちを使いたいですよね。保守的なガベージコレクションであれば、LLVMなどのサポートは必要なく実装できる...。正確なガベージコレクションを実装したい!そこで、LLVMは、この正確なガベージコレクションを実装するためのサポートを提供してくれています。ヤッター!正確なガベージコレクションのためのサポートもう一度言いますが、ガベージコレクション自体は実装していません。つらい!とりあえず、ガベージコレクションのサポートのテストをリポジトリに置いてみました。GitHubLLVMは、正確なガベージコレクションに必要なルート上のオブジェクトを判別するために、以下の方法を提供しています。独自のコード生成pluginの読み込みShadowStackは、汎用なスタック上の情報を記録するための手法だそうです。ポータブルな実装な分、オーバーヘッドが結構大きいとか書いてありましたが、見た感じそんなことなさそう...このShadowStackは、LLVMの組み込みとあってデフォルトで利用できるため、手始めにはとても助かります。ShadowStackのオーバーヘッドが気になるなど、別の手法の実装を使いたい場合は、自身でLLVMのGCサポート用のクラスをC++で実装し、LLVMに読み込ませることで拡張が可能です。今回はShadowStackのみを利用してみます。ア...windowsの方は自力でなんとかして下さい...shadow_stack以下のファイルの説明です。entry.cppmain関数を定義してあります。この関数から、個々のサンプルのf()が呼び出されます。llvm_shadow_stack.cppLLVMのドキュメントを参考にしたShadowStack用の定義です。oreore_runtime.cpp俺々ランタイムです。なんちゃってメモリアロケータと、GCルートのクローラと、ちょっとした関数が込めてあります。それぞれのtest_functionの先頭には、C++で書いたらこうなるかなーというコードが書かれています。ループをひたすら回す処理が書いてあり、その中で毎回int型のメモリを確保するmy_allocを呼んでいます。俺々ランタイムのなんちゃってメモリアロケータは、10個しかメモリ領域を管理できない出来損ないです。メモリを10回確保して開放しないでいると、11回目のメモリ確保でガベージコレクションがトリガされるようになっています。実際に実行してみると、(多分)そのような挙動をしていることがわかります。部分は使用するプラグインの名前になります。デフォルトで使うことができます。確保した領域もSSA形式に変換してしまう可能性があるので、マークを行う必要があります。呼び出しは、最初のBasicBlockで行われる必要があるようです。第1引数は必ずalloca命令かallocaのbitcastを参照する値でなければなりません。第2引数には、ポインタに関連付けられたメタデータへのポインタが入りますが、このポインタは*必ず*定数もしくはglobalな値のアドレスである必要があります。利用しない場合はnullを渡せば良いようです。組み込み命令で実現できます。あとは、アロケータがガベージコレクションのトリガを引いた際に、ルートを巡ってガベージコレクションを行うなりなんなりするだけです。documentationShadowStackについて自分がShadowStackについてよく分かっていなかったので、LLVMではどのように実装されているか見てみました。