レジスタベースの仮想マシンとスタックベースの仮想マシンを使用することの利点と欠点は何ですか?
私には、レジスター・ベースのマシンの方がプログラミングがより簡単で効率的であるように思えます。では、JVM、CLR、および Python VM がすべてスタックベースであるのはなぜでしょうか?
レジスタベースの仮想マシンとスタックベースの仮想マシンを使用することの利点と欠点は何ですか?
私には、レジスター・ベースのマシンの方がプログラミングがより簡単で効率的であるように思えます。では、JVM、CLR、および Python VM がすべてスタックベースであるのはなぜでしょうか?
ハードウェアに実装されたレジスタベースのマシンは、より低速な RAM へのアクセスが少ないため、より効率的になります。ただし、ソフトウェアでは、レジスタ ベースのアーキテクチャであっても、RAM に「レジスタ」が存在する可能性が高くなります。その場合、スタックベースのマシンは同じくらい効率的です。
さらに、スタックベースの VM により、コンパイラの作成がはるかに簡単になります。レジスタ割り当て戦略を扱う必要はありません。基本的に、操作するレジスタの数に制限はありません。
更新:解釈された VM を想定してこの回答を書きました。JIT でコンパイルされた VM には当てはまらない場合があります。私は、JIT コンパイルされた VM がレジスタ アーキテクチャを使用するとより効率的である可能性があることを示していると思われるこの論文に出くわしました。
これは、Parrot VM の FAQ と関連ドキュメントで、ある程度までは既に回答されています 。A Parrot Overview そのドキュメントの関連テキストは次のとおりです。
Parrot VM には、スタック アーキテクチャではなく、レジスタ アーキテクチャがあります。また、Perl や Python などの中レベルの操作よりも Java に似た、非常に低レベルの操作も含まれます。
この決定の主な理由は、基礎となるハードウェアをある程度類似させることによって、Parrot バイトコードを効率的なネイティブ マシン言語にコンパイルできることです。
さらに、高水準言語の多くのプログラムは、ネストされた関数とメソッドの呼び出しで構成されており、中間結果を保持するためのレキシカル変数を使用する場合もあります。非 JIT 設定では、スタックベースの VM は同じオペランドを何度もポップしてからプッシュしますが、レジスターベースの VM は単純に適切な量のレジスターを割り当ててそれらを操作するため、操作量を大幅に削減できます。そしてCPU時間。
これも読みたいかもしれません: Registers vs stacks for interpreter design 少し引用:
間違いなく、スタック マシン用のコードを生成する方が簡単です。ほとんどの新入生のコンパイラ学生はそれを行うことができます。レジスタ マシンのコードを生成するのは、アキュムレータを備えたスタック マシンとして扱わない限り、少し難しくなります。(これは実行可能ですが、パフォーマンスの観点からは理想的とは言えません) ターゲティングの単純さは、少なくとも私にとってはそれほど大きな問題ではありません。さあ、あなたは何人の人が実際にコンパイラを書き込もうとしている人を知っていますか? 数は少ないです。もう 1 つの問題は、コンパイラの知識を持つ人々の多くは、一般的に使用されているすべてのハードウェア CPU がレジスタ マシンであるため、レジスタ マシンをターゲットにすることに慣れていることです。
従来、仮想マシンの実装者は、「VM 実装の単純さ」により、レジスターベースよりもスタックベースのアーキテクチャーを好んでいました。これは、コンパイラーのバックエンドを簡単に作成できるためです。ほとんどの VM は、元来、単一の言語とコード密度、およびスタック アーキテクチャー用の実行可能ファイルをホストするように設計されています。レジスタ アーキテクチャの実行可能ファイルよりも常に小さいです。シンプルさとコード密度は、パフォーマンスのコストです。
調査によると、登録ベースのアーキテクチャでは、スタックベースのアーキテクチャよりも実行される VM 命令が平均 47% 少なくて済み、レジスタ コードは対応するスタック コードよりも 25% 大きくなりますが、コードが大きくなるため、より多くの VM 命令をフェッチするコストが増加します。サイズは、VM 命令ごとにわずか 1.07% の余分な実際のマシン負荷を伴いますが、これは無視できます。レジスタ ベースの VM の全体的なパフォーマンスは、標準的なベンチマークを実行するのにかかる時間が平均で 32.3% 少ないことです。
スタックベースの VM を構築する理由の 1 つは、実際の VM のオペコードをより小さく簡単にできる (オペランドをエンコード/デコードする必要がない) ことです。これにより、生成されるコードが小さくなり、VM コードも単純になります。
レジスターは何個必要ですか?
それよりも少なくとも 1 つ必要になると思います。
スタック ベースの VM はよりシンプルで、コードははるかにコンパクトです。実際の例として、ある友人が (約 30 年前に) Cosmac 上に自作の Forth VM を使用してデータ ロギング システムを構築しました。Forth VM は、2k の ROM と 256 バイトの RAM を備えたマシン上で 30バイトのコードでした。
「レジスタベース」の仮想マシンが「プログラミングがより簡単」または「より効率的」になるかどうかは、私には明らかではありません。おそらく、仮想レジスターが JIT コンパイル段階でショートカットを提供すると考えているでしょうか? 実際のプロセッサのレジスタは VM よりも多い場合も少ない場合もあり、それらのレジスタはさまざまな方法で使用される可能性があるため、これは当てはまりません。(例: デクリメントされる値は、x86 プロセッサの ECX レジスタに配置するのが最適です。) 実際のマシンが VM よりも多くのレジスタを持っている場合、リソースを浪費していることになり、「レジスタ」を使用しても何も得られません。ベース」プログラミング。
スタック ベースの VM は、コードの生成が簡単です。
レジスタ ベースの VM は、高速な実装を簡単に作成でき、高度に最適化されたコードを簡単に生成できます。
最初の試行では、スタック ベースの VM から始めることをお勧めします。