JavaScript エンジンはコードをどのように解析するのでしょうか?

まずはJSエンジンについて知る

1. なぜ JS エンジンが必要なのでしょうか?

より高度なプログラミング言語は、実際には人間の思考に近い言語ですが、この種の言語は一般にコンピューターには理解されず、0と1を含む機械命令のみがコンピューターに受け入れられるため、高度なプログラミング言語は必要です最終的にはマシン命令に転送されて実行されます。
jsコードはブラウザに渡されても、ノードに渡されて実行されても、最終的にはCPUに渡されて実行されますが、CPUは自身の命令セット、つまり0と1を含む機械語しか理解できません。現時点では、JavaScript コードを CPU 命令に変換して実行するために、JavaScript エンジンが必要です。

2. 一般的な JavaScript エンジン

SpiderMonkey: JavaScript 作者によって開発された最初の JavaScript エンジン
Chakra: Microsoft によって開発され、IE ブラウザで使用されています
JavaScriptCore: WebKit に組み込まれた JavaScript エンジン、
Apple によって開発された V8: Google によって開発された強力な JavaScript エンジン。ブラウザ

3. ブラウザカーネルとJSエンジンの関係

Webkit を例に挙げます。
ここに画像の説明を挿入

2. V8エンジン

1. V8エンジンの原理

V8 エンジンは、C++ で書かれた Google のオープンソースの高性能 JavaScript および WebAssembly エンジンで、Chrome や Node.js などで使用されます。
ECMAScript と WebAssembly を実装しており、x64、IA-32、ARM、または MIPS プロセッサを使用する Windows 7 以降、macOS 10.12 以降、および Linux システム上で実行されます。
V8 エンジンは独立して実行することも、任意の C++ アプリケーションに埋め込むこともできます。たとえば、V8 エンジンでの Node.js の使用は、V8 エンジンをアプリケーションに埋め込むこととみなすことができ、Node.js には JavaScript コードを実行する機能があります。

回路図:

ここに画像の説明を挿入
1. インタプリタは JavaScript コードを直接理解しないため、Parse モジュールは JavaScript コードを AST に変換します。関数が呼び出されないとASTに変換されません。
②、IgnitionはASTをByteCodeに変換するインタープリタです。同時に、TurboFan の最適化に必要な情報 (関数パラメーターの型情報など、その型のみで実際の操作が実行できる) が収集されます。関数が 1 回だけ呼び出された場合、Ignition は AST を ByteCode に変換します
③ 最終的にマシン コードに直接変換せずにバイトコードに変換するのはなぜですか?
JSコードが実行される環境は固定されておらず、Windows環境、Mac環境、Linux環境を利用したブラウザ上で実行される場合や、Node.js上で実行される場合もあり、環境が固定されておらず、異なります。環境 CPU が異なれば CPU アーキテクチャも異なり、アーキテクチャが異なれば異なる機械命令を実行できます。
ここに画像の説明を挿入
V8 エンジンが指定したバイトコードに変換されることで、どの環境でも実行可能かつクロスプラットフォームであり、最後に V8 エンジンがバイトコードをアセンブリ命令に変換し、さらに異なる環境に対応した CPU 命令に変換します。
しかし、毎回このプロセスを実行するのはまだ十分便利ではありません。たとえば、繰り返し使用される関数がありますが、以前の一連のプロセスを使用すると、この関数を使用するたびにバイトコードに変換し、その後 CPU 命令に変換する必要があり、この関数を使用するとパフォーマンスが相対的に低くなります。直接実行可能 機械語命令に変換して保存します この機能を使用すると、機械語命令が直接実行され、比較的パフォーマンスが高くなります ただし、この関数が一度だけ実行される場合は、機械語に変換する必要はありませんコードを作成して保存すると、スペースが無駄になります。
④. TurboFan ライブラリを使用します, これはバイトコードを CPU によって直接実行できるマシンコードにコンパイルするコンパイラです. 彼は ignition を使用して関数の実行情報を収集し、どの関数がより頻繁に実行されるかを知ることができます. 関数はマークされていますホット、ホット関数として実行すると、この関数は最適化された機械語命令に変換され、今後このホット関数を使用する場合には、上記の面倒な処理が不要となり、機械語命令を直接実行することができます。
ただし、実際には機械語コードも ByteCode に戻されますが、これは、その後の関数の実行中に型が変更されると、以前に最適化された機械語コードでは正しく処理できなくなり、バイトコードに逆変換されるためです。
⑤、非最適化:例えばこんな機能があります

function  sum(num1,num2){
    
    
   num1+num2
}

sum関数を呼び出す

sum(20,30)
sum(28,30)

数値が渡されて sum 関数が呼び出された場合、実行する必要がある作業は 2 つの数値を加算することであり、実行される機械命令は常に 2 つの数値を加算することになります。受信値の型が変更されると
、 string になる場合、この関数の意味は 2 つの文字列を連結することです。

sum("aaa","bbb")

この 2 種類の入力値の「+」演算に対応する機械語命令は異なります。JavaScript は入力値の種類を検出しないため、数値を加算する機械語命令が引き続き使用されます。今回は関数呼び出しです。結果は使えません。
しかし、V8 エンジンでは、機械語命令の実行時に実行された演算が異なることが判明した場合に、逆最適化してバイトコードに変換して後続の演算を実行する、逆最適化プロセスという解決策を提供します。

2. V8エンジンの解析図

ここに画像の説明を挿入

V8 実装の詳細:

①、Blink がソースコードを V8 エンジンに引き渡し、Stream がソースコードを取得してエンコード変換を実行します。
②、スキャナーが字句解析を実行し、その後コードがトークンに変換されます
。 ③、トークンが AST に変換されますParser と PreParser の後のツリー:
Parser はトークンを AST ツリー構造に直接変換します;
PreParser の事前解析、なぜ事前解析が必要ですか?
1) 上図の関数 inner() に示されているように、内部には関数 inner() がありますが、inner() を呼び出すコードはありません。つまり、最初にすべての JavaScript コードが実行されるわけではありません。すべての JavaScript コードを解析すると、Web ページの動作効率に確実に影響します。
2) V8 エンジンは、不要な関数を事前に解析するために使用される Lazy Parsing (遅延解析) ソリューションを実装しています。そのような機能があることを知っておくだけで済みます。つまり、一時的に必要なコンテンツのみを解析するだけです。関数が呼び出されたときに実行される関数を完全に解析します。
3) 例えば、上図の関数 external 内の inner 関数では、事前解析が行われます。
④ASTツリー生成後はIgnitionによりバイトコードに変換され、その後の処理がコードの実行処理となります

おすすめ

転載: blog.csdn.net/weixin_45172119/article/details/128808039