QML エンジンの進化 その1

QML は JavaScript をベースに作成された言語です。そのため、QML の言語処理系には JavaScript エンジンを使用しています。Qt4 では JavaScriptCore を、Qt5 ではより速度を求めて V8 JavaScript Engine を採用しました。Qt5 では V8 の採用とそれ以外の最適化などで Qt Quick のパフォーマンス向上を果たしましたが、徐々にその限界も見えつつあります。その限界と次のステップを解説する第一弾として “Evolution of the QML engine, part 1” が Qt Blog に投稿されました。面白い記事ですので、ざっくりと訳してみることにします。

さて、現状の V8 の利用にどのような問題があるのでしょうか

  • 複数のオブジェクトモデル
    QML は JavaScript をベースにしていますが、JavaScript そのものではありません。そのため、QML を動かしている場合、QML エンジン内のオブジェクト、JavaScirpt のオブジェクト、C++ 側から QObject を通じて QML に渡されるオブジェクトが存在することになります。これら三種類のオブジェクトの同期やグルーコードがメモリ消費も含めてパフォーマンスの問題となってきます。
  • JavaScript のクロージャとして行われるバインディング
    QML の各バインディングは V8 での評価用に JavaScript のクロージャとして内部で関数の形に書き換えられます。V8 はその式を再びパースします。また、バインディングを V8 で評価する際には、適切なコンテキストを生成するという大きなオーバーヘッドが生じます。この問題は、以前に解説した v4 と呼ばれる小規模な式評価用インタプリタを開発するきっかけとなりました。v4 ではそのオーバーヘッドが小さいため、V8 の数倍高速にバインディングを評価することが出来ます。
  • データ型の変換
    V8 で式の評価が遅いもう一つの理由にデータ型を変換するオーバーヘッドがあります。例えば Qt のプロパティをクセスする場合、プロパティの値として QVariant が生成され、それが V8::Value に変換されます。プロパティの型が文字列の場合にはそのデータのコピーが生じることになります。この改善のために様々なキャッシュが導入されましたが、それらはメモリ使用量の増加とコードの複雑化の一因となっています。
  • スコープルールの違い
    QML の文法はアイテムの木構造の形を取っており、スコープルールもそれに応じて定義されています。しかし、このルールが JavaScript のルールとは異なるため、JavaScript エンジンの実装をそのまま使用することが出来ません。(遅くて非推奨な with 文を使えば可能ですが。) 現状では V8 にパッチを当てて対処しており、またこのため、プロパティを名前で検索する必要があります。
  • QML 型情報の扱い
    QML は静的型付き言語です。しかし、JavaScript が動的型付け言語であるため、QML の型情報がコンパイル時に捨てられています。型情報があれば QML の式の最適化を若干改善することが出来るでしょう。
  • iOS と WinRT のサポート
    iOS ではメモリを実行可能かつ書き込み可能にすることができません。WinRT ではメモリを実行可能にすること自体が出来ません。V8 ではすべての JavaScript を JIT で動作させるため、これらのプラットフォームでは V8 にインタプリタバックエンドを実装しない限り V8 を使用することは出来ません。
  • V8 のアップストリームとの協力
    上述の通り、V8 に対して大規模なパッチを維持する必要があります。しかし、V8 はブラウザでのユースケースに焦点を当てており、これらのパッチがマージされる可能性はありません。

これらの問題から約一年前に Nokia で v4vm というリサーチプロジェクトがスタートしました。プロジェクトは Digia へと引き継がれ、qtplayground の一員として開発されてきました。その v4vm が Qt Declarative モジュールの開発用ブランチにマージされました。今後は Qt Declarative モジュールの中で開発が進んでいくことになります。

新しいエンジンは ECMAScript 5.1 を完全に実装しており、Qt がサポートするすべてのプラットフォームで動作します。Linux と Mac, iOS で動作する JIT も含んでいます。(ファイル構成を見ると LLVM を使用しているように見えますが、現在はデフォルトでは使用していないそうです。)現状は V8 互換 API を通じて動かしていますが、近いうちに直接動作させる予定です。若干の問題はありますが、すべての Qt Quick のデモが動作します。

新しいエンジンは QML で利用するために作られたものであり、現状でも QML のパフォーマンスを改善しています。しかし、純粋な JavaScript のみのパフォーマンスは別問題であり、V8 ほど良くはありません。とはいえ、V8 のベンチマークの結果が Qt 4.8 と Qt Quick 1 での場合に比べて3倍遅い程度であり、最適化を施す余地も十分にあることから JavaScript 自体のパフォーマンスも改善していくことでしょう。

新しいエンジンと今後のプランの詳細は後日の記事で。コードは qtdeclarative モジュールの wip/v4vm ブランチにあります。開発への協力などは IRC で freenode の #qt-v4vm チャンネルで連絡してください。

コメントを残す