简体   繁体   English

为什么代码会主动尝试阻止尾调优化?

[英]Why would code actively try to prevent tail-call optimization?

The title of the question might be a bit strange, but the thing is that, as far as I know, there is nothing that speaks against tail call optimization at all. 这个问题的标题可能有点奇怪,但事实是,据我所知,根本没有什么可以反对尾部调用优化。 However, while browsing open source projects, I already came across a few functions that actively try to stop the compiler from doing a tail call optimization, for example the implementation of CFRunLoopRef which is full of such hacks . 但是,在浏览开源项目时,我已经遇到了一些主动尝试阻止编译器进行尾调用优化的函数,例如CFRunLoopRef的实现,这些函数充满了这样的黑客攻击 For example: 例如:

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
}

I would love to know why this is seemingly so important, and are there any cases were I as a normal developer should keep this is mind too? 我很想知道为什么这看起来如此重要,有没有我作为一个普通的开发人员应该保持这种想法呢? Eg. 例如。 are there common pitfalls with tail call optimization? 尾调用优化有常见的陷阱吗?

My guess here is that it's to ensure that __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ is in the stack trace for debugging purposes. 我的猜测是确保__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__在堆栈跟踪中以进行调试。 It has __attribute__((no inline)) which backs up this idea. 它有__attribute__((no inline))来支持这个想法。

If you notice, that function just goes and bounces to another function anyway, so it's a form of trampoline which I can only think is there with such a verbose name to aid debugging. 如果你注意到,那个函数只是去反弹到另一个函数,所以它是一种蹦床形式,我只能想到它有一个冗长的名称来帮助调试。 This would be especially helpful given that the function is calling a function pointer that has been registered from elsewhere and therefore that function may not have debugging symbols accessible. 这将是特别有用的,因为该函数正在调用已从其他地方注册的函数指针,因此该函数可能没有可访问的调试符号。

Notice also the other similarly named functions which do similar things - it really looks like it's there to aid in seeing what has happened from a backtrace. 还要注意其他类似命名的函数,这些函数执行类似的操作 - 它看起来确实有助于查看从回溯中发生的事情。 Keep in mind that this is core Mac OS X code and will show up in crash reports and process sample reports too. 请记住,这是核心Mac OS X代码,也会出现在崩溃报告和流程样本报告中。

This is only a guess, but maybe to avoid an infinite loop vs bombing out with a stack overflow error. 这只是一个猜测,但可能是为了避免无限循环与使用堆栈溢出错误进行轰炸。

Since the method in question doesn't put anything on the stack it would seem possible for the tail-call recursion optimization to produce code that would enter an infinite loop as opposed to the non-optimized code which would put the return address on the stack which would eventually overflow in the event of misuse. 由于所讨论的方法没有在堆栈上放置任何内容,因此尾调用递归优化可能会产生进入无限循环的代码,而不是将返回地址放在堆栈上的非优化代码在滥用的情况下最终会溢出。

The only other thought I have is related to preserving the calls on the stack for debugging and stacktrace printing. 我唯一的另一个想法是保留堆栈上的调用以进行调试和堆栈跟踪打印。

一个潜在的原因是使调试和分析更容易(使用TCO,父堆栈框架消失,这使得堆栈跟踪更难理解。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM