为什么JVM仍然不支持tail-call优化?

两年之后,这个function似乎有了一个原型 实现 , MLVM已经把function列为“原型80%”了一段时间了。

Sun和Oracle在支持尾部呼叫方面没有积极的兴趣,或者只是尾部呼叫“ 在每个function优先级列表中被排在第二位 ”,正如JVM语言峰会 ?

如果有人testing了MLVM构build,并且可以分享一些它的工作效果(如果有的话),我会非常感兴趣。

更新: 请注意,像Avian这样的虚拟机支持正确的tail-calls,没有任何问题。

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

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

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

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

然后它给出了一个testing,你可以用来确定你的JIT是否这样做。

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

我用两个Java SDK运行这个程序,结果令人惊讶。 在Sun的Hotspot JVM上运行版本1.3,表明Hotspot不执行转换。 在默认设置下,堆栈空间在我的机器上耗尽不到一秒钟。 另一方面,IBM的1.3版本的JVM毫无问题,表明它以这种方式转换代码。

我之前在Java中看到没有实现TCO(而且看起来很难)的一个原因是JVM中的许可模型是堆栈敏感的,因此tail-calls必须处理安全方面的问题。

我相信这不会成为Clements和Felleisen [1] [2]的障碍,我很确定问题中提到的MLVM补丁也是如此。

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

  1. scheme/pubs/esop2003-cf.pdf
  2. scheme/pubs/cf-toplas04.pdf

也许你已经知道了,但是这个function并不像听起来那么简单,因为Java语言实际上把堆栈跟踪暴露给了程序员。

考虑下面的程序:

 public class Test { public static String f() { String s = Math.random() > .5 ? f() : g(); return s; } public static String g() { if (Math.random() > .9) { StackTraceElement[] ste = new Throwable().getStackTrace(); return ste[ste.length / 2].getMethodName(); } return f(); } public static void main(String[] args) { System.out.println(f()); } } 

即使这有一个“尾巴”,它可能不会被优化。 (如果它优化,它仍然需要整个调用堆栈的logging,因为程序的语义依赖于它。)

基本上,这意味着在向下兼容的同时很难支持这一点。

Java是你可能想象得最less的function语言(嗯,好吧, 也许不是 !)但是这对于JVM语言来说是个很大的优势,比如说Scala 。

我的观察是,让JVM成为其他语言的平台似乎不在Sun的优先级列表的首位,我想,现在是Oracle。