C# 为我解释maxstack指令

C# 为我解释maxstack指令,c#,.net,cil,il,C#,.net,Cil,Il,我在调试模式下编译了一些测试代码,并用ILSpy反映了生成的程序集。这是我收到的IL: .class private auto ansi beforefieldinit ArrayListBoxAndUnBox.Program extends [mscorlib]System.Object { // Nested Types .class nested public auto ansi beforefieldinit Point extends [mscorlib]System.O

我在调试模式下编译了一些测试代码,并用ILSpy反映了生成的程序集。这是我收到的IL:

.class private auto ansi beforefieldinit ArrayListBoxAndUnBox.Program
extends [mscorlib]System.Object
   {
// Nested Types
.class nested public auto ansi beforefieldinit Point
    extends [mscorlib]System.Object
{
    // Fields
    .field public int32 x
    .field public int32 y

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x209f
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Point::.ctor

} // end of class Point


// Methods
.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 59 (0x3b)
    .maxstack 2
    .entrypoint
    .locals init (
        [0] class [mscorlib]System.Collections.ArrayList list,
        [1] int32 i,
        [2] class ArrayListBoxAndUnBox.Program/Point p
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: ldc.i4.1
    IL_0009: box [mscorlib]System.Int32
    IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
    IL_0013: pop
    IL_0014: ldloc.0
    IL_0015: ldc.i4.0
    IL_0016: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
    IL_001b: unbox.any [mscorlib]System.Int32
    IL_0020: stloc.1
    IL_0021: ldloc.0
    IL_0022: newobj instance void ArrayListBoxAndUnBox.Program/Point::.ctor()
    IL_0027: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
    IL_002c: pop
    IL_002d: ldloc.0
    IL_002e: ldc.i4.1
    IL_002f: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
    IL_0034: castclass ArrayListBoxAndUnBox.Program/Point
    IL_0039: stloc.2
    IL_003a: ret
} // end of method Program::Main

.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x2097
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void [mscorlib]System.Object::.ctor()
    IL_0006: ret
} // end of method Program::.ctor

} // end of class ArrayListBoxAndUnBox.Program
我看到.maxstack被设置为2,但是当我手工查看代码时,有时会在计算堆栈上得到3个元素。为什么?我是一个糟糕的IL堆栈计数器,还是这背后有什么意义

在我的世界里,IL_0014上的第一个ldloc.0从未被删除,但也许只有我不了解callvirt如何获取_项。当我到达IL_0014时,我必须在我的纸上列出堆栈的引用,然后在IL_0015,当0被推到求值堆栈上时,程序违反.maxstack

我是新手,所以一定有什么不对的地方。也许我的计数是正确的,也许我对.maxstack的理解是错误的,也许是相反的。有人能告诉我,如果我对.maxstack的理解是错误的,那么.maxstack会在运行时显示堆栈上的最大元素。或者如果我数错了?添加或删除对列表实例的引用吗

编辑: 这是我的计算方法。计数在IL代码运行后进行:

IL_0000: 0 on stack
IL_0001: 1 on stack (the reference to array list)
IL_0006: 0 on stack
IL_0007: 1 on stack (the reference to arraylist)
IL_0008: 2 on stack (reference to arraylist and int 1)
IL_0009: 2 on stack (refernce to arraylist and reference to object that wrap 1)
IL_000e: 2 on stack (reference to arraylist and index to the added boxed int object)
IL_0013: 1 on stack (reference to arraylist)
IL_0014: 2 on stack (reference to arraylist and reference to arraylist)
IL_0015: 3 on stack (reference to arraylist and reference to arraylist and int 0)
其余的我都没有数,因为我知道我弄错了


谢谢

很难看出你错在哪里了。执行指令后,左侧标注的堆栈深度:

0    IL_0000: nop
1    IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
0    IL_0006: stloc.0
1    IL_0007: ldloc.0
2    IL_0008: ldc.i4.1
2    IL_0009: box [mscorlib]System.Int32
1    IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
0    IL_0013: pop
1    IL_0014: ldloc.0
2    IL_0015: ldc.i4.0
1    IL_0016: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
1    IL_001b: unbox.any [mscorlib]System.Int32
0    IL_0020: stloc.1
1    IL_0021: ldloc.0
2    IL_0022: newobj instance void ArrayListBoxAndUnBox.Program/Point::.ctor()
1    IL_0027: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
0    IL_002c: pop
1    IL_002d: ldloc.0
2    IL_002e: ldc.i4.1
1    IL_002f: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
1    IL_0034: castclass ArrayListBoxAndUnBox.Program/Point
0    IL_0039: stloc.2
0    IL_003a: ret
唯一重要的是ArrayList.Add()调用。它弹出两个堆栈值,ArrayList对象引用和Add()参数。并向后推一个,即Add()的返回值


编辑后:这确实是你错的地方。

很难看出你错在哪里。执行指令后,左侧标注的堆栈深度:

0    IL_0000: nop
1    IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
0    IL_0006: stloc.0
1    IL_0007: ldloc.0
2    IL_0008: ldc.i4.1
2    IL_0009: box [mscorlib]System.Int32
1    IL_000e: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
0    IL_0013: pop
1    IL_0014: ldloc.0
2    IL_0015: ldc.i4.0
1    IL_0016: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
1    IL_001b: unbox.any [mscorlib]System.Int32
0    IL_0020: stloc.1
1    IL_0021: ldloc.0
2    IL_0022: newobj instance void ArrayListBoxAndUnBox.Program/Point::.ctor()
1    IL_0027: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
0    IL_002c: pop
1    IL_002d: ldloc.0
2    IL_002e: ldc.i4.1
1    IL_002f: callvirt instance object [mscorlib]System.Collections.ArrayList::get_Item(int32)
1    IL_0034: castclass ArrayListBoxAndUnBox.Program/Point
0    IL_0039: stloc.2
0    IL_003a: ret
唯一重要的是ArrayList.Add()调用。它弹出两个堆栈值,ArrayList对象引用和Add()参数。并向后推一个,即Add()的返回值


编辑后:这确实是你做错的地方。

不清楚你是如何计算的,这使得很难看出你可能做错了什么。您是否考虑了
callvirt
从堆栈中弹出目标和参数?参见ECMA-335.1第III.4.2节。我已经更新了我的答案和我的计算方法。我没有读过ECMA。我一直在找那个。我的头发有点生疏了。谢谢也许我没有得到callvirt也会弹出引用?
0e
同时弹出arraylist引用和数字,然后按下一个
Int32
-这就是你出错的地方,你没有注意到arraylist引用被弹出。不清楚你是如何计数的,这使得很难看出你可能做错了什么。您是否考虑了
callvirt
从堆栈中弹出目标和参数?参见ECMA-335.1第III.4.2节。我已经更新了我的答案和我的计算方法。我没有读过ECMA。我一直在找那个。我的头发有点生疏了。谢谢也许我没有得到callvirt也会弹出引用?
0e
同时弹出arraylist引用和数字,然后按下一个
Int32
-这就是你出错的地方,你没有注意到arraylist引用被弹出。