问题描述
public bool Isinst_intSimple(object value)
{
return value is int;
}
正如预期的那样 Isinst_intSimple(0)
返回 true
反编译后的函数如下:
IL_0000: nop
IL_0001: ldarg.1 // 'value'
IL_0002: isinst [System.Runtime]system.int32
IL_0007: ldnull
IL_0008: cgt.un
IL_000a: stloc.0 // V_0
IL_000b: br.s IL_000d
// [196 9 - 196 10]
IL_000d: ldloc.0 // V_0
IL_000e: ret
IL_0002 isinst [System.Runtime]system.int32
指令在执行后会推送到计算堆栈上什么(输入将为 0(int32))?
根据 MS 文档,Isinst
指令应该返回一个对象引用 - The result (either an object reference or a null reference) is pushed onto the stack.
但是对 0 的引用是什么?而如果。指令 IL_0008: cgt.un
应该做什么?
我的解释
在我对所有 IL 指令的解释中 - 函数 retrun 0
。而且我找不到返回 true
的方法。
以下是我对函数执行的解释:
IL_0000: nop
IL_0001: ldarg.1 // push 0 on evaluation stack – stack after {0}
IL_0002: isinst [System.Runtime]system.int32 //pop and object reference is pushed onto the stack. - stack after { 0* or reference to 0 – Boxing? }
IL_0007: ldnull //– stack after {null,0*}
IL_0008: cgt.un //– 0* is not greater than null so its return 0 - stack after {0}
IL_000a: stloc.0 // V_0 – pop to V_0 – stack after {}
IL_000b: br.s IL_000d // – stack after {}
// [196 9 - 196 10]
IL_000d: ldloc.0 // V_0 //– push V_0 – stack after {0}
IL_000e: ret //return {0}
我认为问题出在 IL_0002: isinst
或 IL_0008: cgt.un
,但我找不到。
背景
我正在开发一个模拟 C# dll 的虚拟机 - 一条指令(在“虚拟机”中执行 C#),但我在模拟测试函数 Isinst_intSimple(0)
时遇到问题。我的版本返回 0
但它应该返回 true
解决方法
ECMA-335 specification 定义了 IL 字节码,内容如下:
I.12.1.6.2.6 castclass
和 isinst
关于值类型
不允许在值类型实例之间进行转换(等效操作是装箱和拆箱)。但是,在装箱时,可以使用 isinst
指令查看 System.Object
类型的值是否是特定类的装箱表示。
III.4.6 - isinst
测试 obj
是否是 typeTok
的实例,返回 null
或该类或接口的实例。
堆栈转换:...,obj => ...,结果
描述:typeTok
是元数据标记(typeref、typedef 或 typespec),指示所需的类。如果 typeTok
是不可为空的值类型或泛型参数类型,则将其解释为“装箱”typeTok
可验证性:验证将 result
的类型跟踪为 typeTok
。
因此 isinst
在值类型(结构)上的结果是该值的装箱 ObjectRef。
II.1.5 操作数类型表
cgt.un
在 ObjectRefs (O) 上是允许且可验证的。这通常用于比较 ObjectRef 与 null(没有“比较不相等”指令,否则这是一个更明显的解决方案)
所以 isinst
ldnull
cgt.un
会告诉你一个对象是否属于特定类型