自動回収

自動回収は地味に問題の根が深いことが解ってきた。
一番単純な解は、

  • (gc-push-finalizer! ptr handle)
    • gc_mallocでfinalizer付きオブジェクトを作り、proxy objectを返す
    • finalizerは、スレッドセーフなqueueにhandleをpushするだけ。
  • (gc-ptr-ref obj)
    • proxy objectからポインタを読み取る
  • (gc-pop-finalizer!)
    • queueからhandleをpeekする。無ければ#f。

みたいな手続きをmosh側に追加する。描画用のオブジェクトは常にコピーで作成されるため、この仕組みで安全にオブジェクトを解放できる。
しかし、moshに手続きを追加するとビルドに1時間くらい掛かるので*1、もっと簡単な手法を考えないといけない。

  • 1. enable-plugin hookを復活する

以前TCGを試したときのように、VMにhookを設けて手続きを追加する。

  • 2. FFIで実装する

queueはFFI経由で実現しても問題ない。ファイナライザの実体もFFIでロードできる(が、lookupする正当な手段は無い)。
GCの関数がFFIから呼べない点に関しては、実は、Windows限定で良ければGCをDLLにするという解がある。GCのシンボルをエクスポートすればLinuxでも同じことは出来るはずだが何とも言えない。ただ、これはGCデバッグビルドしたりすれば直ぐにダメになる。

simple

皮肉なことに、シンプルAPIにはこの問題が無いことに気づいた。シンプルAPIでの描画は、全てのコンテキストの準備や描画を(canvas->XXX)手続きで一気に行うため、描画オブジェクトは手続きから返る前に全て解放できる。
シンプルAPIにリスト描画機能を付け、常に描画の最終段階だけでSchemeオブジェクトから描画オブジェクトへの変換を行うデザインも考えられる。これが悪いのは、

  • 同じビットマップを繰り返し描画するケース(毎回ビットマップをコピーすることになる)
  • テンプレートを何度も適用するケース(毎回描画リストのdatumを型チェックすることになる)

くらい。simple APIの想定するユースケースでは問題ない。ビットマップとしてbytevectorを使うようにすれば前者のオーバヘッドは無視できるほど小さくなる(元々cairoのコンテキスト作成/破棄は非常に軽い)ので、bytevectorを使ったsurfaceを導入すれば、(cairoに関して言えば)simple APIを実用的な速度で使える可能性は高い。

*1:cygwinで./configure --enable-developer && make && make distclean、MinGWで./configure && makeする必要がある。