私はインタープリター/コンパイラーを研究していて、JIT-Compilation、特にGoogle ChromeのV8 Javascript Engineに出くわしました。
私の質問は-
私の現在の理解
すべてのJavascriptプログラムは、 ソースコード、その後、実行方法に関係なく、最終的には 機械コード。
どちらも JITコンパイル そして 解釈 このパスに従う必要があるので、JITコンパイルをより高速にするにはどうすればよいですか(また、AITコンパイルとは異なり、JITは時間の制約があるため)?
JIT-Compilationは 比較的古いイノベーション、Wikipediaの JIT-Compilation Article に基づいています。
「最初に公開されたJITコンパイラは、通常、McCarthyによるLISPでの作業に起因するとされています。 1960」
「スモールトーク(c。 1983)JITコンパイルの新しい側面を開拓しました。たとえば、マシンコードへの変換はオンデマンドで行われ、結果は後で使用するためにキャッシュされました。メモリが不足すると、システムはこのコードの一部を削除し、再度必要になったときにコードを再生成します。」
では、なぜJavaScriptが解釈されたのか そもそも?
私は非常に混乱しており、これについて多くの調査を行いましたが、満足のいく答えが見つかりませんでした。
ですから、明確で簡潔な答えをいただければ幸いです。また、通訳、JITコンパイラなどについての補足説明が必要な場合も同様です。
簡単に言えば、JITは初期化時間が長くなりますが、長期的にははるかに高速であり、JavaScriptはもともと長期的な使用を目的としていませんでした。
90年代には、Webサイトの一般的なJavaScriptは、ヘッダーの1つまたは2つの関数になり、少数のコードがonclick
プロパティなどに直接埋め込まれていました。とにかく、ユーザーがページの読み込みに大幅な遅延が発生すると予想していた場合、通常は正しく実行されます。非常に基本的なフォーム検証または住宅ローンの金利計算機のような小さな数学ユーティリティを考えてください。
必要に応じて解釈する方がはるかに簡単で、その日のユースケースに完全に十分なパフォーマンスを提供しました。長時間実行するパフォーマンスが必要な場合は、フラッシュまたはJavaアプレットを使用しました。
2004年のGoogleマップは、JavaScriptを多用した最初のキラーアプリの1つでした。 JavaScriptの可能性に目を見張るものがありましたが、パフォーマンスの問題も際立っていました。 Googleは、ブラウザにJavaScriptのパフォーマンスを向上させるようにしばらく時間を費やしましたが、最終的には競争が最高の動機であり、ブラウザ標準の表で最高の席を与えると決定しました。 ChromeおよびV8は結果として2008年にリリースされました。Googleマップが登場してから11年が経過した今、JavaScriptをそのようなものに不適切と見なされたことを覚えていない新しい開発者がいます。仕事。
関数animateDraggedMap
があるとします。解釈に500ミリ秒、JITコンパイルに700ミリ秒かかる場合があります。ただし、JITコンパイル後、実際に実行されるまでにかかる時間はわずか100ミリ秒です。それが90年代であり、関数を1回だけ呼び出してからページを再ロードする場合、JITはそれだけの価値はありません。それが今日であり、animateDraggedMap
を数百回または数千回呼び出している場合、初期化時の追加の200ミリ秒は意味がなく、ユーザーがマップをドラッグしようとする前にバックグラウンドで実行できます。
実行時に何が行われているのかを理解することで、コードを変更したり、コードの解釈を変更したりして、コンパイル時間より前にわかっているよりも速く実行したり、コンパイルしたりすることができます。
これについてはかなり言えることがある-それはかなりの量の研究の主題である。 で与えられた答えと比較して、私がここで書き始めたという私自身の説明は、違いを理解します:従来のインタープリター、JITコンパイラー、JITインタープリター、およびAOTコンパイラー
非常に簡単に言うと、JavaScriptは当初、JIT用にコンパイルまたは検討されていませんでした。なぜなら、JavaScriptは、複雑で重要なことを意図したものではなかったからです。
の当初の意図 Javaスクリプトは、Webページ上のJavaアプレットにリンクすることでした。ボタンをクリックするか、フォームフィールドに値を入力してJavaアプレットメソッドで機能する機能は、 JavaScriptコードからのアプレットメソッドの呼び出し 。 JavaScriptを介して、アプレットからJavaScriptコードを呼び出す 逆の方法も可能でした 。
JavaScriptの本来の目的は、アプレットとそれらを含むhtmlページをリンクすることでした。このような小さなタスクの場合、優れたパフォーマンスは必要ありません(パフォーマンスが必要な場合は、JITされたアプレットメソッドを呼び出します)。
それは、Netscapeが独自の言語としてJavaScriptを使用して重要な作業を行い、開発のためにそれを促進し始めた後(Netscape Enterprise Serverでの Server Side JavaScript を含む)-ついでに、時間のコンパイル)JavaScriptが深刻なターゲットとして明らかになりました。その後、必要なツールが有用になるまでに何年もかかりました。
変数のタイプがわからない場合、高速なマシンコードを生成することは不可能であるため、JITはJavaScriptに対して高速です。
型情報がない場合、計算にはコストがかかります。例えば、
x + y
xとyについて何も知らなければかなり複雑です。それらは、整数、倍精度浮動小数点数、文字列、またはこの計算に副作用があるオブジェクトです。静的型付けがないので、これは高価な計算です。
ジャストインタイムのコンパイルでは、ランタイム情報を使用して、これをより高速な計算に変えることができます。実行時に、V8は変数のタイプを追跡します。上記のコードが文字列などで数回実行される場合、コンパイラは文字列連結のためのはるかに簡単な命令を実行できます。したがって、コンパイラがx + y
、xとyのさまざまなタイプに分岐する多くのコードを実行する代わりに、コンパイラーは文字列があるかどうかをすばやくチェックし、文字列を具体的に連結する数行のマシンコードを実行します。
たとえば、C++では、変数を宣言する必要があるため、コンパイラはxとyの型を事前に認識しています。そのため、コードを実行する前に、文字列を連結するための最適化されたマシンコードを生成できます。
1)どうすれば標準の解釈よりも速くできますか?さて、考え抜かれた例は次のようになります。 ApplicationCompiledとApplicationInterpretedの2つのアプリケーションがあるとします。これらのプログラムはどちらもまったく同じことを行い、同じソースコードを共有します。 ApplicationCompiledのコンパイルには6秒かかります。
シナリオAのタイミングが次のとおりだとします。
したがって、合計でApplicationCompiledはシナリオA(6秒のコンパイル、4秒の実行)の実行に10秒かかり、ApplicationInterpretedの実行には合計12秒かかります。具体的な例はありませんが、どのケースで上記が当てはまるかはわかりません。また、インタープリターとコンパイラーがどれだけインテリジェントであるかに大きく依存します。
明らかにこれは非常に単純化されていますが、同じ考え方をJITコンパイル/解釈に適用できます。次の質問は、「このブランチをJITコンパイルまたは解釈する必要があるかどうかを低コストでどのように判断するか」です。私はここで私のリーグを抜けています:)
2)そもそもJITコンパイルが使用されなかったのはなぜですか?わからないが、最適化が困難な場合の利用可能な進捗状況のリソースと成熟度の問題だと思います。 JavaScriptのような言語は、これらのような高度な技術を適用します。おそらく、その頃は下にぶら下がっている果物がたくさんあったでしょう。