我有一个简单的C#函数
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
指令应该返回一个对象引用——结果(对象引用或空引用(被推送到堆栈上。
但是对0的引用是什么?以及如果。指令IL_0008: cgt.un
应该做什么?
我的解释
在我对所有IL指令的解释中,函数retrun0
。我找不到返回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规范定义了IL字节码,说明如下:
I.12.1.6.2.6值类型上的
castclass
和isinst
不允许向值类型实例进行强制转换和从值类型实例强制转换(等效的操作有box和unbox(。然而,当被装箱时,可以使用
isinst
指令来查看类型为System.Object
的值是否是特定类的装箱表示。
III.4.6-
isinst
测试
obj
是否是typeTok
的实例,返回null
或该类或接口的实例。堆栈转换:。。。,obj=>。。,结果
描述:
typeTok
是一个元数据标记(typeref、typedef或typespec(,表示所需的类。如果typeTok
是不可为null的值类型或通用参数类型,则将其解释为"盒装"typeTok
可验证性:验证将
result
的类型跟踪为typeTok
。
因此,值类型(结构(上isinst
的结果是该值的装箱ObjectRef。
II.1.5操作数类型表
cgt.un
在ObjectRefs(O(上是允许的并且是可验证的。这通常用于将ObjectRef与null进行比较(没有"compare not equal"指令,否则这将是一个更明显的解决方案(
因此isinst
ldnull
cgt.un
将告诉您对象是否属于特定类型