RubyKaigiでJITコンパイラの書き方について発表した

RubyKaigi 2023でRuby JIT Hacking Guideというタイトルで発表してきた。

speakerdeck.com

JITコンパイラを書くチュートリアル

今回の発表ではJITコンパイラが書ける人間を増やすことをゴールにしていたが、 30分という短い発表枠内では雰囲気を知ってもらうことにフォーカスし、 実際に手を動かしたい人たちにはそれ用のチュートリアルを触ってもらう形を取った。

github.com

JITコンパイラは実は初心者向き

独学でコンパイラの作り方を学ぶ人は、Cコンパイラなどを実装することが多いように思う。 C言語は実装対象として一見シンプルそうに見えて実は結構機能が多いので、C11をゴールに始めてもC89の範囲すら実装しきらないままエターなる人も多いのではないか。

そんな僕みたいな堕落した人間にお勧めなのがJITコンパイラインタプリタと併走する特性上、実装が面倒な入力は全てインタプリタに移譲することで、限られた労力で最適化と互換性を両立できる。 このリポジトリで作ったJITコンパイラをベースに、Railsアプリを動かしても壊れないような修正をいれることは難しくない。

YJITより速いJITを書くという体験

JITコンパイラを書いていて一番楽しいのは、やはり自分が書いた実装が既存の実装を打ち負かした瞬間だと思う。 フィボナッチは個人JIT開発者界隈でよくベンチマークに使われるのだが、 今回のチュートリアルでもこれで他のJITと競う体験をしてもらうことにフォーカスした。 リポジトリ内のヒントを素直に辿るだけで、YJITより速いJITを完成させる喜びが体験ができるようになっている。

フィボナッチ"だけ"をめちゃくちゃ速くするコンパイラは書こうと思えば比較的短期間で書けるのだが、 それなりに複雑になる反面、Railsアプリのような大きなベンチマークではその成果が労力に見合わなくなることが多い。 YJITはマイクロベンチを速くすることにプライオリティを置いていないため、今でも簡単に負かすことができるが、 その一方でRailsをYJITより速くするJITを書くのは難しい。

参照実装を公開した

元々Shopify社内で内部公開していて、自分のアカウントに移すときに参照実装のブランチをpushし忘れてリンク切れになっていたのだが、今は直っている。 どうにもバグが直せなくてギブアップという人や、動くものをとりあえず触ってみたいという方はどうぞ。

github.com

opt_send_without_blockとbranchunless

@HKDnet さんがツイートしていたが、opt_send_without_blockとbranchunlessのところは他よりやや難易度が高くなっている。 前者はRubyのメソッド呼び出しをある種自力で実装しなければならず、後者はCFG (制御フローグラフ) を作ったり循環参照のあるコード生成をしたりということが必要になるからだ。

どちらも自分で頭をひねって実装してみるのは面白い題材なのでそのままにしてあるが、難易度の傾斜的には、この二つは一旦参照実装を理解してもらって、自分の書き方で実装し直してもらうくらいがちょうどいい気がする。

アセンブラを書きたい人へ

本当はRubyKaigiの発表内でModR/Mエンコーディングとかも解説したかったのだが、いくらコアな参加者が多いRubyKaigiといえど流石にやりすぎという気もしたのと、トークの尺やスライドの準備的にも面倒だったので、opv86だけ紹介してわかったつもりになってもらう形を取った。 そこもやってみたい! という人は、lib/jit/assembler.rb を削除して、このサイトとかを参考に一から実装してみるのが良いと思う。

困ったら

Twitter @k0kubun にリプライをいただくか ruby-jp Slackの #ruby-hacking とかで質問していただければ、解説やアドバイスなどできる予定。