Почему код активно пытается предотвратить оптимизацию хвостового вызова?
название вопроса может быть немного странным, но дело в том, что, насколько я знаю, нет ничего, что говорит против оптимизации хвостового вызова вообще. Однако, просматривая проекты с открытым исходным кодом, я уже столкнулся с несколькими функциями, которые активно пытаются остановить компилятор от выполнения оптимизации хвостового вызова, например реализация CFRunLoopRef что это хаки. Например:
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
if (func) {
func(observer, activity, info);
}
getpid(); // thwart tail-call optimization
}
Я бы с удовольствием знаете, почему это, казалось бы, так важно, и есть ли какие-то случаи, когда я был нормальный разработчик должен держать это тоже ум? Например. есть ли общие подводные камни с оптимизацией хвостового вызова?
3 ответа:
Я предполагаю, что это для того, чтобы гарантировать, что
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
находится в трассировке стека для целей отладки. Он имеет__attribute__((no inline))
что подтверждает эту идею.Если вы заметили, что функция просто идет и отскакивает к другой функции в любом случае, так что это форма батута, который я могу только думать, что есть с таким подробным именем, чтобы помочь отладке. Это было бы особенно полезно, учитывая, что функция вызывает указатель на функцию, который был зарегистрирован в другом месте и поэтому что функция может не иметь доступных отладочных символов.
обратите внимание также на другие аналогично названные функции, которые делают подобные вещи - это действительно похоже на то, что это там, чтобы помочь увидеть, что произошло с обратной трассой. Имейте в виду, что это основной код Mac OS X и будет отображаться в отчетах о сбоях и обрабатывать образцы отчетов тоже.
Это только предположение, но, возможно, чтобы избежать бесконечного цикла против бомбардировки с ошибкой переполнения стека.
поскольку рассматриваемый метод ничего не помещает в стек, представляется возможным для оптимизации рекурсии хвостового вызова создать код, который войдет в бесконечный цикл, а не в неоптимизированный код, который поместит обратный адрес в стек, который в конечном итоге переполнится в случае неправильного использования.
единственная другая мысль у меня есть связано с сохранением вызовов в стеке для отладки и печати stacktrace.