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

时间:2009-08-06 20:39:17

标签: c# .net vb.net reflection intermediate-language

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

  1. 这适用于 功能,或所有功能 我们要求的是什么?
  2. 即使只是为了这个功能 是.maxstack被宣布, 你怎么知道maxstack是什么 你有分支?你去看看 所有的“路径”并返回 可能的最大值?
  3. 如果我将它设置为16并且会发生什么? 实际上有17个变量?
  4. 如果我有一个太大的惩罚 将它设置为256?

3 个答案:

答案 0 :(得分:25)

.maxstack是IL验证的一部分。基本上.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. 这仅适用于函数,还是适用于我们要求的所有函数?
  2.   

仅用于功能

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

你去查看所有路径并返回可能的最大值

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

与变量数量无关,请参阅 Lasse V. Karlsen 的回答

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

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

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

答案 1 :(得分:5)

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

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

x = y + z;

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

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

答案 2 :(得分:0)

您可以参考以下内容和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::'<Main>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值,这个值并不是由推送和放大器决定的。流行说明。

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