Runtime: Question: interface call and generated ASM

Created on 28 Nov 2019  ·  3Comments  ·  Source: dotnet/runtime

Hi Guys!

Have a very simple app, that call interface method like this.

namespace InterfaceCalls
{
    public interface IFoo
    {
        int  Bar();
    }

    class Program
    {
        public static int M1(IFoo foo)
        {
            return foo.Bar();
        }

        static void Main(string[] args)
        {
            M1(null);
        }
    }
}

That generates the following ASM for 2.2 (for 3.0 there is lea rsp,[rbp] instead of add rsp,30h)

            return foo.Bar();
00007FFE7B521846  mov         rcx,rsi  
00007FFE7B521849  mov         r11,7FFE7B410028h  
00007FFE7B521853  cmp         dword ptr [rcx],ecx  
00007FFE7B521855  call        qword ptr [7FFE7B410028h]  
00007FFE7B52185B  nop  
00007FFE7B52185C  add         rsp,30h  
00007FFE7B521860  pop         rsi  
00007FFE7B521861  ret  

Sorry for potentially very dumb and novice questions :) but could someone please give me a hint on:

1 Why do we need cmp instruction here (there is no any conditional jump after the cmp)
2 What is 7FFE7B410028h and why we load in r11 here
3 Isn't it too expensive to have cmp per interface call (could cml in that case cause branch prediction miss?)

Thank you a lot!

area-CodeGen-coreclr

Most helpful comment

Why do we need cmp instruction here (there is no any conditional jump after the cmp)

To trigger a NullReferenceException at he point of the call when this is null.

What is 7FFE7B410028h and why we load in r11 here

The address of an "indirection cell" that points to a stub that resolves and calls the interface implementation method. Unfortunately resolving interface methods is a relatively complicated operation that cannot be done "inline".

Initially it points to https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28

Some documentation is available here (though I'm not sure how up to date it is)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md

You can probably skip straight to https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs to get a quick overview.

Isn't it too expensive to have cmp per interface call (could cml in that case cause branch prediction miss?)

It's a compare instruction, not a conditional branch instruction, so it has nothing to do with branch prediction. And it's very cheap compared to the actual interface call cost.

All 3 comments

The cmp is an early nulll check.
You can read about interface dispatch here https://github.com/dotnet/coreclr/blob/master/Documentation/botr/virtual-stub-dispatch.md

Why do we need cmp instruction here (there is no any conditional jump after the cmp)

To trigger a NullReferenceException at he point of the call when this is null.

What is 7FFE7B410028h and why we load in r11 here

The address of an "indirection cell" that points to a stub that resolves and calls the interface implementation method. Unfortunately resolving interface methods is a relatively complicated operation that cannot be done "inline".

Initially it points to https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28

Some documentation is available here (though I'm not sure how up to date it is)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md

You can probably skip straight to https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs to get a quick overview.

Isn't it too expensive to have cmp per interface call (could cml in that case cause branch prediction miss?)

It's a compare instruction, not a conditional branch instruction, so it has nothing to do with branch prediction. And it's very cheap compared to the actual interface call cost.

@mikedn @omariom Thank you

Was this page helpful?
0 / 5 - 0 ratings