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

发布于 2024-09-17 08:56:31 字数 896 浏览 12 评论 0原文

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

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

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

更新: 请注意,某些虚拟机例如 Avian< /a> 支持正确的尾部调用,没有任何问题。

Two years after does-the-jvm-prevent-tail-call-optimizations, there seems to be a prototype implementation and MLVM has listed the feature as "proto 80%" for some time now.

Is there no active interest from Sun's/Oracle's side in supporting tail calls or is it just that tail calls are "[...] fated to come in second place on every feature priority list [...]" as mentioned at the JVM Language Summit?

I would be really interested if someone has tested a MLVM build and could share some impressions of how well it works (if at all).

Update: Note that some VMs like Avian support proper tail-calls without any issues.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

云裳 2024-09-24 08:56:31

我过去发现在 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

One reason I've seen in the past for not implementing TCO (and it being seen as difficult) in Java is that the permission model in the JVM is stack-sensitive and thus tail-calls must handle the security aspects.

I believe this was shown to not be an obstacle by Clements and Felleisen [1] [2] and I'm pretty sure the MLVM patch mentioned in the question deals with it as well.

I realize this does not answer your question; just adding interesting information.

  1. http://www.ccs.neu.edu/scheme/pubs/esop2003-cf.pdf
  2. http://www.ccs.neu.edu/scheme/pubs/cf-toplas04.pdf
知你几分 2024-09-24 08:56:31

诊断 Java 代码:提高 Java 代码的性能 (< a href="http://web.archive.org/web/20120506085636/http://www.ibm.com/developerworks/java/library/j-diag8/index.html" rel="noreferrer">alt< /a>) 解释了为什么 JVM 不支持尾部调用优化。

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

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

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

然后它提供了一个测试,您可以用它来确定您的 JIT 是否执行此操作。

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

我和几个人一起运行了这个程序
Java SDK,结果是
奇怪。在太阳热点上运行
1.3 版本的 JVM 表明
热点不执行
转变。在默认设置下,
堆栈空间在更少的时间内耗尽
比我的机器上的一秒钟还要多。上
另一方面,IBM 的 JVM 版本 1.3
毫无问题地发出呼噜声,
表明它确实改变了
代码就是这样。

Diagnosing Java Code: Improving the Performance of Your Java Code (alt) explains why the JVM does not support tail-call optimization.

But although it is well known how to automatically transform a tail-recursive function into a simple loop, the Java specification doesn't require that this transformation be made. Presumably, one reason it is not a requirement is that, in general, the transformation can't be made statically in an object-oriented language. Instead, the transformation from tail-recursive function to simple loop must be done dynamically by a JIT compiler.

It then gives an example of Java code that won't transform.

So, as the example in Listing 3 shows, we cannot expect static compilers to perform transformation of tail recursion on Java code while preserving the semantics of the language. Instead, we must rely on dynamic compilation by the JIT. Depending on the JVM, the JIT may or may not do this.

Then it gives a test you can use to figure out if your JIT does this.

Naturally, since this is an IBM paper, it includes a plug:

I ran this program with a couple of
the Java SDKs, and the results were
surprising. Running on Sun's Hotspot
JVM for version 1.3 reveals that
Hotspot doesn't perform the
transformation. At default settings,
the stack space is exhausted in less
than a second on my machine. On the
other hand, IBM's JVM for version 1.3
purrs along without a problem,
indicating that it does transform the
code in this way.

嘿哥们儿 2024-09-24 08:56:31

也许您已经知道这一点,但该功能并不像听起来那么微不足道,因为 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());
    }
}

即使它有一个“尾部调用”,它也可能没有被优化。 (如果它经过优化,它仍然需要记录整个调用堆栈,因为程序的语义依赖于它。)

基本上,这意味着在仍然落后的情况下很难支持这一点兼容的。

Perhaps you know this already, but the feature is not as trivial as it may sound since the Java language actually exposes the stack trace to the programmer.

