オープンソースのJavaScript/WebAssemblyエンジンの最新版「V8 release v8.0」が公開された。数週間後に正式リリース予定のWebブラウザ「Chrome 80」に搭載される。メモリ消費量が減ったために高速動作する他、プログラマーがバグを作り込みにくい仕組みを取り入れた。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
オープンソースの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%節約できた。ポインタの圧縮は、下位ビットから上位ビットを合成できるので、下位ビットのみをヒープに保存すれば済むという発想で実現した。
メモリ使用量の改善は、パフォーマンスを犠牲にすることが多い。だが、今回の改善では実際のWebサイトにアクセスした際に必要な時間が改善した。3種類のWebサイト(Facebook、CNN、Google Maps)で検証したところ、ガベージコレクタ単体では20%、総合性能では8%の改善が見られた。
もう一つの改善点は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演算子「??」だ。これは、デフォルト値を処理するための短絡2項演算子だ。
これまで、デフォルト値を論理演算子「||」で処理する場合があった。例えば、次の例のような場合だ。
function Component(props) { const enable = props.enabled || true; // …… }
だが、デフォルト値を計算する上で、「||」を使うことは望ましくない。「a || b」は、aがfalseの場合、bと評価されるからだ。意味を間違いやすいコードだ。props.enabledが明示的にfalseに設定されていても、enableはtrueとなる。
これに対し、nullish coalescing演算子を使うとデフォルト値の挙動が望ましい形になる。「a ?? b」は、「aがnullまたはundefined」という場合、bと評価され、そうでない場合はaと評価されるからだ。「??」を使って先ほどのコードを書き換えると次のようになり、予想外の挙動を予防できる。
function Component(props) { const enable = props.enabled ?? true; // …… }
nullish coalescing演算子とオプショナルチェイニングは、組み合わせて使用する機能であり、一緒に動作するため、次のコードのようにさらに改善を施すことも可能だ。
function Component(props) { const enable = props?.enabled ?? true; // …… }
Copyright © ITmedia, Inc. All Rights Reserved.