22

今日、VS2008 で提供されるツールの間に逆アセンブラー IL を見つけました。プログラムを逆アセンブルして結果を見てみました。オペコードを理解するのはそれほど難しくありませんでしたが、1 つ驚いたことがあります。.NET はスタック ベースなのですか?! 「優れたコードを書く、第 2 巻」を読んでも、スタック ベースのマシンは非常に遅いため、よく理解できませんでした。実装も簡単ですが、コードを実際のマシンコードに変換する必要があるため、問題を移動するだけなので、MS 開発者がその単純さのためにこのアプローチを選択したとは思いません。
この奇妙な選択を説明できる人はいますか?

PS
このトピックについて読んだことをここに投稿します:

13.1.1 スタックベースのマシン スタックベースのマシンは、ほとんどの計算にメモリを使用し、メモリ内のスタックを使用してすべてのオペランドと結果を保持します。スタック アーキテクチャを採用するコンピュータ システムには、他のアーキテクチャに比べていくつかの重要な利点があります。

  • 命令は通常、オペランドを指定する必要がないため、他のアーキテクチャに見られる命令よりも小さい (それぞれの消費バイト数が少ない) ことがよくあります。
  • 算術式を一連のスタック操作に変換するのは非常に簡単であるため、スタック アーキテクチャ用のコンパイラを作成する方が、他のマシン用のコンパイラよりも一般的に簡単です。
  • スタック自体がその目的を果たすため、スタック アーキテクチャで一時変数が必要になることはめったにありません。
残念ながら、スタック マシンには深刻な欠点もあります。
  • ほとんどすべての命令がメモリを参照します (最新のマシンでは遅い)。キャッシュはこの問題を軽減するのに役立ちますが、メモリ パフォーマンスは依然としてスタック マシンの主要な問題です。
  • HLL からスタック マシンへの変換は非常に簡単ですが、他のアーキテクチャよりも最適化の機会が少なくなります。
  • スタック マシンは常に同じデータ要素 (つまり、スタックの一番上にあるデータ) にアクセスしているため、パイプライン処理と命令の並列処理を実現するのは困難です (パイプライン処理と命令の並列処理の詳細については、「優れたコードを書く」第 1 巻を参照してください)。
スタックは、スタックのいくつかの制限された要素 (多くの場合、スタックのトップおよびスタックの次と呼ばれる) でのみ操作を許可するデータ構造です。スタックでは、通常、新しいデータをスタックにプッシュする、スタックからデータをポップする、現在スタックの一番上にあるデータ (およびそのすぐ下のデータ) を操作する、の 3 つのいずれかを行います。

13.1.1.5 実際のスタックマシン
スタック アーキテクチャの大きな利点は、そのようなマシン用のコンパイラを簡単に作成できることです。スタックベースのマシン用のエミュレーターを作成するのも非常に簡単です。これらの理由から、スタック アーキテクチャは、Java 仮想マシンや Microsoft Visual Basic p-code インタープリターなどの仮想マシン (VM) で人気があります。Java VM のハードウェア実装など、実際のスタックベースの CPU はいくつか存在します。ただし、メモリ アクセスのパフォーマンスが制限されるため、あまり一般的ではありません。それにもかかわらず、スタック アーキテクチャの基本を理解することは重要です。多くのコンパイラは、実際のマシン コードに変換する前に HLL ソース コードをスタック ベースの形式に変換するためです。実際、最悪の場合 (まれではありますが)、

編集: @EricLippert のブログで、質問に回答し、@Aaron の回答を確認する記事を見つけました。

4

3 に答える 3

18

中間表現がスタックベースであるからといって、生成されたマシン コードがスタックベースであるとは限らないことに注意してください。コードが中間形式からマシン コードに変換されると、基本的に再コンパイルされ、ローカルの最適化が可能になります。

スタックベースの中間表現を使用することの良い点は、特定のアーキテクチャに縛られないことです。

彼らが理論的なレジスターベースのシステムを中間形態として使用することを決定した場合を想像してみてください。彼らはいくつのレジスターを選ぶべきですか? 8? 16? 64? ターゲット プロセッサに中間形式よりも多くの実際のレジスタがある場合、最適化の可能性を失っています。ターゲットが中間よりも実際のレジスターが少ない場合、これらのレジスターはとにかくメモリにフラッシュされるため、最適化は非生産的です。

現在の CPU でも、x86 と x64 にコンパイルすると大きな違いがあります。代替アーキテクチャ (ARM) や将来のアーキテクチャは言うまでもありません。

このようなものについては、最も単純な形式に保ち、最終的なコード生成中に最適化して実際のハードウェアに一致させたのは良いことです。

于 2011-05-09T18:07:25.480 に答える
1

CIL がスタックベースである理由は、VM を対象とする命令セットとして設計されていないためです。コンパイルの中間段階です。

CLR は、JVM のような VM ではなく、コンパイラ + ランタイムに近いものです。CLR の設計では、解釈されたバイト コードの優れたパフォーマンスを提供しようとはしていません。代わりに、実行時に高レベルのバイトコードをチェックしてマシンコードにコンパイルしようとします。

于 2011-05-09T18:41:46.153 に答える
0

Microsoft の開発者に問い合わせる必要があります。しかし、パフォーマンスの問題は彼らの最大の関心事ではなかったと思います. ほとんどの Windows アプリケーションは、ユーザーがボタンをクリックするのを待つことに大部分の時間を費やしているため、CPU の制限はなく、実際には I/O の制限さえありません。ただし、新しい言語を簡単に実装できるアーキテクチャを持つことは、おそらく優先事項でした。

于 2011-05-09T17:46:23.387 に答える