メインコンテンツまでスキップ

Ignitionインタープリタを起動

· 約5分
Ross McIlroy, V8 Ignitionジャンプスターター

V8およびその他の最新のJavaScriptエンジンは、ジャストインタイム(JIT)コンパイルによって、スクリプトをネイティブマシンコードに即時コンパイルし、実行前に高速化を図っています。コードはまずベースラインコンパイラによって初期的にコンパイルされ、非最適化されたマシンコードを迅速に生成できます。その後、実行時にコードを分析し、必要に応じてより高度な最適化コンパイラで動的に再コンパイルされ、性能を最大化します。V8では、このスクリプト実行パイプラインにおいて、ベースラインコンパイラと2つの最適化コンパイラ(CrankshaftとTurboFan)の間を切り替える複雑な仕組みが存在します。

このアプローチ(アーキテクチャの複雑さを含む)に伴う問題の1つは、JITによって生成された機械コードが、たとえ1度しか実行されないコードであっても、かなりのメモリを消費する可能性があることです。このオーバーヘッドを軽減するために、V8チームはIgnitionと呼ばれる新しいJavaScriptインタープリタを構築しました。これによりV8のベースラインコンパイラを置き換え、メモリのオーバーヘッドを減少させ、よりシンプルなスクリプト実行パイプラインを実現しました。

Ignitionでは、V8がJavaScript関数を簡潔なバイトコードにコンパイルします。そのサイズは、同等のベースラインマシンコードの約50%〜25%です。このバイトコードは、高性能なインタープリタによって実行され、リアルなWebサイトでの実行速度はV8の既存のベースラインコンパイラが生成するコードに匹敵します。

Chrome 53では、RAMが限られている(512 MB以下の)AndroidデバイスでIgnitionが有効化されます。現場での初期実験結果によると、Ignitionを使用することでChromeタブごとのメモリが約5%削減されると言われています。

Ignitionが有効になったV8のコンパイルパイプライン

詳細

Ignitionのバイトコードインタープリタを構築する際、チームはいくつかの実装アプローチを検討しました。従来型のC++で書かれたインタープリタは、V8の他の生成コードとの効率的な相互作用が難しいと考えられました。もう1つの代替案として、アセンブリコードでインタープリタを手動でコーディングする方法がありましたが、V8がサポートする9つのアーキテクチャポートを考慮すると、莫大なエンジニアリング負担が伴います。

その代わりに、TurboFanという新しい最適化コンパイラの強みを活用する方法を選びました。TurboFanはすでにV8のランタイムや他の生成コードとの最適な相互作用に向けて調整されています。Ignitionのインタープリタは、TurboFanの低レベルでアーキテクチャに依存しないマクロアセンブリ命令を使用して、それぞれのオペコード用のバイトコードハンドラを生成します。TurboFanはこれらの命令をターゲットアーキテクチャにコンパイルし、その際に低レベルな命令選択やマシンレジスター割り当てを行います。これにより、バイトコード命令を実行し、V8仮想マシンの他の部分と効率的に相互作用する高度に最適化されたインタープリタコードが生成され、コードベースに新しい仕組みを最小限に抑えます。

Ignitionはレジスタマシンであり、各バイトコードが入力と出力を明示的なレジスタオペランドとして指定します。これにより、入力を消費し、出力を暗黙のスタックにプッシュするスタックマシンと異なります。特別なアキュムレータレジスタは、多くのバイトコードで暗黙的な入力および出力レジスタとして機能します。これにより特定のレジスタオペランドを指定する必要がなくなり、バイトコードのサイズが縮小されます。多くのJavaScript式は左から右に評価される操作の連鎖を含むため、これらの操作の一時的な結果は、式の評価中にアキュムレータに保持されることが多く、明示的なレジスタにロードおよび保存する操作の必要性を最小化します。

バイトコードが生成されると、一連のインライン最適化ステージを通過します。これらのステージはバイトコードストリームの簡単な分析を行い、一般的なパターンを高速なシーケンスに置き換え、一部の冗長な操作を削除し、不必要なレジスタロードおよび転送操作を最小限に抑えます。これらの最適化により、バイトコードのサイズがさらに縮小され、性能が向上します。

Ignitionの実装に関する詳細については、BlinkOnの講演をご覧ください。

将来

これまでIgnitionの焦点は、V8のメモリオーバーヘッドを削減することでした。しかし、Ignitionをスクリプト実行パイプラインに追加することで、将来的に多くの可能性が開かれます。Ignitionパイプラインは、コードの実行と最適化のタイミングに関してより賢明な決定を可能にし、ウェブページの読み込みを高速化し、カクつきを減らし、さらにV8の各コンポーネント間の連携をより効率的にするよう設計されています。

IgnitionとV8の将来の進展にご期待ください。