web-dev-qa-db-ja.com

VMが「スタックマシン」や「レジスタマシン」などである必要があるのはなぜですか。

(これは非常に初心者向けの質問です)。

私は仮想マシンについて少し勉強してきました。

それらの多くは、物理的または理論的なコンピューターと非常によく似て設計されています。

たとえば、JVMは「スタックマシン」であると読みました。つまり、それがすべての「一時メモリ」をスタックに格納し、すべてのオペコードに対してこのスタックで操作を行うということです(私が間違っている場合は修正してください)。

たとえば、ソースコード2 + 3は次のようなバイトコードに変換されます:

Push 2
Push 3
add

私の質問はこれです:

JVMはおそらくC/C++などを使用して記述されています。もしそうなら、JVMが次のCコードを実行しないのはなぜですか:2 + 3 ..?つまり、なぜ物理コンピューターのように、スタックや他のVMの「レジスター」が必要なのでしょうか。

基盤となる物理CPUがこれをすべて処理します。 VMライターは、VMがプログラムされている言語で「通常の」命令を使用して、解釈されたバイトコードを単に実行しないのですか?

実際のハードウェアが既にハードウェアを実行しているのに、なぜVMはハードウェアをエミュレートする必要があるのですか?

繰り返しますが、非常に初心者向けの質問です。ご協力いただきありがとうございます

48
Aviv Cohn

仮想かどうかにかかわらず、マシンは計算のモデルを必要とします。定義により、計算するとすぐに、いくつかの計算モデルが実装されます。次に問題は次のとおりです。VMにはどのモデルを選択すればよいですか物理マシンは、ハードウェアで効果的かつ効率的に実行できるものによって制約されます。ただし、お気づきのとおり、仮想マシンにはそのような制約はありません。仮想マシンは、任意の高水準言語を使用してソフトウェアで定義されます。

実際、あなたが説明するように高レベルの仮想マシンがあります。 これらはプログラミング言語と呼ばれます。たとえばC標準は、そのページの大部分を、Cプログラムの動作、および拡張(as-ifルール)によるCコンパイラ(またはインタープリター)の動作を記述する、いわゆる「C抽象マシン」のモデルの定義に特化しています。動作するはずです。

もちろん、通常はそれを仮想マシンとは呼びません。 A VMは通常、効率的に実行されるように設計された、直接プログラミングすることを意図していない、より低レベルのハードウェアに近いものを意味します。この選択バイアスは、高レベルの構成可能なコード(記述したものと同様)は、VM becauseは高レベルのコードを実行する)とは見なされません。

しかし、要点を説明するために、VM(バイトコードコンパイラのターゲットなど)をレジスタベースなどにする理由)をいくつか示します。スタックおよびレジスタマシンは非常にシンプルです。 。各命令には一連の命令、いくつかの状態、およびセマンティクスがあります(関数の状態->状態)。複雑なツリーの削減はなく、演算子の優先順位はありません。最小の言語であるため、構文解析、分析、および実行は非常に簡単です(構文砂糖はコンパイルされます)、人間が読むのではなく、機械が読むように設計されています。

対照的に、最も単純なCのような言語でさえ解析は非常に困難であり、それを実行するには、型のチェックと伝播、オーバーロードの解決、シンボルテーブルの維持、string識別子の解決、線形変換などの非ローカル分析が必要です。優先順位駆動型ASTへのテキストなど。人間にとって当たり前のコンセプトに基づいていますが、機械によって徹底的にリバースエンジニアリングする必要があります。

たとえば、JVMバイトコードはjavacによって発行されます。人間が読んだり書いたりする必要はほとんどないので、機械で消費するように調整するのが自然です。人間向けに最適化した場合、JVMはすべての起動時にコードを読み取り、それを解析して分析し、そのような簡略化されたマシンモデルに似た中間表現に変換しますとにかく。真ん中の男も切り抜くかもしれない。

51
user7043

この回答はJVMに焦点を当てていますが、実際には、どのVMにも適用されます。

実際のハードウェアが既にハードウェアを実行しているのに、なぜVMはハードウェアをエミュレートする必要があるのですか?

そうではありませんが、VMははるかにシンプルで移植性があります。ハードウェアをエミュレートするVMは、どのハードウェアCPUよりも同じ計算モデルを使用できます。

特に、JVMは移植性を念頭に置いて構築され、実際にはハードウェアでさえ実装できるように構築されました(今日は信じがたいかもしれませんが、 Origin of Java は組み込みの世界にありました) -具体的には、インタラクティブテレビのコントローラー)。

このような目標がある場合、VMは、実際のマシンコードへの変換がより簡単になり、より高速になるため、できるだけ物理マシンに近い場所で動作することが望ましいです。オペコードを取得したらVMの理論上は、プログラムを実際に実行するCPUのオペコードに変換するだけで、実際にはそれほど単純ではありません。

つまり、なぜ物理コンピューターのように、スタックや他のVMの「レジスター」が必要なのでしょうか。

スタックベースの仮想マシンモデルを使用すると、レジスタマシンとスタックマシンの両方に簡単に転送できるという利点がありますが、その逆は必ずしも当てはまりません。レジスタベースのVMは、レジスタの数、レジスタのサイズなどを想定する必要があります。スタックマシンでは、そのような想定は必要ありません。

基盤となる物理CPUがこれをすべて処理します。 VMライターは、VMがプログラムされている言語で「通常の」命令を使用して、解釈されたバイトコードを単に実行しないのですか?

まあ、それはそのようなVMが行うことです、彼らはバイトコードを解釈します。 JVMでも実際には、少なくともJIT(ジャストインタイム)が始まる前に、バイトコードを解釈し、JVMが記述された言語(通常はCまたはC++)でステートメントを実行しますが、1つでも記述されていますJavaScriptでは、 Doppio )です。ただし、そのようなステートメントでもコンパイラーによってマシンコードに変換され、実際にはJavaコンパイラーが生成するものと非常によく似ています。つまり、レジスターとスタックを使用して作業を実行します。この時点で、「解釈された」言語と「コンパイルされた」言語の使用が やや不鮮明 になることに注意してください。

20
miraculixx

VMが「スタックマシン」または「マシンの登録」などである必要があるのはなぜですか?

彼らはしない。仮想マシンが必要な場合は、何でもかまいません。

既存の仮想マシンは、次のような状況の解決策として登場しました本当に素晴らしいアイデアが頭に浮かんだので、新しいプログラミング言語を発明しました!しかし、コードを生成する必要があります。醜いのでi8086コードを生成したくありません。他の皆がIntelを使用しているため、68kコードを生成したくありません。VAXもありますが、コンピュータもVAXブックもありません。したがって、物理的に存在しない一部のプロセッサのコードを生成し、そのプロセッサをソフトウェアに実装します。そのVMの仕様は、私の論文の章を作成します。理論的には、コンパイルすることは可能です。任意のプロセッサのネイティブコードに変換しますが、それは私にはなりません。

一方、「2 + 3」のような表記は、何かが実行される前に多くの変換を行うことを意味するため、近い将来、VMによって使用されなくなる可能性があります。

11