Consider the following program:

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());
    }
}

Even though this has a "tail-call" it may not be optimized. (If it is optimized, it still requires book-keeping of the entire call-stack since the semantics of the program relies on it.)

Basically, this means that it's hard to support this while still being backward compatible.

拧巴小姐 2024-09-24 08:56:31

Java 是你能想象到的最不实用的语言(好吧,也许不是!)但是这个对于 JVM 语言来说,这将是一个巨大的优势,例如 Scala

我的观察是,让 JVM 成为其他语言的平台似乎从来都不是 Sun 的首要任务,我猜现在是 Oracle 的首要任务。

Java is the least functional language you could possibly imagine (well, OK, perhaps not!) but this would be a great advantage for JVM languages, like Scala, which are.

My observations are that making the JVM a platform for other languages has never seemed to be at the top of the priority list for Sun and I guess, now for Oracle.

开始看清了 2024-09-24 08:56:31

这不是 Java 的问题……而是 JVM 的问题之一。 Java 是 JVM 语言的鼻祖。

制作 TCO 是跳转到下一个堆栈帧,同时删除当前堆栈帧,在正在运行的程序和当前堆栈调用变量之间应该在其他地方......;)

最好的方法是为跳转提供一个新的特殊调用操作码-调用其他框架来制作这些东西。他们已经在虚拟通话中这样做了。解释上并不是真正的问题,JIT 可能会引发其他问题,而且 JVM 已经足够臃肿了。

在Java或其他语言中,由于没有适当的TCO,另一种方法是tramponing,但它增加了很多代码。或者使用特定的异常,但它很混乱。而且它在你的代码中,但不在别人的库中......

啊!如果 Rich Hickey 添加了一个(重复的...)东西(它不是一个函数),那是因为缺乏真正的 TCO,他不希望人们认为有一个。他可以很容易地在内部尾调用中自动生成 TCO。它还有助于检测不在尾部位置的不良尾部调用。

还有一个用于外部 TCO 的(蹦床...)东西,但它很混乱(作为蹦床),并且除了在糟糕的堆栈情况下之外很少使用。

但是,是的,很多虚拟机都在管理 TCO。我听说 CLR 会。我什至见过一个付费的 JVM 来管理它(不久前,不记得了......)

js 中的 Trampolining 示例: https://codeinjavascript.com/2020/06/13/tail-call-optimization-tco/

关于带 Frame 的 HotSpot VM 上的 TCO 的旧论文覆盖:https://ssw.jku.at/Research/Papers/Schwaighofer09Master/ schwaihofer09master.pdf

It's not a Java problem... it's one of the JVM. Java is just the grand-grand-ol'-pa of JVM languages.

Making a TCO is jumping to the next Stack Frame while deleting the current one, in between the running program and current stack calling vars should be somewhere else... ;)

The best way would be to have a new special call opcode for a jump-call in other frames that makes the stuff. They already did that for the virtual call. Not really a problem in interpretation, JIT perhaps rises other problems, and the JVM is bloated enough.

In Java or other languages, as there no proper TCO, the other way is trampolining, but it adds a lot of code. Or using specific exceptions, but it messes a lot. And it is in your code, but not in others' libraries...

Ah! If Rich Hickey added a (recur...) stuff (it's not a function), it's because of lack of real TCO, he doesn't want people to think there was one. He could very easily make an automatic TCO in an internal tail call. It also helps to detect bad tail calls that are not in tail position.

There's also a (trampoline...) stuff for external TCO, but it's messy (as a trampoline), and is quite not used except in awful stack situations.

But yes, a lot of VM manage TCO. I've heard that CLR will. I've even seen a paying JVM that manages it (a time ago, don't remember...)

Trampolining example in js: https://codeinjavascript.com/2020/06/13/tail-call-optimization-tco/

An old Thesis on TCO on HotSpot VM with Frame overwrite: https://ssw.jku.at/Research/Papers/Schwaighofer09Master/schwaighofer09master.pdf

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文