none
Was an indexer inlined? RRS feed

  • Question

  • To anybody familiar with native assembly instructions, please could you tell me whether the indexer from the following C# code was inlined by the JIT compiler? Thanks a lot.


    class Test  
    {  
        class CustomCollection   
        {  
            List<object> list = new List<object>();  
      
            public object this[int index]   
            {   
                get   
                {   
                    return list[index];   
                }   
            }   
        }   
       
        CustomCollection collection;   
        object tmp;   
     
        ... 
     
        void Method() 
        {   
            for (int i = 0; i < NUM_ITERATIONS; i++)   
            {   
              tmp = collection[ i ];    // *** was the indexer getter JIT inlined?   
            }   
        } 
    }  



    The disassembly of a JIT optimized code, I hope to have located the for() loop.

    7900B1BC  pop         edi   
    7900B1BD  inc         ebx   
    7900B1BE  outs        dx,dword ptr [esi]  
    7900B1BF  jb          7900B206  
    7900B1C1  js          7900B228  
    7900B1C3  dec         ebp   
    7900B1C4  popad             
    7900B1C5  imul        ebp,dword ptr [esi],0B183B8h  
    7900B1CC  jns         7900B1B7  
    7900B1CE  pop         ds    
    7900B1CF  jle         7900B1D0  
    7900B1D1  dec         dword ptr [ebp-46F73h]  
    7900B1D7  db          ffh   
    7900B1D8  call        7900396B  
    7900B1DD  mov         dword ptr [ebp-4],ebx  
    7900B1E0  cmp         dword ptr [ebp+10h],ebx  
    7900B1E3  jne         7900B237  
    7900B1E5  cmp         dword ptr [ebp+8],ebx  
    7900B1E8  je          7900B237  
    7900B1EA  xor         eax,eax  
    7900B1EC  inc         eax   
    7900B1ED  push        ebx   
    7900B1EE  push        eax   
    7900B1EF  lea         ecx,[ebp-470h]  
    7900B1F5  call        79004DA1  
    7900B1FA  cmp         eax,ebx  
    7900B1FC  mov         dword ptr [ebp-414h],eax  
    7900B202  jl          790145A5  
    7900B208  mov         ecx,edi  
    7900B20A  call        790039D2  
    7900B20F  test        eax,eax  
    7900B211  je          790146BB  
    7900B217  or          dword ptr [ebp-4],0FFFFFFFFh  
    7900B21B  lea         ecx,[ebp-470h]  
    7900B221  call        790038CF  
    7900B226  cmp         dword ptr ds:[7903E0C8h],ebx  
    7900B22C  je          79005DBE  
    7900B232  jmp         79005DF5  
    7900B237  xor         eax,eax  
    7900B239  jmp         7900B1ED  
    7900B23B  call        79009507  
    7900B240  jmp         79003119  
    7900B245  mov         ecx,dword ptr [ecx+4Ch]  
    7900B248  test        ecx,ecx  
    7900B24A  je          7900327F  
    7900B250  mov         eax,dword ptr [ebp+8]  
    7900B253  mov         dword ptr [eax],ebx  
    7900B255  jmp         79003289  
    7900B25A  add         eax,20h  
    7900B25D  jmp         7900B275  
    7900B25F  mov         edx,dword ptr [esp+8]  
    7900B263  push        esi   
    7900B264  mov         esi,dword ptr [esp+8]  
    7900B268  push        edi   
    7900B269  movzx       eax,byte ptr [esi]  
    7900B26C  lea         ecx,[eax-41h]  
    7900B26F  inc         esi   
    7900B270  cmp         ecx,19h  
    7900B273  jbe         7900B25A  
    7900B275  movzx       ecx,byte ptr [edx]  
    7900B278  lea         edi,[ecx-41h]  
    7900B27B  inc         edx   
    7900B27C  cmp         edi,19h  
    7900B27F  jbe         7900B28E  
    7900B281  test        eax,eax  
    7900B283  je          7900B289  
    7900B285  cmp         eax,ecx  
    7900B287  je          7900B269  
    7900B289  pop         edi   
    7900B28A  sub         eax,ecx  
    7900B28C  pop         esi   
    7900B28D  ret               
    7900B28E  add         ecx,20h  
    7900B291  jmp         7900B281  
    7900B293  push        7900B1BCh  
    7900B298  push        esi   
    7900B299  call        7900B2AD  
    7900B29E  test        eax,eax  
    7900B2A0  pop         ecx   
    7900B2A1  pop         ecx   
    7900B2A2  je          79003486  
    7900B2A8  jmp         7900B5A7  
    7900B2AD  push        ebp   
    7900B2AE  mov         ebp,esp  
    7900B2B0  push        esi   
    7900B2B1  xor         esi,esi  
    7900B2B3  cmp         dword ptr ds:[7903E134h],esi  
    7900B2B9  jne         790175D7  
    7900B2BF  cmp         dword ptr [ebp+8],esi  
    7900B2C2  je          790175B8  
    7900B2C8  cmp         dword ptr [ebp+0Ch],esi  
    7900B2CB  je          790175B8  
    7900B2D1  pop         esi   
    7900B2D2  pop         ebp   
    7900B2D3  jmp         7900B25F  
    7900B2D5  mov         eax,dword ptr [esi+4]  
    7900B2D8  test        eax,eax  
    7900B2DA  je          79005703  
    7900B2E0  jmp         790056FC  
    7900B2E5  dec         esi   
    7900B2E6  jmp         79006D2E  
    7900B2EB  xor         eax,eax  
    7900B2ED  cmp         dword ptr [ebp-4],eax  
    7900B2F0  mov         bl,22h  
    7900B2F2  sete        al    
    7900B2F5  inc         esi   
    7900B2F6  mov         dword ptr [ebp-4],eax  
    7900B2F9  jmp         79006D16  
    7900B2FE  push        ebp   
    7900B2FF  mov         ebp,esp  
    7900B301  push        esi   
    7900B302  push        dword ptr [ebp+0Ch]  
    7900B305  call        79008834  
    7900B30A  push        dword ptr [ebp+10h]  
    7900B30D  mov         esi,eax  
    7900B30F  push        esi   

    Monday, November 24, 2008 2:57 AM

