嗨,大家好!
有一个非常简单的应用程序,调用接口方法是这样的。
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);
}
}
}
为 2.2 生成以下 ASM(对于 3.0,有 lea rsp,[rbp] 而不是 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
很抱歉可能非常愚蠢和新手的问题:) 但有人可以给我一个提示:
1 为什么这里需要cmp指令(cmp后没有条件跳转)
2 什么是 7FFE7B410028h 以及为什么我们在这里加载 r11
3 每个接口调用都有 cmp 是不是太贵了(在这种情况下,cml 会导致分支预测失败吗?)
非常感谢!
cmp是早期的 nulll 检查。
您可以在此处阅读有关接口调度的信息https://github.com/dotnet/coreclr/blob/master/Documentation/botr/virtual-stub-dispatch.md
为什么这里需要cmp指令(cmp后面没有条件跳转)
当this
为null
时,在调用点触发NullReferenceException
null
。
什么是 7FFE7B410028h 以及为什么我们在这里加载 r11
指向解析和调用接口实现方法的存根的“间接单元”的地址。 不幸的是,解析接口方法是一个相对复杂的操作,不能“内联”完成。
此处提供了一些文档(尽管我不确定它是最新的)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md
您可以直接跳到https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs以获得快速概览。
每个接口调用都有 cmp 是不是太贵了(在这种情况下 cml 会导致分支预测失败吗?)
这是一条比较指令,不是条件分支指令,因此与分支预测无关。 而且与实际的接口调用成本相比,它非常便宜。
@mikedn @omariom谢谢
最有用的评论
当
this
为null
时,在调用点触发NullReferenceException
null
。指向解析和调用接口实现方法的存根的“间接单元”的地址。 不幸的是,解析接口方法是一个相对复杂的操作,不能“内联”完成。
最初它指向https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28
此处提供了一些文档(尽管我不确定它是最新的)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md
您可以直接跳到https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs以获得快速概览。
这是一条比较指令,不是条件分支指令,因此与分支预测无关。 而且与实际的接口调用成本相比,它非常便宜。