SPVMの開発の今後の道のり - 仕様作成からJITによる最適化まで
Perlの処理を30倍速くすることを目標に開発しているSPVMですが、今後の道のりをここに記しておきます。
デバッグモード追加
現状は例外が起こったときに、コールスタックは表示されるけど、行番号とファイルは表示されない。これは、開発のときはちょっと不便なので、デバッグモードを追加する予定。
ウィークリファレンスの実装
Perlと同じように、SPVMのGCはリファレンスカウントで実装されている。現在制限として、オブジェクトの循環参照は禁止されているが、ウィークリファレンスを実装して、この制限を解きたい。
タグポインタという仕組みを使って、実装しようと思うのだが、まだ構想段階で、パフォーマンスを悪くすることなく、実装できるかは未知数。なんとかなりそうな気もする。
ネイティブインターフェース
JavaにはJNIというC言語に接続するためのインターフェースがあるのだけれど、これをSPVMでも作成する。このインターフェースがあれば、SPVMの配列などのデータ構造にC言語レベルでアクセスできる。
GPUやSIMDなどの並列処理を、記述したいときは、このネイティブインターフェースを使って実装できるようにする。
ダイナミックリンクライブラリ
ダイナミックリンクライブラリの機能を追加する。ダイナミックリンクライブラリが読み込めるようになると、必要に応じてC言語のライブラリが読み込めるようになる。
ダイナミックリンクライブラリが読み書きできるようになると、ネイティブインターフェースを使って書いたSPVMのライブラリを、CPAN上にアップして再利用できるようになる。
PerlのもっているXSやDynaLoaderの機能を使ってうまく実装できるような気もしている。
定数畳み込み
1 + 3 のようなものをコンパイル時に4にするような最適化を定数畳み込みという。これを実装する。
インライン展開
小さな関数を展開して、関数呼び出しをなくすインライン展開の機能
抽象構文木をSSA形式にして最適化
SSA形式というのは、「結果、演算子、値1、(値2)」という線形の形式で表現されたプログラムのことで、変数名がかぶらないように採番されるのが特徴のようだ。
SSA形式に変換すると、定数伝播や不要な式の削除が行いやすくなるらしい。
ループ最適化
ループの中で、undefのチェックや配列の範囲チェックしている部分を、外に追い出す。これによって命令数を少なくする。これは、かなり難しそうだ。
レジスタ型VM
現在はスタック型のVMとして実装している。でも、僕が調査したことによると、現在のCPUにおいては、コードサイズが小さいことよりも、命令数が少ないということが、パフォーマンスにとって重要らしい。
レジスタ型VMは命令長が長くなる代わりに、加算や減算などの命令数を減らすことができる。
またレジスタ型VMにすると、JITを行う場合に、ちょうどCPUの命令に近いような表現ができる。
VMを書き直すのはかなり大変そう。
機械語に対応するバイトコード生成
レジスタAにレジスタBを加算するというような、機械語に対応するバイトコードを作成する。これによって、定数決め打ちで演算ができるので、速くなる。また、JITにちょうど対応する命令を生成できる。
JIT
最後にJIT。つまり実行時コンパイル。僕は、どうしてJITにすると速くなるのかという疑問を持っていた、だってVMだって結局は機械語で実行されているのにねって。
JITを行うと速くなる理由は、命令のジャンプがなくなるということに尽きる。
バイトコード命令の場合は、命令を実行するために、その命令の位置までジャンプしないといけない。このジャンプの負荷が大きい。
JITを行うと機械語命令を、連続した領域に並べることができる。これでジャンプがなくなり、速くなるというわけ。
「次期PHPにJITがやってきそうでうらやましそう」といっていた方がいましたけど、Perlにもやってきますよ!
地道に順番に実装してく
これを地道に順番に実装していく。SPVMは、Javaとgperlとluajit2が、大きな参考になっている。
Perlの可能性が広がって、ますますPerlが面白く、いろんな分野にチャレンジできると思う。30代の目標は、ひたすらオープンソースで開発して、インフラを作ること。40代の目標は、教育、研究、出版という分野で、Perlを横に広げることだ。今はそういう目標を持っている。