Perlテックブログ

ITエンジニアの成長意欲を刺激する技術考察、モジュール開発の日記。Perlイベントや国内や海外のPerlの記事の紹介。

SPVMのJITの単位をサブルーチンからモジュールへ

SPVMのJITの単位をサブルーチンからモジュールへ変更することを考えている。そして、サブルーチンが実行されるタイミングで、コンパイルするのではなくって、モジュールがuseされたタイミングでコンパイルする。

三種類のコンパイル方法

コンパイルには、大きく分けて3種類ある。

  1. すべてをプログラムが始まる前にコンパイル
  2. モジュール単位で実行時コンパイル
  3. サブルーチン単位で、実行時コンパイル

僕は、3番目をやることを最初に考えていて現在の実装は3番目なのだけれど、これをやめて2番目に統一する。

サブルーチン単位の実行時コンパイルは何が難しいのか

実装をやってわかったことがいくつかある。

  1. サブルーチン単位にコンパイルされるので、サブルーチンごとに、.soファイルを作成してしまう。メモリ使用量が非常に大きい。
  2. ダイナミックリンクライブラリの抽象化をPerlのほうに依存しているので、SPVMからPerlの関数を呼び出さなければいけなくって、密結合してしまう。
  3. JITコンパイル時に、インライン展開やループ展開で最適化をかけたい場合に、抽象構文木を再構築しなければならない
  4. JITコンパイルによって、実行時にメモリ使用量が増えてしまう。
  5. もし仮にgccを使わずに、メモリ上で機械語にする場合は、環境依存になってしまう。LLVM JIT, libjitなど。IntelやARMの機械生成の独自実装は辛すぎる。v8などがやっている方法。
  6. 実行時のコンパイルに時間がかけれないので、最高の最適化には適さない。
  7. 実装が非常に複雑である
  8. Windowsでの.dllのコンパイルは非常に遅い

実際にサブルーチン単位のJITの実装をやってみると、最初には見えなかった複雑さや弱さが見えてくる。

モジュール単位での実行時コンパイルは何がうれしいか

モジュール単位での実行時コンパイルは、上の欠点をすべてなくすことができる。そして、実装が非常に簡単になる。ただし、実行時のコンパイル速度は、ひとつのモジュールに属するすべてのサブルーチンをコンパイルするので遅くなる。この欠点は、プリコンパイルするか、キャッシュを利用することで解消できると考える。

それと、この方法は非常にPerlらしいということだ。Perlはしっての通り、XSでモジュールを構築する場合は、モジュール単位で.soという共有ライブラリを作成して、それをPerlの側から読み込むということをしている。つまり、モジュール単位で、.soファイルを生成すれば、Perlの仕組みに統合することができそうだ。

これは、XSで.soを作成する代わりに、SPVMで.soを作成して、CPAN上にリリースできるということを意味する。

Perlユーザーにとって一番うれしいことは、まるでPerlのように扱えるということだと、僕は考える。