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


48

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

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

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

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

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

push 2
push 3
add

私の質問はこれです:

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

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

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

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


5
仮想マシンのベースを検討しましたか?

5
@MichaelT物理的なマシンですか?
アビブコーン14年

もちろん、ほとんどのJavascript VMはスタックマシンやレジスタマシンではありません。V8/ IonMonkey / Chakraなどは、Javascriptを実装するVMです。「VM」は、設計者が望む任意の言語を実装できる単なるインタプリタまたはJITコンパイラです。
ビリーONeal 14年

@BillyONealたとえば、ある言語のVMを作成し、Cで作成する場合、VMはbytcode行「print "hi"」を解析し、実行printf("hi");します。これはVMと見なされますか?「スタック」や「レジスタ」などはありません。
アビブコーン14年

@Prog:はい、そうです。
ビリーONeal 14年

回答:


51

仮想マシンであろうとなかろうと、マシンには計算の実行方法を記述する計算モデルが必要です。定義により、計算するとすぐに、何らかの計算モデルを実装します。質問は次のとおりです。VMにはどのモデルを選択する必要がありますか?物理マシンは、ハードウェアで効果的かつ効率的に実行できるものに制約されます。ただし、ご指摘のとおり、仮想マシンにはこのような制約はなく、任意の高レベル言語を使用してソフトウェアで定義されます。

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

もちろん、通常は仮想マシンとは呼びません。通常、VMとは、直接プログラムすることを意図したものではなく、効率的に実行されるように設計された、ハードウェアに近い低レベルのものを意味します。この選択バイアスは、高レベルのコードを実行するため、高レベルのコンポーザブルコード(説明したような)を受け入れるものはVM は見なされないことを意味します。

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

対照的に、最も単純なCライクな言語でさえ解析するのは非常に難しく、その実行には型のチェックと伝播、オーバーロードの解決、シンボルテーブルの維持、文字列識別子の解決、線形テキストの優先順位駆動型ASTへの変換などの非ローカル分析が必要です、 等々。それは人間にとって自然な概念に基づいて構築されていますが、機械によって骨の折れるリバースエンジニアリングが必要です。

たとえば、JVMバイトコードはによって発行されjavacます。人間が読み書きする必要はほとんどないので、機械による消費に合わせて調整するのが自然です。それを人間向けに最適化すると、JVMはスタートアップのたびにコードを読み取り、解析し、分析し、とにかくそのような単純化されたマシンモデルに似た中間表現に変換します。中間者も切り抜くかもしれません。


だからあなたが言っていることは、すべてをスタック上の命令にコンパイルする(つまり、スタック上のSystem.out.println("hi");ある命令にint a = 7コンパイルされる、スタック上の命令にコンパイルされるなど)ことで、プログラムを簡単かつ効率的に実行できるということですか?
テルアビブコーン

2
@Prog基本的にははい。しかし、実行だけでなく、分析も。プログラムで行われるすべて

それでも、なぜ2 + 3にコンパイルされるのか理解できませんpush 2 push 3 addaddとにかくCコードを実行することにより、最後のステップはJVMによって実行されます2 + 3。JVMのプログラマーがこれを行う他の方法はありません。それを2 + 3にコンパイルして、JVMにCコードを実行させるだけです2 + 3(Cコードで書かれていると仮定して)。
テルアビブコーン

@Prog JVMの作成者は2 + 3、JVMのソースコードを記述することはできません。JVMは、任意の順序で任意の操作を実行するプログラムで動作する必要があるためです。Cソースコードをビルドし、C実装に延期すると、同じ問題がC実装に押し込まれます(効率的にはもちろん、簡単にはできません)。プログラムを解釈し、JITコンパイルできるように、プログラムを記述するデータ構造が必要です。「人間が読み取れるソースコード」は、上記で概説した理由により、データ構造のひどい選択です。

7
@Prog 2 + 3の特定のケースに集中しすぎているようa + bです。その後、追加する値はからではなくi.argument{1,2}、ローカル変数からロードされます。どうfrobnicate(x[i]) + (Foo.bar() * 2)?この設計を使用すると、add(for int)の操作が1つだけで、加数の計算方法とは無関係に機能します。プラス、追加の命令のみリテラル整数は無意味のようになります。その結果は全く同じように(つまり、代わりに事前計算された可能性がありadd(2,3)、それがあるべきpush(5))。

