В конце лета в JIT внесли изменение, учитывающее семантику методов, которые не содержат
return. Грубо говоря, теперь методы, не возвращающие нормально управление обратно в вызывающий их код, помечаются флагом
DOES_NOT_RETURN.
Вот здесь можно почитать подробнее:
Do not inline methods that never return
Соответственно, предлагаю вынести
throw Exception из внутреннестей Code/EnumCode и других методов в отдельный класс, например, в ThrowHelper.
Что это дает? Сейчас методы из набора
Code инлайнятся, что очень правильно, так как позволяет с экономить на вызовах и/или избежать самих проверок. В случае, когда джит удаляет проверки проблем нет. Они возникают, если джит не может их устранить. В этом случае, вместе с встраиванием ассерта инлайнится и код, генерирующий исключение. Ассемблерный листинг показывает, что генерация исключений спокойно может раздуть код в несколько раз, для маленьких методов так вообще в 10-15 раз.
В целом, для текущего джита все останется примерно так же как сейчас, от нового мы получим профит
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Здравствуйте, rameel, Вы писали:
R>В целом, для текущего джита все останется примерно так же как сейчас, от нового мы получим профит
Наивный вопрос: а как оно нам поможет?
В смысле, у нас весь код выполнен в стиле
void Check(...)
{
if (somethingBadHappened)
{
throw CreateException(...);
}
}
всё, что поменяется с
DOES_NOT_RETURN — это не будет инлайниться CreateException(), который по определению находится в cold path. Сам Check инлайнится по-прежнему.
Короч, нужен тест чтоб было видно что текущее положение дел не ухудшилось.
Здравствуйте, Sinix, Вы писали:
| Скрытый текст |
| S>В смысле, у нас весь код выполнен в стиле
S>S>void Check(...)
S>{
S> if (somethingBadHappened)
S> {
S> throw CreateException(...);
S> }
S>}
S>
|
| |
S>всё, что поменяется с DOES_NOT_RETURN — это не будет инлайниться CreateException(), который по определению находится в cold path. Сам Check инлайнится по-прежнему.
Предлагается сделать так:
void Check(...)
{
if (somethingBadHappened)
{
ThrowHelper.ThrowSomeException();
}
}
class ThrowHelper
{
public static void ThrowSomeException()
{
throw CodeExceptions.SomeException();
}
}
В данном случае инлайнится Check и CodeExceptions. С
DOES_NOT_RETURN не инлайнится ThrowHelper.ThrowSomeException(), который переедет в cold path.
Для вот такого кода
| Пример кода на C# |
| public static int Add(int value)
{
Assert(value, nameof(value));
return value + 10;
}
public static void Assert(int value, string paramName)
{
if (value < 0)
throw CreateException(paramName);
}
private static ArgumentOutOfRangeException CreateException(string paramName)
{
return new ArgumentOutOfRangeException(paramName);
}
|
| |
c
DOES_NOT_RETURN и без него джит генерирует такой код
00007FF7BA0D04C0 push rsi
00007FF7BA0D04C1 sub rsp,20h
Assert(value, nameof(value));
00007FF7BA0D04C5 test ecx,ecx
00007FF7BA0D04C7 jl 00007FF7BA0D04D2
return value + 10;
00007FF7BA0D04C9 lea eax,[rcx+0Ah]
00007FF7BA0D04CC add rsp,20h
00007FF7BA0D04D0 pop rsi
00007FF7BA0D04D1 ret
Assert(value, nameof(value));
00007FF7BA0D04D2 mov rcx,7FF818831FC0h
00007FF7BA0D04DC call 00007FF8196C2510
00007FF7BA0D04E1 mov rsi,rax
00007FF7BA0D04E4 mov ecx,1
00007FF7BA0D04E9 mov rdx,7FF7B9FC40E0h
00007FF7BA0D04F3 call 00007FF8198737E0
00007FF7BA0D04F8 mov rdx,rax
00007FF7BA0D04FB mov rcx,rsi
00007FF7BA0D04FE call 00007FF818ED4890
00007FF7BA0D0503 mov rcx,rsi
00007FF7BA0D0506 call 00007FF8198604E0
00007FF7BA0D050B int 3
Вот для такого
| Пример кода на C# |
| public static int Add(int value)
{
Assert(value, nameof(value));
return value + 10;
}
public static void Assert(int value, string paramName)
{
if (value < 0)
{
// Вынесли код, бросающий исключение в отдельный метод
ThrowException(paramName);
}
}
private static void ThrowException(string paramName)
{
throw CreateException(paramName);
}
private static ArgumentOutOfRangeException CreateException(string paramName)
{
return new ArgumentOutOfRangeException(paramName);
}
|
| |
c
DOES_NOT_RETURN джит генерирует вот такое
00007FF7BA0D04C0 push rsi
00007FF7BA0D04C1 sub rsp,20h
Assert(value, nameof(value));
00007FF7BA0D04C5 test ecx,ecx
00007FF7BA0D04C7 jl 00007FF7BA0C04CB
return value + 10;
00007FF7BA0D04C9 lea eax,[rcx+0Ah]
00007FF7BA0D04CC add rsp,20h
00007FF7BA0D04D0 pop rsi
00007FF7BA0D04D1 ret
Assert(value, nameof(value));
00007FF7BA0C04CB mov rcx,1D39B833578h
00007FF7BA0C04D5 mov rcx,qword ptr [rcx]
00007FF7BA0C04D8 call 00007FF7BA0C0090
В общем, с новым джитом и вынесением методов, бросающих исключение, код становится более кеш-френдли. Без этого генерируемый код исключений плодится по всем методам, где его используют
S>Короч, нужен тест чтоб было видно что текущее положение дел не ухудшилось.
Для текущего джита можно навесить на методы ThrowHelper.Throw...
MethodImplOptions.AggressiveInlining, тогда асм. код будет один в один как сейчас.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Здравствуйте, rameel, Вы писали:
R>Для текущего джита можно навесить на методы ThrowHelper.Throw... MethodImplOptions.AggressiveInlining, тогда асм. код будет один в один как сейчас.
Ну, если это текущие фреймворки не затронет, то можешь и поменять.
Тут другой момент — Core мы пока что не поддерживаем вообще, а когда оно доберется до .Net FW — одному богу известно.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>