XSでクロージャ

Perlのようにクロージャをサポートする言語では,eval()せずに実行時にサブルーチンを定義できるので大変便利である。しかし,Cではポータブルにクロージャを作る方法はないので,サブルーチンの動的定義とXSによる高速な実装は相容れないように見える。しかし,実際にはXSでもクロージャを作ることができる。というのも,Cの関数自体はデータを持てないが,newXS()で定義したCV(Code Value)はデータを持つことができるからだ。
そのためのスロットがSV全般に存在するMAGICスロットで,これは本来はTie変数や%ENVなどの実装に使われるSVへの操作をフックするメカニズムである。しかしこの場合は,特定のCVとデータ(MAGIC構造体)を関連付けするためだけに使う。この関連付けられたデータCVの消滅と共に破棄されるので,クロージャの実装に使うことができる*1
CVへの関連付けにはsv_magicext()を使う。

sv_magicext((SV)xscv, (SV*)any_data, PERL_MAGIC_ext, &identity_vtbl, other_ptr, other_ptr_size);

説明すると長くなるのでここでは詳細は省くが,実際のコード例としては,Data::Utilにあるcurry()/modify_subroutine()(in DataUtil.xs)がクロージャ生成ルーチンで,XS_Data__Util_curried()/XS_Data__Util_modified()(in subs.c)がクロージャルーチンとなっている。
参考: perldoc perlguts/Magic Variables

*1:XSによるCVにはもう一つANYというスロットがあるが,こちらはGCの対象にならないのでこのケースでは適さない。