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

「内部構造」タグの記事が17件件あります

全てのタグを見る

陸地が見えた:Sea of Nodesを離れて

· 約38分
ダリウス・メルカディエ

V8の最上位最適化コンパイラTurbofanは、Sea of Nodes (SoN)を使用する数少ない大規模プロダクションコンパイラの1つとして知られています。しかし、約3年前からSea of Nodesを廃止し、より伝統的な制御フローグラフ (CFG) 中間表現 (IR)に戻りました。それをTurboshaftと名付けました。現在では、TurbofanのJavaScriptバックエンド全体がTurboshaftを使用しており、WebAssemblyはその全パイプラインを通じてTurboshaftを使用しています。Turbofanの2つの部分ではまだSea of Nodesが一部使用されています。1つは組み込みパイプラインで、これをTurboshaftに置き換えつつあります。もう1つはJavaScriptパイプラインのフロントエンドで、これをMaglevという別のCFGベースのIRに置き換えています。このブログ記事では、Sea of Nodesを廃止することになった理由を説明します。

可変ヒープ数でV8をターボチャージ

· 約7分
[Victor Gomes](https://twitter.com/VictorBFG)、ビットシフター

V8では、JavaScriptのパフォーマンス向上に常に努めています。この努力の一環として、最近JetStream2のベンチマークスイートを見直し、パフォーマンスの問題を解消しました。この投稿では、async-fsベンチマークで大幅な2.5倍の改善を達成し、全体スコアに著しい向上をもたらした特定の最適化について詳しく説明します。この最適化はベンチマークから着想を得ましたが、実際のコードでも類似のパターンが見られます。

新しいクラス機能を使用するインスタンスの初期化がより高速に

· 約15分
[Joyee Cheung](https://twitter.com/JoyeeCheung), インスタンス初期化担当

クラスフィールドはV8 v7.2以降でサポートされ、プライベートクラスメソッドはv8.4以降でサポートされています。提案が2021年にステージ4に到達してから、新しいクラス機能のサポートを改善する作業が開始されました。それまでに、この採用に影響を与える2つの主な問題がありました:

V8におけるポインタ圧縮

· 約27分
Igor SheludkoとSantiago Aboy Solanes、*ポインタ圧縮の達人*

メモリとパフォーマンスの間には常に戦いがあります。ユーザーとしては、速度が速いことを望むと同時に、できるだけ少ないメモリ消費で済ませたいと思います。しかし、通常、パフォーマンスを向上させるにはメモリ消費の代償が伴い(その逆も然り)、ジレンマを抱えることになります。

軽量化されたV8

· 約15分
Mythri Alle, Dan Elphick, および [Ross McIlroy](https://twitter.com/rossmcilroy), V8軽量化チーム

2018年末、私たちはV8のメモリ使用量を劇的に削減することを目指してV8 Liteというプロジェクトを開始しました。このプロジェクトは当初、低メモリモバイルデバイスやメモリ使用量の削減を重視したエンベッダー利用ケース向けに、V8の別のLiteモードとして構想されていました。しかし、この作業の過程で、このLiteモードのために行った多くのメモリ最適化が、通常のV8にも適用可能であり、V8のすべてのユーザーに利益をもたらせることに気付きました。

WebAssembly開発者のためのコードキャッシュ

· 約13分
[ビル・バッジ](https://twitter.com/billb)、キャッシュにCa-ching!を加える

開発者の間で「最も速いコードは実行されないコードだ」という言葉があります。同様に、最も速いコンパイルコードは、コンパイルする必要がないコードです。WebAssemblyコードキャッシュはChromeとV8における新しい最適化技術で、コンパイラによって生成されたネイティブコードをキャッシュすることでコードのコンパイルを回避することを目指しています。以前、ChromeとV8がJavaScriptコードをキャッシュする方法や、これらの最適化を活用するためのベストプラクティスについて執筆 しました 今回のブログ記事では、ChromeのWebAssemblyコードキャッシュの動作と、大規模なWebAssemblyモジュールを持つアプリケーションの読み込みを高速化するために、開発者がこれをどのように活用できるかを説明します。

信じられないほど速いパース、パート2:遅延パース

· 約20分
Toon Verwaest ([@tverwaes](https://twitter.com/tverwaes)) と Marja Hölttä ([@marjakh](https://twitter.com/marjakh))、パーサー

V8がJavaScriptを可能な限り高速に解析する方法を説明するシリーズの第二部です。第一部では、V8のスキャナを高速化する方法について説明しました。

パースは、ソースコードをコンパイラ(V8ではバイトコードコンパイラのIgnition)が利用できる中間表現に変換するステップです。パースとコンパイルはウェブページのスタートアップの重要なプロセスであり、ブラウザに送られるすべての関数がスタートアップ時にすぐに必要になるわけではありません。開発者が非同期や遅延スクリプトを使用してそのようなコードを遅らせることができますが、それが常に可能とは限りません。また、多くのウェブページでは、特定の機能でのみ使用されるコードが含まれており、ユーザーがそのページを利用する間に一度もアクセスされない可能性があります。

V8でのソートの整理

· 約24分
Simon Zünd([@nimODota](https://twitter.com/nimODota))、一貫性のある比較関数

Array.prototype.sortは、V8でセルフホスティングJavaScriptで実装された最後のビルトインの1つでした。このポート作業を通じて、異なるアルゴリズムや実装戦略を試す機会を得、それを最終的にV8 v7.0 / Chrome 70で安定化することができました。

埋め込み組み込み機能

· 約16分
Jakob Gruber ([@schuay](https://twitter.com/schuay))

V8の組み込み関数(組み込み機能)は、V8のすべてのインスタンスでメモリを消費します。組み込み機能の数、平均サイズ、およびChromeブラウザータブごとのV8インスタンス数は大幅に増加しています。本ブログ記事では、過去1年間でウェブサイトごとのV8ヒープサイズの中央値を19%削減した方法について説明します。

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

· 約7分
[Ross McIlroy](https://twitter.com/rossmcilroy), メインスレッド擁護者

要約: Chrome 66から、V8がJavaScriptのソースコードをバックグラウンドスレッド上でコンパイルするようになり、典型的なウェブサイトでメインスレッドのコンパイル時間が5%から20%短縮されました。

背景

バージョン41以降、ChromeはV8のStreamedSource APIを通じてバックグラウンドスレッドでのJavaScriptソースファイルの解析をサポートしています。これは、Chromeがネットワークからファイルの最初のチャンクをダウンロードするとすぐに、V8がJavaScriptソースコードの解析を開始できるようにし、Chromeがネットワーク経由でファイルをストリームする間に並行して解析を継続することを可能にします。これにより、V8がJavaScriptの解析をほぼ完了している状態でファイルのダウンロードが終了するため、読み込み時間が大幅に改善される場合があります。

しかし、V8の元々のベースラインコンパイラの制限により、V8はまだメインスレッドに戻り、解析を最終化し、スクリプトのコードを実行するためのJITマシンコードにコンパイルする必要がありました。Ignition + TurboFanパイプラインへの移行により、バイトコードコンパイルをバックグラウンドスレッドに移動することが可能になり、これによりChromeのメインスレッドが解放され、よりスムーズで反応の良いウェブブラウジング体験が提供されるようになりました。

バックグラウンドスレッドバイトコードコンパイラの構築

V8のIgnitionバイトコードコンパイラは、パーサーによって生成された抽象構文木(AST)を入力として受け取り、JavaScriptソースを実行するための関連メタデータとともにバイトコード(BytecodeArray)のストリームを生成します。

Ignitionのバイトコードコンパイラは、マルチスレッドを念頭に置いて構築されていますが、バックグラウンドコンパイルを可能にするためにはコンパイルパイプライン全体でいくつかの変更が必要でした。主な変更の1つとして、バックグラウンドスレッドで実行中のコンパイルパイプラインがV8のJavaScriptヒープ内のオブジェクトにアクセスすることを防ぐ必要がありました。JavaScriptがシングルスレッドであるため、V8のヒープ内のオブジェクトはスレッドセーフではなく、バックグラウンドコンパイル中にメインスレッドやV8のガーベッジコレクターによって変更される可能性があります。

コンパイルパイプラインには、V8のヒープ上のオブジェクトにアクセスする主な段階が2つありました: AST内部化とバイトコード最終化です。AST内部化は、ASTで識別されたリテラルオブジェクト(文字列、数字、オブジェクトリテラルなど)をV8ヒープに割り当てるプロセスであり、スクリプトが実行されるときに生成されたバイトコードによって直接使用できるようにします。このプロセスは従来、パーサーがASTを生成した直後に行われていました。そのため、コンパイルパイプラインの後続のステップでは、リテラルオブジェクトが割り当てられていることを前提としていました。バックグラウンドコンパイルを可能にするために、AST内部化をコンパイルパイプラインの後の段階、バイトコードがコンパイルされた後に移動しました。これにより、パイプラインの後続の段階で、ヒープ上で内部化された値ではなく、ASTに埋め込まれた_raw_リテラル値にアクセスするよう変更が必要でした。

バイトコード最終化は、関連するメタデータ(例: バイトコードが参照する定数を格納するConstantPoolArrayや、JavaScriptソースの行番号と列番号をバイトコードのオフセットにマッピングするSourcePositionTable)とともに関数を実行するために使用される最終的なBytecodeArrayオブジェクトを構築するプロセスです。JavaScriptが動的な言語であるため、これらのオブジェクトはすべてJavaScriptヒープ内に存在し、バイトコードが関連付けられたJavaScript関数が収集される場合にガーベッジコレクションが可能である必要があります。従来、これらのメタデータオブジェクトのいくつかはバイトコードコンパイル中に割り当てられ、変更されるプロセスが含まれており、これにはJavaScriptヒープへのアクセスが必要でした。バックグラウンドコンパイルを可能にするために、Ignitionのバイトコードジェネレーターはこれらのメタデータの詳細を追跡し、それらを完全なコンパイルプロセスの最終段階までJavaScriptヒープ上に割り当てることを遅らせるようにリファクタリングされました。

これらの変更により、ほとんどすべてのスクリプトのコンパイルをバックグラウンドスレッドに移動することが可能となり、メインスレッドで実行されるのは短いAST内部化のステップとバイトコード最終化ステップのみとなり、それはスクリプト実行の直前に行われます。

現在のところ、トップレベルのスクリプトコードと即時呼び出し関数式(IIFE)のみがバックグラウンドスレッドでコンパイルされます。内部関数は依然として(最初に実行されたときに)メインスレッドで遅延コンパイルされます。将来的には、バックグラウンドコンパイルをより多くの状況に拡張することを目指しています。しかし、これらの制限がある場合でも、バックグラウンドコンパイルはメインスレッドをより長く自由にし、ユーザーインタラクションへの反応、アニメーションのレンダリング、またはそれ以外の場合でもスムーズで応答性の高い体験を提供するための作業を可能にします。

結果

人気のあるウェブページのセットを対象にした私たちの実世界ベンチマークフレームワークを使用して、バックグラウンドコンパイルのパフォーマンスを評価しました。

バックグラウンドスレッドでコンパイルできる対象は、トップレベルのストリーミングスクリプトコンパイル中にコンパイルされたバイトコードの割合と、呼び出された内部関数として遅延コンパイルされる割合(メインスレッドで実行する必要がある部分)によって異なります。そのため、メインスレッドで節約される時間の割合も異なり、多くのページではメインスレッドのコンパイル時間が5%から20%の範囲で削減されます。

次のステップ

バックグラウンドスレッドでスクリプトをコンパイルするより良い方法は何でしょうか?スクリプトをまったくコンパイルする必要がないことです!バックグラウンドコンパイルと並行して、V8のコードキャッシングシステムを改良し、V8によってキャッシュされるコードの量を拡大することで、頻繁に訪問するサイトのページ読み込みを高速化する作業も行っています。この分野の進捗については、近々お知らせできることを期待しています。お楽しみに!