バイトコードインタープリターを設計するとき、スタックまたは3アドレス形式(または他の何か?)のどちらが優れているかについて、最近のコンセンサスはありますか?私はこれらの考慮事項を見ています:
目的言語は、Javascriptにかなり似た動的言語です。
パフォーマンスは重要ですが、開発のスピードと移植性は今のところもっと重要です。
したがって、実装は当面は厳密にインタプリタになります。リソースが許せば、JITコンパイラは後で来るかもしれません。
インタプリタはCで書かれます。
バイトコードインタープリターを設計するとき、スタックまたは3アドレス形式(または他の何か?)のどちらが優れているかについて、最近のコンセンサスはありますか?私はこれらの考慮事項を見ています:
目的言語は、Javascriptにかなり似た動的言語です。
パフォーマンスは重要ですが、開発のスピードと移植性は今のところもっと重要です。
したがって、実装は当面は厳密にインタプリタになります。リソースが許せば、JITコンパイラは後で来るかもしれません。
インタプリタはCで書かれます。
Luaの進化とLua5.0の実装を読んで、Luaがスタックベースの仮想マシンからレジスタベースの仮想マシンにどのように変化したか、そしてなぜそれを実行してパフォーマンスが向上したかを確認してください。
David Gregg と Roberto Ierusalimschy が行った実験では、同じタスクを実行するために必要なバイトコード命令が少なくて済むため (したがって、デコードのオーバーヘッドが少なくてすむ)、レジスタ ベースのバイトコードの方がスタック ベースのバイトコードよりもうまく機能することが示されています。したがって、3 アドレス形式が明らかに勝者です。
私はこの分野での経験があまりありません (実際にはまったくありません) ので、次のいくつかを自分で確認してください (または、他の誰かが必要に応じて修正してくれますか?)。
現在、私が最も多く扱っている 2 つの言語は C# と Java であるため、自然にそれらの方法論に傾倒しています。ほとんどの人が知っているように、どちらもバイト コードにコンパイルされ、両方のプラットフォーム (CLR と JVM) は JIT を使用します (少なくとも主流の実装では)。また、各プラットフォームのジッターは C/C++ で記述されていると思いますが、確かなことはわかりません。
全体として、これらの言語とそれぞれのプラットフォームは、あなたの状況にかなり似ています (動的な部分を除けば、これが重要かどうかはわかりません)。また、これらは主流の言語であるため、それらの実装は設計のかなり良いガイドになると確信しています。
これで、CLR と JVM の両方がスタックベースのアーキテクチャであることは確かです。私が覚えているスタックベースとレジスタベースの利点のいくつかは次のとおりです。
また、スタックベースの方がもう少し直感的で読みやすいと思いますが、それは主観的なものであり、前に述べたように、まだあまり多くのバイト コードを見たことがありません。
レジスタベースのアーキテクチャのいくつかの利点は次のとおりです。
もちろん、それぞれの欠点を相殺する方法は常にありますが、これらは考慮すべき明らかなことを説明していると思います。
JIT を念頭に置いている場合は、バイトコードが唯一のオプションです。
念のため、私の TIScript: http://www.codeproject.com/KB/recipes/TIScript.aspx とソース: http://code.google.com/p/tiscript/をご覧ください。
OCaml バイトコード インタープリターを見てみましょう。これは、この種のツールの中で最も高速なものの 1 つです。これはほとんどスタック マシンであり、読み込み時にスレッド化されたコードに変換されます (GNU で計算された goto 拡張機能を使用)。Forth のようなスレッド化されたコードを生成することもできますが、これは比較的簡単に行うことができます。
ただし、将来の JIT コンパイルを念頭に置いている場合は、スタック マシンが実際にはフル機能のスタック マシンではなく、式ツリーのシリアル化形式 (.NET CLI など) であることを確認してください。 「スタック」バイトコードを 3 アドレス形式に変換してから、SSA に変換します。