这些问题似乎找不到好的答案。
这就是我想知道的和我不清楚的。
以下面的示例为例。是否通过ptr引用将该局部变量存储在评估堆栈中?
public struct MyStruct
{
public long x, y, z;
public static MyStruct Foo()
{
MyStruct c;
c.x = 1;
c.y = 2;
c.z = 3;
return c;
}
}
“ ldloc.0”清楚地将结构存储到评估堆栈中,但其大小也远大于64位。而是存储参考吗?
.class public sequential ansi sealed beforefieldinit MyStruct
extends [mscorlib]System.ValueType
{
// Fields
.field public int64 x
.field public int64 y
.field public int64 z
// Methods
.method public hidebysig static
valuetype MyStruct Foo () cil managed
{
// Method begins at RVA 0x2050
// Code size 34 (0x22)
.maxstack 2
.locals init (
[0] valuetype MyStruct,
[1] valuetype MyStruct
)
IL_0000: nop
IL_0001: ldloca.s 0
IL_0003: ldc.i4.1
IL_0004: conv.i8
IL_0005: stfld int64 MyStruct::x
IL_000a: ldloca.s 0
IL_000c: ldc.i4.2
IL_000d: conv.i8
IL_000e: stfld int64 MyStruct::y
IL_0013: ldloca.s 0
IL_0015: ldc.i4.3
IL_0016: conv.i8
IL_0017: stfld int64 MyStruct::z
IL_001c: ldloc.0// What is actually stored here?
IL_001d: stloc.1
IL_001e: br.s IL_0020
IL_0020: ldloc.1
IL_0021: ret
} // end of method MyStruct::Foo
} // end of class MyStruct
答案 0 :(得分:1)
堆栈的元素大小并非全部相同,并且可以包括任意大小的值类型(struct
s)。
摘自ECMA-335,第I.12.3.2.1节:
评估堆栈由可以容纳任何数据类型的插槽组成,包括值类型的未装箱实例。
[...]
尽管某些JIT编译器可能会更详细地跟踪堆栈上的类型,但CLI仅要求值是以下之一:
int64
,一个8字节有符号整数int32
,一个4字节有符号整数native int
,一个4或8个字节的有符号整数,以对目标体系结构更方便的方式F
,浮点值(float32
,float64
或基础硬件支持的其他表示形式)&
,托管指针O
,对象引用*
是一个“瞬态指针”,只能在单个方法的主体内使用,它指向已知在非托管内存中的值(有关更多详细信息,请参见CIL指令集规范。*
类型是在CLI内部生成的;它们不是由用户创建的。- 用户定义的值类型
稍早于I.12.1节:
用户定义的值类型可以出现在内存位置或堆栈中,并且没有大小限制
因此,在您的情况下,ldloc.0
指令正在将整个值类型实例及其三个数据字段加载到堆栈中。
感谢this answer将我引向这些ECMA部分。 该问题以及该问题的其他答案表明,为什么可以在插槽而不是字节中测量堆栈:因为JIT编译器已经在评估如何将MSIL转换为本地指令,所以它必须知道每条指令堆栈上的值的类型。
答案 1 :(得分:0)
如果.maxsize为8,那意味着(8 * size_t)?
.maxstack
指令与运行时评估堆栈的实际大小不相关。相反,它暗示了分析工具同时有多少个物品。错误设置.maxstack
(例如,设置得太小)时,该方法被认为是不可验证的,这可能会导致信任度较低的情况下出现问题(但这对您来说应该不是问题,因为您正在阅读CIL,不写)。
例如,让我们考虑一个简单的Add
方法,该方法接受int
参数,将它们加在一起,将结果存储在名为sum
的类字段中,并返回该字段的值
.method private hidebysig instance
int32 Add (
int32 value1,
int32 value2
) cil managed
{
.maxstack 3 // At most, there are three elements on the stack.
ldarg.0 // 1 item on the stack
ldarg.1 // 2 items on the stack
ldarg.2 // 3 items on the stack
add // 2 items on the stack
stfld int32 Foo::sum // 0 items on the stack
ldarg.0 // 1 item on the stack
ldfld int32 Foo::sum // 1 item on the stack
ret
}
该方法的评估堆栈上最多只能同时包含3个项目。
来源: