Если вы откроете эту функцию в отладчике с кодом, скомпилированным в режиме отладки:
bool foo(string arg)
{
return bar(arg);
}
Вы можете установить 3 точки останова:
- На открывающей скобке функции.
- В строке «возврат».
- На закрывающей скобке функции.
Установка точки останова на открывающей скобке означает «разрыв, когда вызывается эта функция». Вот почему в начале метода есть инструкция no-op. Когда точка останова установлена на открывающей скобке, отладчик фактически устанавливает ее в нерабочем состоянии.
Установка точки останова на закрывающей скобке означает «разрыв, когда эта функция завершается». Чтобы это произошло, функция должна иметь одну инструкцию возврата в своем IL, где можно установить точку останова. Компилятор позволяет это, используя временную переменную для хранения возвращаемого значения и конвертируя
return retVal;
в
$retTmp = retVal;
goto exit;
, а затем вставьте следующий код в конец метода:
exit:
return $ret;
Кроме того, когда в режиме отладки компиляторы глупы в отношении кода, который они генерируют. Они в основном делают что-то вроде:
GenerateProlog();
foreach (var statement in statements)
{
Generate(statement);
}
GenerateEpilog();
В вашем случае вы видите:
return foo(arg);
переводится на:
; //this is a no-op
bool retTemp = false;
retTemp = foo(arg);
goto exit;
exit:
return retTemp;
Если бы компилятор выполнял «оптимизацию скользящего окна», он мог бы взглянуть на этот код и понять, что существует некоторая избыточность. Однако компиляторы обычно не делают этого в режиме отладки. Оптимизация компилятора может выполнять такие вещи, как устранение переменных и изменение порядка команд, что затрудняет отладку. Поскольку целью отладочной сборки является включение отладки, было бы нецелесообразно включать оптимизацию.
В сборке релиза код не будет выглядеть так. Это связано с тем, что компилятор не вводит специальный код для включения точек останова на открывающей и закрывающей скобках, в результате чего компилируется следующее:
return bar(arg);
Все выглядит довольно просто.
Следует отметить, однако, что я не думаю, что компилятор C # делает много оптимизаций скользящего окна, даже в розничных сборках. Это потому, что большинство этих оптимизаций зависят от базовой архитектуры процессора и выполняются компилятором JIT. Выполнение оптимизаций, даже тех, которые не зависят от процессора, в компиляторе C # может препятствовать способности JIT оптимизировать код (он ищет шаблоны, сгенерированные неоптимизированной генерацией кода, и если он видит сильно оптимизированный IL, он может получить смущенный). Поэтому обычно компиляторы управляемого кода не делают их. Он делает некоторые «дорогие вещи» (которые JIT не хочет делать во время выполнения), такие как обнаружение мертвого кода и анализ переменных в реальном времени, но они не решают проблемы, решаемые путем оптимизации скользящего окна.