不存储引用时 .maxstack 更大吗?

发布于 2024-08-14 17:38:24 字数 1456 浏览 2 评论 0原文

我不是任何类型的 IL 大师,我只是有时使用它来检查编译器如何处理我编写的代码。我一直想知道的一件事是为什么 .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

第二个IL 代码更短,这是预期的。但让我有点好奇的是,为什么第二个代码示例中的 .maxstack i 是 8,而第一个代码示例中是 1?为什么第二个代码会导致系统为该操作保留更大的堆栈?

I am no IL master of any sort, I just use it sometimes to check what the compiler makes of the code that I write. One thing that I have been wondering about is why .maxstack gets the value it gets sometimes. Consider the following class:

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

Then, I have a program like this:

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

The above code gives the following IL (Release compiled):

.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

Now, if I change the program code into this:

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

...it results in the following IL code:

.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

The second IL code is shorter, which was expected. But what gets me a bit curious is why .maxstack i 8 in the second code sample, but 1 in the first? Why does the second code lead to the system reserving a larger stack for the operation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沩ん囻菔务 2024-08-21 17:38:24

方法头的二进制表示有“tiny 格式”和“fat 格式”。 Tiny header 占用的字节数较少,只要满足以下条件就可以使用:

  • 最大堆栈 <= 8
  • 无异常处理
  • 无局部变量
  • 代码大小 <= 8 64 字节

您的更改允许编译器使用此形式,并且当遇到小标头时,始终假定使用最大堆栈为 8。

参考是 ECMA-335 §25.4.2

旁注 我特别感兴趣的是以下事实:发布版本(根据您在OP中的注释)他们生成了不同的代码,其中缩短的形式既更小又更快。您使用什么版本的 C#?我希望以后的版本能够利用这种明显的优化:

  • 可以在不更改语义的情况下删除局部变量。
  • 当局部变量不存在时,编译器知道该值的具体类型正是 Sample,因此即使 SomeMethod 是虚拟的,它也可以直接使用 调用它>调用指令。

The binary representation of a method header has a "tiny format" and a "fat format". The tiny header takes fewer bytes and can be used as long as the following conditions are met:

  • Max stack <= 8
  • No exception handling
  • No local variables
  • Code size < 64 bytes

Your change allowed the compiler to use this form, and when a tiny header is encountered it is always assumed to use a max stack of 8.

Reference is ECMA-335 §25.4.2

On a side note Of particular interest to me is the fact that in a release build (per your note in the OP) they produced different code, where the shortened form is both smaller and faster. What version of C# are you using? I would expect later versions to take advantage of this obvious optimization:

  • The local variable could be removed without changing the semantics.
  • When the local variable is not present, the compiler knows the concrete type of the value is exactly Sample, so even though SomeMethod is virtual it can call it directly with the call instruction.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文