web-dev-qa-db-ja.com

JITされたバイトコードは正確に何をすべきですか?

私はJITingを実装する予定のVM(およびそのためのスクリプト言語)に取り組んでいます。現在はその「配管」にのみ取り組んでいますが、私はしていません。 JITコンパイラを後から付け加えたいと思っていますが、その基本は理解していますが、JITが正確に何をすべきかについて少し混乱しています。

それが実装されていると私が考えることができる2つの方法があります:

  1. 他のコンパイラと同じように、バイトコードを「適切な」x86に変換して、インタプリタ/ VMの部分を排除します。
  2. バイトコードをx86に変換してVM関数を呼び出し、何をすべきかを指示します。これにより、インタープリターのオペコードデコード手順が不要になり、内部VM関数の呼び出しに直接進みます。

最初の方法は、本格的なコンパイラを構築するだけでなく、通常はVM機能に依存する高水準言語をコンパイルできる)に関する知識が必要なため、実装が困難です。ネイティブコードにコンパイルされます。

2番目の方法は、実際にプログラムをコンパイルしていないため、実装がはるかに簡単です。対応するオペランドを使用して(内部VMへの)C関数呼び出しのリストを動的に作成し、x86命令を使用して同じ順序で呼び出します。そうでなければ、「デコード」するためにインタプリタが必要になります。

ただし、2番目の実装は明らかに正気のように見えますが、プログラムのパフォーマンスにどれだけ影響するか(または少なくなるか)はわかりません。どの方向を目指すべきですか?注目すべき長所と短所はありますか?

2
Famand

確かに、メソッド2では、単純なバイトコードインタープリターループよりもパフォーマンスが大幅に向上することはありません。本当の利益は方法1を使用することによって得られることになっています。とはいえ、方法1は、役立つライブラリがあるため、最近は以前ほど難しくはありません。

比較的東にあり、優れたパフォーマンスが得られる可能性のある興味深いアプローチの1つは、LLVMを使用してメソッド2を実装し、既存のLLVMコンパイラ(clangなど)を使用して、ネイティブではなくLLVMコードに呼び出す関数をコンパイルすることです。結果、特に関数呼び出しインラインの最適化ステップ。これにより、複雑さをあまり気にすることなく、適度に優れたネイティブコードが得られるはずです。

2
Jules

[〜#〜] gccjit [〜#〜]libjit[〜#〜] llvm [〜 #〜]asmjit 、...バイトコードをCに変換し、実行時にそのCコードを共有ライブラリに動的にコンパイルしてdlopen-ingすることも検討できます。そのプラグインなど...

そのためには、いくつかのコンパイルと最適化の手法を理解する必要があります(特に、バイトコードが、使用するJITライブラリで必要な内部表現から意味的に遠い場合があるため)。