为什么 JVM 仍然不支持尾部调用优化?

进行jvm-prevent-tail-call-optimizations两年后,似乎有一个原型实现MLVM已经将该功能列为“原型80%”一段时间了。

Sun/Oracle方面是否对支持尾部调用没有积极兴趣,或者只是尾部调用是“[...]注定在每个功能优先级列表上排名第二[...]”正如在JVM语言峰会上提到的?

如果有人测试了MLVM构建,并且可以分享一些关于它工作效果的印象(如果有的话),我会非常感兴趣。

更新:请注意,某些 VM(如 Avian)支持正确的尾部调用,而不会出现任何问题。


答案 1

诊断 Java 代码:提高 Java 代码的性能alt) 解释了为什么 JVM 不支持尾部调用优化。

但是,尽管众所周知如何将尾递归函数自动转换为简单的循环,但Java规范并不要求进行这种转换。据推测,它不是必需的一个原因是,一般来说,转换不能在面向对象的语言中静态地进行。相反,从尾递归函数到简单循环的转换必须由 JIT 编译器动态完成。

然后,它给出了一个不会转换的Java代码的示例。

因此,正如清单 3 中的示例所示,我们不能期望静态编译器在 Java 代码上执行尾递归转换,同时保留语言的语义。相反,我们必须依靠 JIT 的动态编译。根据 JVM 的不同,JIT 可能会或可能不会执行此操作。

然后,它给出了一个测试,您可以使用它来确定您的JIT是否这样做。

当然,由于这是一篇 IBM 论文,因此它包含一个插件:

我用几个Java SDK运行了这个程序,结果令人惊讶。在 1.3 版的 Sun 的 Hotspot JVM 上运行表明 Hotspot 不执行转换。在默认设置下,堆栈空间在我的计算机上会在不到一秒钟的时间内耗尽。另一方面,IBM的1.3版JVM没有问题,表明它确实以这种方式转换了代码。


答案 2

我过去看到过在Java中不实现TCO(并且被视为困难)的一个原因是JVM中的权限模型对堆栈敏感,因此尾部调用必须处理安全性方面。

我相信这不是Clements和Felleisen [1] [2]的障碍,我很确定问题中提到的MLVM补丁也处理它。

我意识到这并不能回答你的问题;只是添加有趣的信息。

  1. http://www.ccs.neu.edu/scheme/pubs/esop2003-cf.pdf
  2. http://www.ccs.neu.edu/scheme/pubs/cf-toplas04.pdf

推荐