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

V8リリースv6.6

· 約9分
V8チーム

6週間ごとに、私たちはリリースプロセスの一環としてV8の新しいブランチを作成します。各バージョンは、Chrome Betaのマイルストーン直前にV8のGitマスタから分岐されます。本日、新しいブランチV8バージョン6.6を発表できることを嬉しく思います。このバージョンは、数週間後にChrome 66 Stableと連携してリリースされるまでベータ版です。V8 v6.6には開発者に向けた多くの魅力的な機能が詰まっています。この投稿では、リリースに先立つ注目すべきハイライトのプレビューを提供します。

JavaScript言語機能

Function.prototype.toStringの改訂 #function-tostring

Function.prototype.toString() は、空白やコメントを含む、ソースコードテキストの正確なスライスを返すようになりました。以下は旧動作と新動作を比較する例です:

// `function`キーワードと関数名の間のコメントおよび
// 関数名の後のスペースに注意してください。
function /* コメント */ foo () {}

// 以前は:
foo.toString();
// → 'function foo() {}'
// ^ コメントなし
// ^ スペースなし

// 現在は:
foo.toString();
// → 'function /* コメント */ foo () {}'

JSON ⊂ ECMAScript

行区切り記号 (U+2028) および段落区切り記号 (U+2029) が文字列リテラルで使用可能になり、JSONと一致するようになりました。従来はこれらの記号は文字列リテラル内で行終端記号として扱われており、使用すると SyntaxError 例外が発生していました。

オプションのcatchバインディング

try文のcatch句は、パラメータなしで使用可能になりました。例外を処理するコード内でexceptionオブジェクトが不要な場合に便利です。

try {
doSomethingThatMightThrow();
} catch { // → 見て、バインディングなしだよ!
handleException();
}

片側トリミングされた文字列

String.prototype.trim()に加えて、V8はString.prototype.trimStart()String.prototype.trimEnd()を実装しました。この機能は以前は非標準のtrimLeft()およびtrimRight()メソッドを通じて利用可能でしたが、これらのメソッドは新しいメソッドのエイリアスとして後方互換性のために残されています。

const string = '  hello world  ';
string.trimStart();
// → 'hello world '
string.trimEnd();
// → ' hello world'
string.trim();
// → 'hello world'

Array.prototype.values

Array.prototype.values() メソッド は、配列にES2015のMapSetコレクションと同じイテレーションインターフェースを提供します。これにより、keysvaluesentriesメソッドを呼び出してイテレーションできるようになります。この変更は既存のJavaScriptコードとの互換性問題を引き起こす可能性があります。ウェブサイトで奇妙な動作や問題を発見した場合は、chrome://flags/#enable-array-prototype-valuesからこの機能を無効にし、問題を報告してください。

実行後キャッシュされたコード

読み込み性能を気にする人々にとって、コールド状態ウォーム状態 という用語はよく知られているかもしれません。V8では、ホット状態 という概念もあります。ChromeがV8を埋め込んだ例でこれらのレベルを説明しましょう:

  • コールド状態: Chromeは訪問したウェブページを初めて目にし、データをまったくキャッシュしていません。
  • ウォーム状態: Chromeはそのウェブページを以前訪問したことを記憶しており、キャッシュから特定のアセット(例:画像やスクリプトソースファイル)を取得できます。V8はそのページで以前提供された同じスクリプトファイルを認識し、ディスクキャッシュとともにコンパイル済みコードをキャッシュします。
  • ホット状態: Chromeがウェブページを3回目に訪問する際、ディスクキャッシュからスクリプトファイルを提供し、前回のロードでキャッシュされたコードをV8に提供します。V8はこのキャッシュされたコードを使用してスクリプトをゼロから解析およびコンパイルする必要がなくなります。

V8 v6.6以前では、トップレベルのコンパイル直後に生成されたコードをキャッシュしていました。V8はトップレベルのコンパイル中にすぐ実行されることが分かっている関数のみをコンパイルし、それ以外の関数には遅延コンパイルを指定します。このため、キャッシュされたコードにはトップレベルのコードのみが含まれ、その他の関数はページロード時に毎回ゼロから遅延コンパイルされる必要がありました。バージョン6.6以降、V8はスクリプトのトップレベル実行後に生成されたコードをキャッシュするようになりました。スクリプトを実行するにつれて、より多くの関数が遅延コンパイルされ、キャッシュに含めることができます。その結果、これらの関数は将来のページロード時にコンパイルする必要がなくなり、ホットロードシナリオでのコンパイル時間と解析時間が20〜60%短縮されます。目に見えるユーザーへの変更としては、メインスレッドの混雑が軽減され、スムーズで高速な読み込み体験が実現します。

