很多人以为C语言天生就能做尾调用优化,但事实并非如此。以x86等常见架构上的C调用约定为例,被调用的函数并不会清理调用者压入栈的参数,而是由调用者在调用返回后自己完成清理。也就是说,调用者必须在“调用”和“返回”之间插入参数清理动作,这会让本来的尾调用变成非尾调用。
1994年,我观察当时的C编译器时发现,它们对文章里展示的那种尾调用场景并不会做优化。到了2001年,Mark Probst才在GCC中通过一套单独调用约定实现了尾调用优化。他在论文第6.4节列出了当时GCC尾调用优化的一系列限制,其中包括“无法处理间接调用”。对于解释器分发这类需要动态跳转的场景,这恰是一个关键问题。
![]()
此后很长一段时间,我没有再仔细跟进GCC的尾调用支持,因为GCC提供的“goto *”已经基本够用。直到去年读到一篇关于“Copy-and-Patch Compilation”的论文,我才重新关注这个问题。论文作者Xu和Kjolstad使用了尾调用优化,而且是用10万个代码片段做实验;相比之下,我们在Gforth中只用了不到2000个片段。如果GCC和Clang真能支持10万量级的尾调用,那么解释器实现中就能采用更灵活、更高效的技术。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.