Can C# 'is' operator suffer under release mode optimization on .NET 4?

前端 未结 4 1115
余生分开走
余生分开走 2021-01-31 15:03

Below is a simple test fixture. It succeeds in Debug builds and fails in Release builds (VS2010, .NET4 solution, x64):

[TestFixture]
public sealed class Test
{
          


        
相关标签:
4条回答
  • 2021-01-31 15:29

    The store and load is essentially a nop as far as flow-control goes, but probably massage some CPU caches in some way. The actual flow just loads the argument on the stack, checks if it's an instance (which return null or the instance), pushes null onto the stack, and compares (greater-than) which results in a boolean being left on the stack.

    Now what the JITter does with it is another story altogether (and would depend on what platform you are using. The JITter will do all sorts of crazy things in the name of performance (our team recently got hit because tail-call optimization changed to optimize across domain boundaries which broke GetCallingAssembly()). It's possible the JITter is inlining IsDateTime, noticing that there's not way it can't not be a DateTime and just pushing true onto the stack.

    It's also possible your release version is targetting a slightly different Framework so DateTime in the test assembly is not DateTime in the tested assembly.

    I realize that doesn't answer why your code is breaking.

    0 讨论(0)
  • 2021-01-31 15:41

    This bug already came up in this SO question by Jacob Stanley. Jacob has already reported the bug, and Microsoft has confirmed that it is indeed a bug in the CLR JIT. Microsoft had this to say:

    This bug will be fixed in a future version of the runtime. I'm afraid it's too early to tell if that will be in a service pack or the next major release.

    Thank you again for reporting the issue.

    You should be able to work around the bug by adding the following attribute to TestChecker():

    [MethodImpl(MethodImplOptions.NoInlining)]
    
    0 讨论(0)
  • 2021-01-31 15:41

    It isn't related to the C# compiler, the IL is identical. You found a bug in the .NET 4.0 jitter optimizer. You can repro it in Visual Studio. Tools + Options, Debugging, General, untick the "Suppress JIT optimization on module load" option and run the Release build to repro the failure.

    I haven't looked at it closely enough yet to identify the bug. It looks very strange, it inlines the method and completely omits the code for the boxing conversion. The machine code is substantially different from the code generated by the version 2 jitter.

    A clean workaround isn't that easy, you can do it by suppressing inlining. Like this:

        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
        public bool IsDateTime(object o) {
            return o is DateTime;
        }
    

    You can report the bug at connect.microsoft.com. Let me know if you don't want to and I'll take care of it.


    Never mind, that was already done. It wasn't fixed in the maintenance release that was included with VS2010 SP1.


    This bug has been fixed, I can no longer repro it. My current version of clrjit.dll is 4.0.30319.237 dated May 17th 2011. I can't tell exactly what update repaired it. I got a security update on Aug 5th 2011 that updated clrjit.dll to revision 235 with a date of Apr 12, that would be the earliest.

    0 讨论(0)
  • 2021-01-31 15:41

    For reference I checked with mono

    • Mono JIT compiler version 2.6.7 (Debian 2.6.7-3ubuntu1)
    • Mono JIT compiler version 2.8.2 (sehe/d1c74ad Fri Feb 18 21:46:52 CET 2011)

    Both presented no problems whatsoever. Here is the IL with optimization in 2.8.2

    .method public hidebysig 
           instance default bool IsDateTime (object o)  cil managed 
    {
        // Method begins at RVA 0x2130
        // Code size 10 (0xa)
        .maxstack 8
        IL_0000:  ldarg.1 
        IL_0001:  isinst [mscorlib]System.DateTime
        IL_0006:  ldnull 
        IL_0007:  cgt.un 
        IL_0009:  ret 
    } // end of method Checker::IsDateTime
    

    Without optimizations is exactly the same

    Here is the result of mono's jitted code for this IL:

    00000130 <TestData_Checker_IsDateTime_object>:
         130:       55                      push   %ebp
         131:       8b ec                   mov    %esp,%ebp
         133:       53                      push   %ebx
         134:       56                      push   %esi
         135:       83 ec 10                sub    $0x10,%esp
         138:       e8 00 00 00 00          call   13d <TestData_Checker_IsDateTime_object+0xd>
         13d:       5b                      pop    %ebx
         13e:       81 c3 03 00 00 00       add    $0x3,%ebx
         144:       8b 45 0c                mov    0xc(%ebp),%eax
         147:       89 45 f4                mov    %eax,-0xc(%ebp)
         14a:       8b 75 0c                mov    0xc(%ebp),%esi
         14d:       83 7d 0c 00             cmpl   $0x0,0xc(%ebp)
         151:       74 1a                   je     16d <TestData_Checker_IsDateTime_object+0x3d>
         153:       8b 45 f4                mov    -0xc(%ebp),%eax
         156:       8b 00                   mov    (%eax),%eax
         158:       8b 00                   mov    (%eax),%eax
         15a:       8b 40 08                mov    0x8(%eax),%eax
         15d:       8b 48 08                mov    0x8(%eax),%ecx
         160:       8b 93 10 00 00 00       mov    0x10(%ebx),%edx
         166:       33 c0                   xor    %eax,%eax
         168:       3b ca                   cmp    %edx,%ecx
         16a:       0f 45 f0                cmovne %eax,%esi
         16d:       85 f6                   test   %esi,%esi
         16f:       0f 97 c0                seta   %al
         172:       0f b6 c0                movzbl %al,%eax
         175:       8d 65 f8                lea    -0x8(%ebp),%esp
         178:       5e                      pop    %esi
         179:       5b                      pop    %ebx
         17a:       c9                      leave  
         17b:       c3                      ret    
         17c:       8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi
    
    0 讨论(0)
提交回复
热议问题