20

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

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

そうではありませんが、VMが非常にシンプルでポータブルになります。ハードウェアをエミュレートするVMは、ハードウェアCPUと同じ計算モデルを使用できます。

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

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

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

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

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

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


もちろん、ソフトウェアで実装できるものはすべて、ハードウェアで実装できます。また、現在のJVM(ホットスポット)はJITコンパイラです-JVM が記述された言語でステートメントを実行しませ。そうすると、Javaはひどく動作し、現在のプラットフォームほど実行可能性はありません。 。(地獄、ほとんどのJavascriptの実装は高速になります)
ビリーONeal 14年

2
@BillyONeal "Java HotSpot VMはメソッドごとにメソッドをコンパイルするのではなく、インタプリタを使用してプログラムをすぐに実行し、実行中にコードを分析してプログラム内の重要なホットスポットを検出します。ホットスポットのグローバルネイティブコード最適化」から引用。oracle.com/technetwork/java/whitepaper-135217.html#2『ホットスポットの検出は、』
miraculixx

はい。「ネイティブコードオプティマイザー」== JITコンパイル。JITがめったに使用されないものを避けるために、「ホット」に見えないコードのインタープリターフェーズがあります。しかし、それはJITがまったく行われないことを意味しません。
ビリーONeal 14年

回答ありがとうございます。あなたの答えから私が収集したのは、VMのハードウェアをエミュレートする理由(別名「スタック」または「レジスタ」など)は、後でバイトコードまたはソースコードを実際のマシンコードに簡単にコンパイルできるためです物理CPU。しかし、それとは別に、VMでハードウェアをエミュレートすることから得られるものはありますか?実際にソフトウェアについて話しているときに、VMを設計している人が「スタックマシン」や「レジスタマシン」などの観点で考える理由がまだわかりません。何か不足していますか?
アビブコーン14年

@Progわかりました、あなたはプログラミング言語を持っています、Xと言います。そのプログラムをどのように実行しますか?ソースを解釈するか、マシンコードにコンパイルするか、中間コードにコンパイルします。別のプログラミング言語Yがあり、Xを使用して実装したい場合。両方の実装がインタープリターである場合、YのインタープリターがXのインタープリターで実行され、これは非常に遅くなります。
18446744073709551615 14年

11

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

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

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

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


回答ありがとうございます。あなたの答えから私が集めたのは、物理CPUをエミュレートするVMを設計する動機は、実際のマシンコードにコンパイルするコンパイラを後で簡単に実装できるためだということです。しかし、それ以外に-「スタックマシン」や「レジスタマシン」などの観点からVMを設計する利点はありますか?
アビブコーン14年

1
レジスタには、理論とデバッグの両方を必要とするレジスタ割り当てアルゴリズムが必要です。スタックマシン(特にゼロオペランドの1つ)は、スタックにデータを配置するだけです。OTOH、ハードウェアは通常、可変サイズのスタックではなく、限られた量のレジスタを実装します。したがって、スタックはソフトウェアにとってより簡単であり、レジスタはハードウェアにとってより容易であり、したがって、おそらく少し高速です。
18446744073709551615 14年

-2

尋ねられた実際の質問に答えるため。「仮想マシン」という用語は、すべてのソフトウェア/ハードウェアがシミュレート/エミュレートされることを意味します。基礎となるソフトウェア/ハードウェアを使用して命令を実行する場合、VMがなく、コンパイラ/インタープリターがあります。


これは単にあなたの意見ですか、それとも何らかの形でバックアップできますか?
gnat

@Kyrelelそれは真実ではありません。「すべて」のハードウェアは「システム」または「フル」VMでエミュレートされます。すべてのVMがいっぱいではありません。たとえば、ハードウェアがエミュレートされていないにもかかわらず、BSD VMレイヤーの名前は「仮想マシン」です。
Netch

私は質問が専門用語について必ずしもあるとは思わないが、むしろ仮想マシンは、一見、既に実際のハードウェアで処理された機能を実装する理由
ライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.