オープンソースのJavaScript/WebAssemblyエンジン「V8 release v8.0」が公開ポインタ圧縮の効果が大きい

オープンソースのJavaScript/WebAssemblyエンジンの最新版「V8 release v8.0」が公開された。数週間後に正式リリース予定のWebブラウザ「Chrome 80」に搭載される。メモリ消費量が減ったために高速動作する他、プログラマーがバグを作り込みにくい仕組みを取り入れた。

» 2019年12月23日 10時30分 公開
[@IT]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

 オープンソースのJavaScript/WebAssemblyエンジン「V8」の開発チームは、2019年12月18日(米国時間)、最新版「V8 release v8.0」の公開を発表した。数週間後に正式リリース予定のWebブラウザ「Chrome 80」の安定版にも搭載される予定だ。

 V8はC++で記述されており、ChromeやNode.jsなどに採用されている。ECMAScriptとWebAssembly規格に準拠しており、Windows 7以降、macOS 10.12以降、各種Linuxシステムで動作する。スタンドアロンでも、C++アプリケーションに組み込んで実行できる。

 新版では、バグの修正はもちろん、パフォーマンスを大きく改善する改善を施した。

ポインタ圧縮の効果は大きい

 開発チームはヒープメモリの削減を試みた。V8のヒープメモリにはさまざまなデータが登録されている。浮動小数点数の値やストリング文字、コンパイルされたコード、V8ヒープへのポインタ、小さな整数を表す「タグ付きの値(tagged values )」などだ。どのデータが多いのか、調査した結果、タグ付きの値がヒープメモリの大部分を占めていることが分かった。

 タグ付きの値のサイズはシステムポインタと同じであり、アーキテクチャに依存する。例えば64bitアーキテクチャであれば64bit幅だ。

 新版ではタグ付きの値(ポインタ)の圧縮により、ヒープメモリを平均40%節約できた。ポインタの圧縮は、下位ビットから上位ビットを合成できるので、下位ビットのみをヒープに保存すれば済むという発想で実現した。

ポインタの圧縮でヒープメモリを平均40%削減できた(出典:vi.dev

 メモリ使用量の改善は、パフォーマンスを犠牲にすることが多い。だが、今回の改善では実際のWebサイトにアクセスした際に必要な時間が改善した。3種類のWebサイト(Facebook、CNN、Google Maps)で検証したところ、ガベージコレクタ単体では20%、総合性能では8%の改善が見られた。

ポインタ圧縮による処理時間短縮の効果(出典:vi.dev

高次のビルトインの最適化が性能改善に役立つ

 もう一つの改善点はTurboFanの最適化パイプライン内の制限を取り除いたことだ。この制限はこれまで、より高次のビルトインの積極的な最適化を妨げていたものだ。

 これまでcharCodeAtの呼び出しは、V8のコンパイラ「TurboFan」からは不透明だった。このため、次のコードのようにユーザー定義関数の汎用(はんよう)呼び出しを生成していた。

const charCodeAt = Function.prototype.call.bind(String.prototype.charCodeAt);
charCodeAt(string, 8);

 だが、今回の改善により、V8はビルトインString.prototype.charCodeAt関数を呼び出すようになった。これによってTurboFanがビルトインの呼び出しを最適化によって改善でき、次のコードを記述した場合と同等のパフォーマンスを実現できるようになった。

string.charCodeAt(8);

 この変更は、Function.prototype.applyやReflect.apply、さまざまな高次配列ビルトイン(例えばArray.prototype.mapなど)のような多くのビルトインに影響する。

オプショナルチェイニングによってプロパティアクセスのチェインを確実に動作するように改善

 プロパティアクセスのチェインを作成する場合、コード上で中間値がNULL(nullish)かどうかをチェックする必要がある。nullかundefinedを判定する必要があるということだ。なぜならエラーチェックを作り込んでいないチェインはスローする可能性があるからだ。

 かといって明示的にエラーチェックを行うチェインのコードは冗長になる。非NULL値だけでなく、次のコードのように全ての真の値もチェックしてしまうからだ。

// Error prone-version, could throw.
const nameLength = db.user.name.length;
// Less error-prone, but harder to read.
let nameLength;
if (db && db.user && db.user.name)
  nameLength = db.user.name.length;

 この問題を解決するために、今回、オプショナルチェイニング(「?.」)を導入した。これを使うと、中間値がnullなのかundefinedなのかどうかを簡潔にチェックできる。オプショナルチェイニングは確実に機能するため、信頼性の高いプロパティアクセスチェインを作成できる。

 今回の改良によって、中間値がnullまたはundefinedだった場合に、式全体がundefinedと評価できる。

// Still checks for errors and is much more readable.
const nameLength = db?.user?.name?.length;

 オプショナルチェイニングは、静的プロパティアクセスに加えて、動的プロパティアクセスと呼び出しもサポートしている。

nullish coalescingでデフォルト値処理が正確になる

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。