言語処理系のC拡張とGC
GCがある処理系、特にポインタが移動するCopying GCやGenerational GCなどは、プリミティブやC拡張を書くのが結構面倒だったりする。 Cやマシン語での処理の際に、新しいオブジェクトを作ると、GCが発動してポインタが動いてしまう可能性があるから。
そういった言語がいかに拡張を書きやすくしているか調べてみる。
Chicken Scheme
Cheney on the M.T.AでCのスタックから移すのでポインタが移動するはず。
Interface to external functions and variablesのEmbeddingを見ると、CHICKEN_new_gc_root
関数がある。
- GCのスキャンルートを作成して
- そこに保護したい値を入れて
- 新しいオブジェクトを作成して
- スキャンルートから保護した値を取り出す
という使用法かな。
処理系側の実装は楽そうだけど、使う際に消し忘れに気を付けないといけない。Early Returnの際に特に注意が必要。
Lua
Incremental Mark&SweepとGenerational GCの複合?
APIの章にThe Stackとある。 Cの関数呼び出しの際にスタックが用意され、引数や返り値の受け渡しはそこで行われる。また、GC Rootとしても扱われる。
スタックが関数呼び出し毎に用意されるので、push/popが必ず対になってる必要はない。indexから値を参照・変更すればいい。多値を返すときも楽そう。
まあちょっと面倒だとは思うし、面倒だとよく聞くけど、一番Cへの埋め込みに使われているし安定した手法なのかな。return時にUnprotectが必要ないのが良い。
考察
LuaみたいにC関数を呼び出すときにスタックを割り当てておいて、ローカル変数の位置をGCルートとしてスタック上に記録してしまうのはどうなんだろう。ただそんなに軽い処理とは思えないので、プリミティブのCコード実行時には使えなさそう。ここは要調査。
参照カウントとConservativeGCはそれぞれ利点欠点あるけど、一番面倒そうなのはデフラグ。この処理を自前でやるなら結構大変。ringではribbitの真似して3セルのみのオブジェクト表現でConservativeGCにしたので、まあ書くのはかなり楽だった。遅いけど。
TODO
- LuaとChickenのVM命令がどうオブジェクトを保護しているか調べる