【发布时间】:2013-11-13 10:06:56
【问题描述】:
CIL stelem 指令(ECMA 335 [pdf] 中的 III.4.26)指定为
格式汇编格式说明 A4stelem typeTok 将 index 处的数组元素替换为 值在栈上 堆栈转换: …,数组,索引,值,-> …
我不明白 typeTok 参数的目的是什么。
原始规格
以下是规范中对typeTok的全部提及:
-
在描述中:
值的类型必须是指令中的array-element-compatible-with typeTok。
-
在“正确性”部分:
typeTok 应为有效的
typedef、typeref或typespec元数据令牌。 -
在“可验证性”部分:
array的跟踪类型是
T[],对于一些T;value的跟踪类型是array-element-compatible-with typeTok;
typeTok 是 array-element-compatible-with
T
所以 typeTok 不用于任何事情;它只需要提供。换句话说,我看到的唯一要求是满足条件的typeTok 必须exist。
修改规范
然而,仅仅要求存在这样的 typeTok 就相当于1 将上述规范部分更改为
-
在描述中:
value的类型必须是array-element-compatible-witharray的元素类型
在“正确性”部分,删除上述部分。
-
在“可验证性”部分:
array的跟踪类型是
T[],对于一些T;value的跟踪类型是array-element-compatible-with
T
1如果value是a-e-c-witharray的元素类型,那么因为a-e-c-with 关系的自反性,可以选择 value 的类型或数组的元素类型作为满足要求的 typeTok的“原始规格”。相反,如果存在具有给定要求的 typeTok,则 a-e-c-with 关系的传递性立即产生“Modified spec”的要求。
那么我错过了什么?为什么有 typeTok 参数(以及为什么除了stelem.ref 之外的stelem.<type> 指令甚至存在)?
【问题讨论】:
-
很难回答,这条 IL 指令只在通用代码中使用过。抖动和验证者很容易在他们的代码中使用令牌来执行检查并决定生成什么代码。无论是为了让他们更轻松,还是真的有必要处理数组协方差,这都是我无法带回家的,它们是 .NET 的难点。第 I.8.7.1 章令人头疼。好奇心还是真正的问题?
-
好奇心,主要是。试图深入研究 IL,这引起了我在阅读规范时的注意。
-
通常存在原始类型的速记版本,因此您不必使用类型令牌。这导致它减少了 4 个字节。较短的方法通常有更高的内联机会。
-
@MichaelB 我知道这一点,但如果长版本的类型参数不起作用,那么速记版本同样没用(长版本可能同样短)。
-
从技术上讲,您可以像 CLR 演示的那样对每个数组索引使用 ldelema,然后使用 stind 或 stobj。它的方式更加臃肿。它们的存在是因为 CLR 验证程序也在检查意图。序列
ldloc.0,ldc.i4.3,ldc.i4.8stelem.ref显然是错误的,因为您需要在 int 进入插槽之前将其装箱。我认为目的是针对非原始结构和泛型。但也许是因为非基元在数组中的使用不多(也许它们在泛型上下文中使用得更多),所以序列从来没有被优化过?