1

私はいかなる種類のILマスターでもありません。私が書いたコードをコンパイラーがどのように作成するかを確認するために、時々それを使用します。私が疑問に思っていることの1つは、なぜ.maxstackそれが時々得る価値を得るのかということです。次のクラスについて考えてみます。

public class Sample
{
    public void SomeMethod(){}
}

次に、私はこのようなプログラムを持っています:

private static void Main(string[] args)
{
    Sample sample = new Sample();
    sample.SomeMethod();      
}

上記のコードは、次のIL(リリースコンパイル済み)を提供します。

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       13 (0xd)
  .maxstack  1
  .locals init ([0] class ConsoleApplication1.Sample sample)
  IL_0000:  newobj     instance void ConsoleApplication1.Sample::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  callvirt   instance void ConsoleApplication1.Sample::SomeMethod()
  IL_000c:  ret
} // end of method Program::Main

ここで、プログラムコードを次のように変更すると、次のようになります。

private static void Main(string[] args)
{
    new Sample().SomeMethod();  
}

...次のILコードになります。

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  newobj     instance void ConsoleApplication1.Sample::.ctor()
  IL_0005:  call       instance void ConsoleApplication1.Sample::SomeMethod()
  IL_000a:  ret
} // end of method Program::Main

2番目のILコードは短く、予想どおりでした。しかし、私が少し不思議に思うのは、なぜ.maxstack私は2番目のコードサンプルでは8であるのに、最初のコードサンプルでは1であるのかということです。2番目のコードが、システムが操作のためにより大きなスタックを予約することにつながるのはなぜですか?

4

1 に答える 1

4

メソッドヘッダーのバイナリ表現には、「小さな形式」と「太い形式」があります。小さなヘッダーは必要なバイト数が少なく、次の条件が満たされている限り使用できます。

  • 最大スタック<=8
  • 例外処理なし
  • ローカル変数なし
  • コードサイズ<64バイト

変更により、コンパイラはこの形式を使用できるようになり、小さなヘッダーが検出されると、常に最大スタック8を使用すると想定されます。

参照はECMA-335§25.4.2です

ちなみに、私が特に興味を持っているのは、リリースビルド(OPのメモごと)で、短縮形がより小さく、より高速な異なるコードを生成したという事実です。どのバージョンのC#を使用していますか?後のバージョンでは、この明らかな最適化を利用することを期待しています。

  • セマンティクスを変更せずにローカル変数を削除できます。
  • ローカル変数が存在しない場合、コンパイラは値の具体的な型が正確Sampleであることを認識しているため、仮想であってもSomeMethod、命令を使用して直接呼び出すことができますcall
于 2009-12-15T08:54:11.347 に答える