Answers

  • The JIT compiler is smart enough to optimize the for() loop away when you use while(true) {}.  This is what I get:

    00000015  nop             
    00000016  jmp         00000015

    Yup, that's an endless loop.

    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Friday, November 28, 2008 1:14 PM
    Monday, November 24, 2008 7:03 PM
    Moderator

All replies

  • Could you change your code to this :
     


         
            public object this[int index]      
            {      
                [MethodImpl(MethodImplOptions.NoInlining)]  
                get      
                {      
                    return list[index];      
                }      
            }      
     

    and post the assembly again?

    Monday, November 24, 2008 3:24 AM
  • Used the attribute but the asm code is identical.

    That doesn't necessarily mean that the indexer wasn't inlined, since I'm a little unsure whether I've located the appropriate code, but should be! Thought that a for-loop could be easily isolated...

    Monday, November 24, 2008 4:10 AM
  • It does not get inlined when I try it.  This is easier to see when you leave the debugger in mixed or managed mode.  Set a breakpoint on the statement of interest, wait until it hits, right-click + Go To Disassembly.
    Hans Passant.
    Monday, November 24, 2008 1:08 PM
    Moderator
  • nobugz said:

    It does not get inlined when I try it. 

    Thanks a lot

    nobugz said:

    This is easier to see when you leave the debugger in mixed or managed mode.  Set a breakpoint on the statement of interest, wait until it hits, right-click + Go To Disassembly.


    I just don't seem to be hitting breakpoints with optimized code. (I.e. Tools->Options->Debugging->Suppress JIT optimization on module load, disable)

    So I inserted a while(true){} before the for() loop like this
    void Method()  
        {    
            while (true) { } 
     
            for (int i = 0; i < NUM_ITERATIONS; i++)    
            {    
              tmp = collection[ i ];    // *** was the indexer getter JIT inlined?    
            }    
        }  

    And hit Debug -> Break All to enter the debugger while in the while-loop.

    The code around that I get is
     
    7900B19F  push        7900B1BCh  
    7900B1A4  push        dword ptr [ebp-4]  
    7900B1A7  call        dword ptr ds:[79001020h]  
    7900B1AD  test        eax,eax ; if (null) return...
    7900B1AF  je          7900B1B6  
    7900B1B1  call        eax  ; ...else invoke (I guess)
       
    7900B1B3  pop         esi  ; *** here the debugger actually stops 
     
    7900B1B4  leave            ; return
    7900B1B5  ret               
    7900B1B6  mov         eax,esi  
    7900B1B8  jmp         7900B1B3
    7900B1BA  nop               
    7900B1BB  nop       

    ; *** The above doesn't seem to do any for() looping whatsoever, so I posted from here        
    7900B1BC  pop         edi
    7900B1BD  inc         ebx   
    7900B1BE  outs        dx,dword ptr [esi]  
    7900B1BF  jb          7900B206  
    7900B1C1  js          7900B228  
    7900B1C3  dec         ebp   
    7900B1C4  popad             
    7900B1C5  imul        ebp,dword ptr [esi],0B183B8h  
    7900B1CC  jns         7900B1B7  
    7900B1CE  pop         ds    
    7900B1CF  jle         7900B1D0  
    7900B1D1  dec         dword ptr [ebp-46F73h]  
    7900B1D7  db          ffh   
    7900B1D8  call        7900396B  
    7900B1DD  mov         dword ptr [ebp-4],ebx  
    7900B1E0  cmp         dword ptr [ebp+10h],ebx  
    7900B1E3  jne         7900B237  
    7900B1E5  cmp         dword ptr [ebp+8],ebx  
    7900B1E8  je          7900B237  
    7900B1EA  xor         eax,eax  
    7900B1EC  inc         eax   
    7900B1ED  push        ebx   
    7900B1EE  push        eax   
    7900B1EF  lea         ecx,[ebp-470h]  
    7900B1F5  call        79004DA1  
    7900B1FA  cmp         eax,ebx  
    7900B1FC  mov         dword ptr [ebp-414h],eax  
    7900B202  jl          790145A5  
    7900B208  mov         ecx,edi  
    7900B20A  call        790039D2  
    7900B20F  test        eax,eax  
    7900B211  je          790146BB  
    7900B217  or          dword ptr [ebp-4],0FFFFFFFFh  
    7900B21B  lea         ecx,[ebp-470h]  
    7900B221  call        790038CF  
    7900B226  cmp         dword ptr ds:[7903E0C8h],ebx  
    7900B22C  je          79005DBE  
    7900B232  jmp         79005DF5  
    7900B237  xor         eax,eax  
    7900B239  jmp         7900B1ED  
    7900B23B  call        79009507  
    7900B240  jmp         79003119  
    7900B245  mov         ecx,dword ptr [ecx+4Ch]  
    7900B248  test        ecx,ecx  
    7900B24A  je          7900327F  
    7900B250  mov         eax,dword ptr [ebp+8]  
    7900B253  mov         dword ptr [eax],ebx  
    7900B255  jmp         79003289  
    7900B25A  add         eax,20h  
    7900B25D  jmp         7900B275  
    7900B25F  mov         edx,dword ptr [esp+8]  
    7900B263  push        esi   
    7900B264  mov         esi,dword ptr [esp+8]  
    7900B268  push        edi   
    7900B269  movzx       eax,byte ptr [esi]  
    7900B26C  lea         ecx,[eax-41h]  
    7900B26F  inc         esi   
    7900B270  cmp         ecx,19h  
    7900B273  jbe         7900B25A  
    7900B275  movzx       ecx,byte ptr [edx]  
    7900B278  lea         edi,[ecx-41h]  
    7900B27B  inc         edx   
    7900B27C  cmp         edi,19h  
    7900B27F  jbe         7900B28E  
    7900B281  test        eax,eax  
    7900B283  je          7900B289  
    7900B285  cmp         eax,ecx  
    7900B287  je          7900B269  
    7900B289  pop         edi   
    7900B28A  sub         eax,ecx  
    7900B28C  pop         esi   
    7900B28D  ret               
    7900B28E  add         ecx,20h  
    7900B291  jmp         7900B281  
    7900B293  push        7900B1BCh  
    7900B298  push        esi   
    7900B299  call        7900B2AD  
    7900B29E  test        eax,eax  
    7900B2A0  pop         ecx   
    7900B2A1  pop         ecx   
    7900B2A2  je          79003486  
    7900B2A8  jmp         7900B5A7  
    7900B2AD  push        ebp   
    7900B2AE  mov         ebp,esp  
    7900B2B0  push        esi   
    7900B2B1  xor         esi,esi  
    7900B2B3  cmp         dword ptr ds:[7903E134h],esi  
    7900B2B9  jne         790175D7  
    7900B2BF  cmp         dword ptr [ebp+8],esi  
    7900B2C2  je          790175B8  
    7900B2C8  cmp         dword ptr [ebp+0Ch],esi  
    7900B2CB  je          790175B8  
    7900B2D1  pop         esi   
    7900B2D2  pop         ebp   
    7900B2D3  jmp         7900B25F  
    7900B2D5  mov         eax,dword ptr [esi+4]  
    7900B2D8  test        eax,eax  
    7900B2DA  je          79005703  
    7900B2E0  jmp         790056FC  
    7900B2E5  dec         esi   
    7900B2E6  jmp         79006D2E  
    7900B2EB  xor         eax,eax  
    7900B2ED  cmp         dword ptr [ebp-4],eax  
    7900B2F0  mov         bl,22h  
    7900B2F2  sete        al    
    7900B2F5  inc         esi   
    7900B2F6  mov         dword ptr [ebp-4],eax  
    7900B2F9  jmp         79006D16  
    7900B2FE  push        ebp   
    7900B2FF  mov         ebp,esp  
    7900B301  push        esi   
    7900B302  push        dword ptr [ebp+0Ch]  
    7900B305  call        79008834  
    7900B30A  push        dword ptr [ebp+10h]  
    7900B30D  mov         esi,eax  
    7900B30F  push        esi   
    7900B310  push        dword ptr [ebp+8]  
    7900B313  push        80000001h  
    7900B318  call        7900B344  
    7900B31D  test        eax,eax  
    7900B31F  jge         7900B340  
    7900B321  push        dword ptr [ebp+10h]  
    7900B324  push        esi   
    7900B325  push        dword ptr [ebp+8]  
    7900B328  push        80000002h  
    7900B32D  call        7900B344  
    7900B332  test        eax,eax  
    7900B334  jge         7900B340  
    7900B336  mov         eax,80004005h  
    7900B33B  pop         esi   
    7900B33C  pop         ebp   
    7900B33D  ret         0Ch   
    7900B340  xor         eax,eax  
    7900B342  jmp         7900B33B  
    7900B344  push        ebp   
    ... 
     


    The point where the debugger stops doesn't give sense to me already.

    I don't see any original C# code in the debugger to compare with - that's the Suppres JIT optimization option disabled.

    Confused.

    Monday, November 24, 2008 6:24 PM
  • In Debug mode without JIT optimizations the for-loop looks like this

     
                            for (int i = 0; i < NUM_ITERATIONS; i++) 
    00000000  push        edi   
    00000001  push        esi   
    00000002  push        ebx   
    00000003  push        ebp   
    00000004  mov         edi,ecx 
    00000006  cmp         dword ptr ds:[00982E08h],0 
    0000000d  je          00000014 
    0000000f  call        792C7457 
    00000014  xor         esi,esi 
    00000016  xor         esi,esi 
    00000018  nop               
    00000019  jmp         00000035 
                            { 
                                tmp = collection[i]; 
    0000001b  mov         ebp,edi 
    0000001d  mov         ecx,dword ptr [edi+8] 
    00000020  mov         edx,esi 
    00000022  cmp         dword ptr [ecx],ecx 
    00000024  call        dword ptr ds:[009833BCh] 
    0000002a  mov         ebx,eax 
    0000002c  lea         edx,[ebp+14h] 
    0000002f  call        790146BB  
    Can't find anything similar in the optimized disasembly, so perhaps I couldn't locate the appropriate part there.

    What could I be doing wrong?
    Thanks
    Monday, November 24, 2008 6:53 PM
  • The JIT compiler is smart enough to optimize the for() loop away when you use while(true) {}.  This is what I get:

    00000015  nop             
    00000016  jmp         00000015

    Yup, that's an endless loop.

    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Friday, November 28, 2008 1:14 PM
    Monday, November 24, 2008 7:03 PM
    Moderator
  • Aha :)

    Monday, November 24, 2008 7:32 PM
  • I realized that I'm getting the same disassembly for any C# code (when optimised), it definitely doesn't represent the code I'm trying to test.




    Monday, November 24, 2008 8:09 PM