要删除的抖动逻辑 unbox_any
Jitter logic to remove unbox_any
我正在调查此 C# 代码的执行情况:
public static void Test<T>(object o) where T : class
{
T t = o as T;
}
等效的 IL 代码是:
.method public static void Test<class T>(object A_0) cil managed
{
// Code size 13 (0xd)
.maxstack 1
.locals init (!!T V_0)
IL_0000: ldarg.0
IL_0001: isinst !!T
IL_0006: unbox.any !!T
IL_000b: stloc.0
IL_000c: ret
} // end of method DemoType::Test
根据这个答案(), can anyone explain to me what the exact logic the Jitter is doing here; how exactly does the Jitter decide to ignore the 'unbox_any' instruction in this specific case (theoretically, according to msdn,当 isinst 指令产生 null 时应该抛出 NullReferenceException,但这在实践中不会发生!)
更新
根据 usr answer 和 Hans comment,如果 obj 是引用类型,将调用 castclass
,因此,没有 NRE。
但是下面的情况呢?
static void Test<T>(object o) where T : new()
{
var nullable = o as int?;
if (nullable != null)
//do something
}
Test<int?>(null);
以及等效的 IL 代码(部分):
IL_0001: ldarg.0
IL_0002: isinst valuetype [mscorlib]System.Nullable`1<int32>
IL_0007: unbox.any valuetype [mscorlib]System.Nullable`1<int32>
IL_000c: stloc.0
IL_000d: ldloca.s nullable
IL_000f: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: brfalse.s IL_0024
在这种情况下它的值类型为什么不抛出 NRE?
When applied to a reference type, the unbox.any instruction has the same effect as castclass typeTok.
T
被限制为引用类型。在这种情况下,该指令不会抛出 NRE。 JIT 不会 "ignore" 它,它会按指定执行。不允许JIT忽略指令。
文档中有声明
NullReferenceException is thrown if obj is a null reference.
这是一种误导,因为它仅适用于值类型。我引用的第一个声明是明确的。
要回答可为空值类型的第二种情况(问题的更新部分),我们需要仔细查看 ECMA CLI 规范(III.4.33 unbox.any – 将装箱类型转换为值):
System.NullReferenceException is thrown if obj is null and typeTok is a non-nullable value type
MSDN 文档中缺少粗体部分。
总结 unbox_any 的行为:
- 如果 typeTok 是 ref 类型,与 castclass 的行为相同
如果typeTok是值类型:
2.1。如果 obj 为 null 且 typeTok 为可空值类型,则结果为 null
2.2。如果 obj 为 null 且 typeTok 不是可空值类型,则会抛出 NullReferenceException
如果我没理解错的话,第 2.2 段的行为与常规拆箱操作相同 see jitter source code
我正在调查此 C# 代码的执行情况:
public static void Test<T>(object o) where T : class
{
T t = o as T;
}
等效的 IL 代码是:
.method public static void Test<class T>(object A_0) cil managed
{
// Code size 13 (0xd)
.maxstack 1
.locals init (!!T V_0)
IL_0000: ldarg.0
IL_0001: isinst !!T
IL_0006: unbox.any !!T
IL_000b: stloc.0
IL_000c: ret
} // end of method DemoType::Test
根据这个答案(
更新
根据 usr answer 和 Hans comment,如果 obj 是引用类型,将调用 castclass
,因此,没有 NRE。
但是下面的情况呢?
static void Test<T>(object o) where T : new()
{
var nullable = o as int?;
if (nullable != null)
//do something
}
Test<int?>(null);
以及等效的 IL 代码(部分):
IL_0001: ldarg.0
IL_0002: isinst valuetype [mscorlib]System.Nullable`1<int32>
IL_0007: unbox.any valuetype [mscorlib]System.Nullable`1<int32>
IL_000c: stloc.0
IL_000d: ldloca.s nullable
IL_000f: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: brfalse.s IL_0024
在这种情况下它的值类型为什么不抛出 NRE?
When applied to a reference type, the unbox.any instruction has the same effect as castclass typeTok.
T
被限制为引用类型。在这种情况下,该指令不会抛出 NRE。 JIT 不会 "ignore" 它,它会按指定执行。不允许JIT忽略指令。
文档中有声明
NullReferenceException is thrown if obj is a null reference.
这是一种误导,因为它仅适用于值类型。我引用的第一个声明是明确的。
要回答可为空值类型的第二种情况(问题的更新部分),我们需要仔细查看 ECMA CLI 规范(III.4.33 unbox.any – 将装箱类型转换为值):
System.NullReferenceException is thrown if obj is null and typeTok is a non-nullable value type
MSDN 文档中缺少粗体部分。
总结 unbox_any 的行为:
- 如果 typeTok 是 ref 类型,与 castclass 的行为相同
如果typeTok是值类型:
2.1。如果 obj 为 null 且 typeTok 为可空值类型,则结果为 null
2.2。如果 obj 为 null 且 typeTok 不是可空值类型,则会抛出 NullReferenceException
如果我没理解错的话,第 2.2 段的行为与常规拆箱操作相同 see jitter source code