Jitter logic to remove unbox_any

妖精的绣舞 提交于 2019-12-23 09:50:01

问题


I'm investigating the execution of this C# code:

public static void Test<T>(object o) where T : class
{
    T t = o as T;
}

The equivalent IL code is:

.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

Based on this answer (unnecessary unbox_any), 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, a NullReferenceException should be thrown when the isinst instruction yields null, but this doesn't happen in practice!)

Update

Based on usr answer and Hans comment, if the obj is a reference type, castclass will be called, and therefore, no NRE.

But what about the following case?

static void Test<T>(object o) where T : new()
    {
        var nullable = o as int?;
        if (nullable != null)
            //do something
    }

Test<int?>(null);

And the equivalent IL code (partial):

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

In this case its value type so why NRE not thrown?


回答1:


When applied to a reference type, the unbox.any instruction has the same effect as castclass typeTok.

T is constrained to be a reference type. This instruction does not throw a NRE in this case. The JIT does not "ignore" it, it executes it as specified. The JIT is not allowed to ignore instructions.

The documentation has the statement

NullReferenceException is thrown if obj is a null reference.

which is misleading as it only applies to value types. The first statement that I quoted is unambiguous.




回答2:


To answer on the second case (update section on the question) of nullable value type, we need to look closely in the ECMA CLI spec (III.4.33 unbox.any – convert boxed type to value):

System.NullReferenceException is thrown if obj is null and typeTok is a non-nullable value type

The bold part is missing from the MSDN documentation.

So to summarize the behavior of unbox_any:

  1. If typeTok is a ref type, same behavior as castclass
  2. If typeTok is a value type:

    2.1. If obj is null and typeTok is a nullable value type, the result is null

    2.2. If obj is null and typeTok is not a nullable value type, a NullReferenceException will thrown

If I understand correctly, the behavior of paragraph 2.2 is same as regular unbox operation see jitter source code



来源:https://stackoverflow.com/questions/34382683/jitter-logic-to-remove-unbox-any

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!