Привет, ребята!
У вас есть очень простое приложение, которое вызывает такой метод интерфейса.
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);
}
}
}
Это генерирует следующий ASM для 2.2 (для 3.0 вместо add rsp, 30h используется lea rsp, [rbp])
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 - это ранняя проверка на нулевое значение.
О диспетчеризации интерфейсов можно прочитать здесь https://github.com/dotnet/coreclr/blob/master/Documentation/botr/virtual-stub-dispatch.md
Зачем здесь нужна инструкция cmp (после cmp нет никакого условного перехода)
Чтобы вызвать NullReferenceException
в точке вызова, когда this
равно null
.
Что такое 7FFE7B410028h и почему мы здесь загружаем в r11
Адрес «косвенной ячейки», указывающей на заглушку, которая разрешает и вызывает метод реализации интерфейса. К сожалению, разрешение методов интерфейса - это относительно сложная операция, которую нельзя выполнить «на лету».
Первоначально он указывает на 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, чтобы получить быстрый обзор.
Разве не слишком дорого иметь cmp для каждого вызова интерфейса (может ли cml в этом случае вызвать ошибку предсказания ветвления?)
Это инструкция сравнения, а не инструкция условного перехода, поэтому она не имеет ничего общего с предсказанием перехода. И это очень дешево по сравнению с реальной стоимостью вызова интерфейса.
@mikedn @omariom Спасибо
Самый полезный комментарий
Чтобы вызвать
NullReferenceException
в точке вызова, когдаthis
равно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, чтобы получить быстрый обзор.
Это инструкция сравнения, а не инструкция условного перехода, поэтому она не имеет ничего общего с предсказанием перехода. И это очень дешево по сравнению с реальной стоимостью вызова интерфейса.