¡Hola tios!
Tenga una aplicación muy simple, que llame a un método de interfaz 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);
}
}
}
Eso genera el siguiente ASM para 2.2 (para 3.0 hay lea rsp, [rbp] en lugar de agregar 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
Perdón por las preguntas potencialmente muy tontas y novatos :) pero, ¿alguien podría darme una pista sobre:
1 ¿Por qué necesitamos la instrucción cmp aquí (no hay ningún salto condicional después del cmp)
2 ¿Qué es 7FFE7B410028h y por qué cargamos en r11 aquí?
3 ¿No es demasiado caro tener cmp por llamada de interfaz (¿podría cml en ese caso causar un error en la predicción de rama?)
¡Muchas gracias!
El cmp es una verificación nula temprana.
Puede leer sobre el envío de la interfaz aquí https://github.com/dotnet/coreclr/blob/master/Documentation/botr/virtual-stub-dispatch.md
¿Por qué necesitamos la instrucción cmp aquí (no hay ningún salto condicional después del cmp)
Activar un NullReferenceException
en el punto de la llamada cuando this
es null
.
¿Qué es 7FFE7B410028h y por qué cargamos en r11 aquí?
La dirección de una "celda de indirección" que apunta a un código auxiliar que resuelve y llama al método de implementación de la interfaz. Desafortunadamente, la resolución de métodos de interfaz es una operación relativamente complicada que no se puede realizar "en línea".
Inicialmente apunta a https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28
Alguna documentación está disponible aquí (aunque no estoy seguro de si está actualizada)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md
Probablemente pueda ir directamente a https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs para obtener una descripción general rápida.
¿No es demasiado costoso tener cmp por llamada de interfaz (¿podría cml en ese caso causar un error en la predicción de rama?)
Es una instrucción de comparación, no una instrucción de rama condicional, por lo que no tiene nada que ver con la predicción de rama. Y es muy barato en comparación con el costo real de la llamada de interfaz.
@mikedn @omariom Gracias
Comentario más útil
Activar un
NullReferenceException
en el punto de la llamada cuandothis
esnull
.La dirección de una "celda de indirección" que apunta a un código auxiliar que resuelve y llama al método de implementación de la interfaz. Desafortunadamente, la resolución de métodos de interfaz es una operación relativamente complicada que no se puede realizar "en línea".
Inicialmente apunta a https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/coreclr/src/vm/amd64/VirtualCallStubAMD64.asm#L28
Alguna documentación está disponible aquí (aunque no estoy seguro de si está actualizada)
https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md
Probablemente pueda ir directamente a https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/virtual-stub-dispatch.md#stubs para obtener una descripción general rápida.
Es una instrucción de comparación, no una instrucción de rama condicional, por lo que no tiene nada que ver con la predicción de rama. Y es muy barato en comparación con el costo real de la llamada de interfaz.