Oi pessoal!
Tenha um aplicativo bem simples, que chame o método de interface como este.
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);
}
}
}
Isso gera o seguinte ASM para 2.2 (para 3.0 há lea rsp, [rbp] em vez de adicionar 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
Desculpe por perguntas potencialmente muito idiotas e novatas :) mas alguém poderia me dar uma dica sobre:
1 Por que precisamos da instrução cmp aqui (não há nenhum salto condicional após o cmp)
2 O que é 7FFE7B410028h e por que carregamos em r11 aqui
3 Não é muito caro ter cmp por chamada de interface (poderia cml, nesse caso, causar falha de previsão de ramificação?)
Muito obrigado!
O cmp é uma verificação nula antecipada.
Você pode ler sobre o despacho de interface aqui https://github.com/dotnet/coreclr/blob/master/Documentation/botr/virtual-stub-dispatch.md
Por que precisamos da instrução cmp aqui (não há nenhum salto condicional após o cmp)
Para acionar NullReferenceException
no ponto da chamada quando this
é null
.
O que é 7FFE7B410028h e por que carregamos em r11 aqui
O endereço de uma "célula indireta" que aponta para um esboço que resolve e chama o método de implementação da interface. Infelizmente, resolver métodos de interface é uma operação relativamente complicada que não pode ser feita "inline".
Inicialmente, ele aponta para https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28
Alguma documentação está disponível aqui (embora eu não tenha certeza de como ela está atualizada)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md
Você provavelmente pode pular direto para https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs para obter uma visão geral rápida.
Não é muito caro ter cmp por chamada de interface (poderia cml, nesse caso, causar falha de previsão de branch?)
É uma instrução de comparação, não uma instrução de desvio condicional, portanto, não tem nada a ver com a previsão de desvio. E é muito barato em comparação com o custo real da chamada da interface.
@mikedn @omariom obrigado
Comentários muito úteis
Para acionar
NullReferenceException
no ponto da chamada quandothis
énull
.O endereço de uma "célula indireta" que aponta para um esboço que resolve e chama o método de implementação da interface. Infelizmente, resolver métodos de interface é uma operação relativamente complicada que não pode ser feita "inline".
Inicialmente, ele aponta para https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28
Alguma documentação está disponível aqui (embora eu não tenha certeza de como ela está atualizada)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md
Você provavelmente pode pular direto para https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs para obter uma visão geral rápida.
É uma instrução de comparação, não uma instrução de desvio condicional, portanto, não tem nada a ver com a previsão de desvio. E é muito barato em comparação com o custo real da chamada da interface.