.NET IL .maxstack指令如何工作?

我想知道.maxstack是如何工作的。 我知道它与您声明的类型的实际大小无关,但与它们的数量有关。 我的问题是:

  1. 这仅适用于函数,还适用于我们要求的所有函数?
  2. 即使只是函数是.maxstack正在声明,如果你有分支,你怎么知道maxstack是什么? 你去看看所有的“路径”并尽可能返回最大值?
  3. 如果我将它设置为16并且实际上有17个变量会发生什么?
  4. 如果我把它设置为256,会有太大的惩罚吗?

.maxstack是ILvalidation的一部分。 基本上.maxstack告诉JIT它需要为该方法保留的最大堆栈大小。 例如, x = y + (a - b)转换为

(伪IL 🙂

 1. Push y on the stack 2. Push a on the stack 3. Push b on the stack 4. Pop the last two items from the stack, substract them and push the result on the stack 5. Pop the last two items from the stack, add them and push the result on the stack 6. Store the last item on the stack in x and pop the last item from the stack 

如您所见,每次堆叠最多有3个项目。 如果为此方法将.maxstack设置为2(或更小),则代码将无法运行。

此外,您不能拥有这样的东西,因为它需要无限的堆栈大小:

 1. Push x on the stack 2. Jump to step 1 

回答你的问题:

  1. 这仅适用于函数,还适用于我们要求的所有函数?

只为function

  1. 即使只是函数是.maxstack正在声明,如果你有分支,你怎么知道maxstack是什么? 你去看看所有的“路径”并尽可能返回最大值?

您可以查看所有路径并返回可能的最大值

  1. 如果我将它设置为16并且实际上有17个变量会发生什么?

它与变量的数量无关,参见Lasse V. Karlsen的回答

  1. 如果我把它设置为256,会有太大的惩罚吗?

似乎不是一个好主意,但我不知道。

你真的必须自己计算.maxstack吗? System.Reflection.Emit为你计算它IIRC。

它与声明的变量数量无关,而是与在任何给定时间推送堆栈需要多少值以计算某些表达式有关。

例如,在下面的表达式中,我假设需要将2个值压入堆栈:

 x = y + z; 

这与存在至少3个变量x,y和z以及可能还有其他变量的事实无关。

不幸的是,我不知道你的其他问题的答案,我猜想实验将是找到答案的一种方法。

您可以参考以下内容和ECMA标准以获得更好的理解:

 void msd(string a, string b, string c, string d, string e) { Console.WriteLine(a); } msd("a","b","c","d","e"); 

当我运行ildasm.exe我得到了这个:

 { .entrypoint // Code size 40 (0x28) .maxstack 8 IL_0000: nop IL_0001: nop IL_0002: ldstr "a" IL_0007: ldstr "b" IL_000c: ldstr "c" IL_0011: ldstr "d" IL_0016: ldstr "e" IL_001b: call void sf.Program::'
g__msd|0_0'(string, string, string, string, string) IL_0020: nop IL_0021: call string [mscorlib]System.Console::ReadLine() IL_0026: pop IL_0027: ret } // end of method Program::Main

从上面。 我发现最大stakc值不是由push&pop指令决定的。

我不知道真正的堆栈数值是多少。 因此,我引用ildasm反汇编代码来确定实际的最大堆栈值。