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!
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
Most helpful comment
To trigger a
NullReferenceException
at he point of the call whenthis
isnull
.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.
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.