このテーマについての詳細なブログ投稿が近日公開される予定ですので、ぜひご期待ください。

バックグラウンドコンパイル

V8は以前よりバックグラウンドスレッドでJavaScriptコードを解析する機能を提供していました。V8の新しいIgnitionバイトコードインタープリタが昨年導入されたことで、バックグラウンドスレッドでJavaScriptソースコードをバイトコードにコンパイルする機能もサポートされました。これにより、埋め込む側はメインスレッドをより多くのJavaScriptを実行するために解放し、jankを削減するための作業をバックグラウンドで実行できます。この機能はChrome 66で有効になり、一般的なウェブサイトにおいてメインスレッドコンパイル時間が5%から20%削減されています。詳細についてはこの機能に関する最近のブログ投稿をご覧ください。

ASTナンバリングの削除

昨年のIgnitionとTurboFanの導入後、コンパイルパイプラインを簡素化することで引き続きメリットを享受しています。以前のパイプラインでは「ASTナンバリング」と呼ばれるポスト解析段階が必要でした。この段階では、生成された抽象構文木(AST)のノードに番号を付け、それを使用する様々なコンパイラが共通の参照ポイントを持つようにしていました。

しかし時間の経過とともに、この後処理段階は他の機能を含むようになりました。ジェネレーターや非同期関数の停止ポイントのナンバリング、急なコンパイル用内部関数の収集、リテラルの初期化や最適化不可能なコードパターンの検出などが追加されました。

新しいパイプラインでは、Ignitionバイトコードが共通の参照ポイントとなり、ナンバリングそのものが不要となりました。ただし、残りの機能は依然として必要であり、ASTナンバリングパスは維持されていました。

V8 v6.6では、残りの機能を移動または廃止することがようやく成功し、このツリーウォークを削除できました。これにより、実際のコンパイル時間が3〜5%改善されました。

非同期パフォーマンスの改善

プロミスと非同期関数のパフォーマンスを向上させることができ、特に非同期関数と簡略化されたプロミスチェーンの間の差を埋めることができました。

Promiseのパフォーマンス改善

さらに、非同期ジェネレーターや非同期イテレーションのパフォーマンスが大幅に改善され、V8 v6.6を含む予定のNode 10 LTSで利用可能な選択肢になりました。例えば、以下のフィボナッチ数列の実装をご覧ください。

async function* fibonacciSequence() {
for (let a = 0, b = 1;;) {
yield a;
const c = a + b;
a = b;
b = c;
}
}

async function fibonacci(id, n) {
for await (const value of fibonacciSequence()) {
if (n-- === 0) return value;
}
}

このパターンについて、Babelトランスパイレーション前後で次の改善を測定しました。

非同期ジェネレーターのパフォーマンス改善

最後に、ジェネレーターや非同期関数、モジュールなどの「停止可能関数」に対するバイトコード改善により、インタープリタ実行中のこれらの関数のパフォーマンスが向上し、コンパイルサイズが縮小しました。今後のリリースでは非同期関数や非同期ジェネレーターのパフォーマンスをさらに向上させる予定ですので、ご期待ください。

配列のパフォーマンス改善

Array#reduceのスループット性能が穴あきの2倍配列に対して10倍以上向上しました(穴あき配列とパックされた配列が何であるかの説明はこちらをご参照ください)。これにより、Array#reduceが穴あき、そしてパックされた2倍配列に適用される場合のファストパスが拡大されました。

Array.prototype.reduceのパフォーマンス改善

信頼できないコードへの緩和措置

V8 v6.6では、信頼できないJavaScriptおよびWebAssemblyコードに情報漏洩を防ぐためのサイドチャネル脆弱性に対するさらなる緩和策を導入しました。

GYPの削除

これがGYPファイルを公式に含まない最初のV8バージョンです。削除されたGYPファイルが製品に必要な場合は、独自のソースリポジトリにコピーする必要があります。

メモリプロファイリング

ChromeのDevToolsでは、C++ DOMオブジェクトをトレースおよびスナップショットし、JavaScriptからの参照を含む、到達可能なすべてのDOMオブジェクトを表示できるようになりました。この機能は、V8のガーベッジコレクターに追加された新しいC++トレースメカニズムのメリットの1つです。詳細については専用のブログ投稿をご覧ください。

V8 API

git log branch-heads/6.5..branch-heads/6.6 include/v8.hを使用して、API変更の一覧を取得してください。