我对值类型和CIL评估堆栈有点困惑。 ECMA-335,分区III,§1.1表示CLI处理这些“基本CLI类型”:
完整数值类型的子集(int32,int64,native int和F)。
对象引用(O),不区分引用的对象类型。
指针类型(native unsigned int和&),没有区分指向的类型。
Partition II,§12.1还提供了一个类似的列表,它排除了值类型,并声明:
但是,CLI在其操作中仅支持存储在其评估堆栈-int32,int64和native int上的值的这些类型的子集。
除了通过托管指针类型之外,没有提及任何值类型。然而,ldfld
的规范说:
ldfld指令将字段的值推入堆栈 OBJ。 obj应该是一个对象(类型O),一个托管指针(类型&),一个 非托管指针(类型为native int),或值类型的实例。
这是否意味着值类型可以直接在评估堆栈上推送(而不是通过托管指针)?如果是这样,我可以假设被推送的值类型是原始的成员副本(例如,字段值)吗?
答案 0 :(得分:2)
参见III.1.1的介绍(强调我的):
虽然CTS定义了富类型系统,但CLS指定了一个 可用于语言互操作性的子集,CLI本身 处理更简单的类型。 这些类型包括 用户定义的值类型和内置类型的子集。该 子集,统称为“基本CLI类型”,包含 以下类型:
答案 1 :(得分:1)
是的,ldfld肯定会将值类型值复制到eval堆栈上。 “基本CLR类型”是可以作为其操作的操作数出现的类型。例如,查看表III.2,显示您希望某种操作数可用于 add 指令。只是int32,int64,native int,F,O和&出现在那里。
此外,C#需要强制转换将添加到字节值的结果复制回byte类型的核心原因。不是基本的CLR类型,因此它转换为int32并生成int32结果。将它装回一个字节是一个非平凡的转换。
答案 2 :(得分:1)
ISO/IEC 23271:2012的第I.12.3.2.1节(CLI规范)声明如下:
虽然CLI通常支持§I.12.1中描述的完整类型集,但CLI以特殊方式处理评估堆栈。虽然一些JIT编译器可能会更详细地跟踪堆栈上的类型,但CLI只要求值为以下值之一:
int64
,一个8字节有符号整数int32
,一个4字节有符号整数native int
,一个4或8字节的有符号整数,以较方便的目标架构为准。F
,浮点值(float32,float64或底层硬件支持的其他表示形式)&
,托管指针O
,一个对象引用*
,一个“瞬态指针”,只能在单个方法的主体中使用,指向已知在非托管内存中的值(有关更多详细信息,请参阅CIL指令集规范)。 *类型在CLI内部生成;它们不是由用户创建的。- 用户定义的值类型
所以,是的,评估堆栈可以包含值类型。并且复制了该值类型。