JIT コンパイルまとめ

Mosh のパフォーマンスを向上させたいので JIT コンパイル周りを調べてみました。誤りや不足がありましたらご指摘いただけると助かります。

何か?

Just in time コンパイルの略。実行時に必要になった時点で動的にコードを生成する仕組み。
VM 型のインタプリタにおいて、実行時に bytecode を native code にコンパイルすることを指すことが多い。


必要になった時点のコンパイルではあるが、Pre-JIT のように起動時にまとめて JIT コンパイルする場合もある。

目的・効果

インタプリタの良いところを維持しつつインタプリタ実行速度を高速化。AOT コンパイラが出力するコードの速度に近づける。

JIT が AOT (Ahead of time)と比較して有利な点

  • 実行時の統計情報を利用できる
  • 実行ホストに最適化されたコードを利用できる

JIT コンパイルされる対象

コードの断片、関数など手法によって様々。

JIT コンパイル手法

  • 実行時に良く実行される関数を native code にコンパイル
  • Tracing JIT
    • 関数単位でコンパイルするのではなく、他の関数呼び出しなどを含むループ全体を JIT コンパイルする。
    • 動的な型づけの言語の場合に specalized された型用のループコードを生成
      • trace 時に分岐や、型など、前提としている条件が整っているかどうかチェックする "guard" が挿入される
  • trace したコードには種々の最適化が施される(AOT コンパイラで行われるような最適化)
  • Context Threaded JIT
    • Direct Threaded のダメな点を改善
      • パイプラインストール
      • 間接分岐が原因の分岐予測ミス
    • vPC(仮想プログラムカウンタ)と PC が一致するように
    • 基本的には op code 単位の変換
      • 複雑な opcode body は runtime の関数呼び出しに変換
      • 単純な opcode や分岐は inlined nativecode に。
    • メリット
      • VM インストラクションのリストが保持する分岐コンテキストが CPU から見える形になる
      • opcode dispatch による間接分岐が減り分岐予測しやすくなる。
    • SquirrelFish で採用
    • 他の JIT に比べて実装が簡単らしい
  • V8(JS->AST->native code)
    • bytecode を介さない JIT コンパイル
    • AST からのコード生成はほぼ決めうち。
    • Tracing JIT で見られるような強力な最適化は施されていないが同等の速度が出ているらしい
  • Superinstruction selective inlining
    • superinstruction を VM ロード時に 各op body を memcpy することで生成する。GCC の label-as-values と組み合わせ。

所感

Tracing JIT は型安全を保証できる trace の詳細が分からなかったので調べる必要がありそう。
Context Threaded は今の CPU には合わないかもしれない。


Tracing JIT にしろ関数単位の JIT にしろ

  • 得られる速度向上
  • JIT に適した命令セット、VM の構造
  • JIT コンパイラ自体のメンテナンスコスト

などを考えていかないとまずそうだ。JIT コンパイラScheme で書くので意外とメンテナンスは簡単かもしれないけど。


研究レベルでは Tracing JIT の次は何が来ているんだろう。