为了实现尾调用优化,jvm 必须牺牲什么?

发布于 2024-07-24 11:15:51 字数 515 浏览 4 评论 0原文

人们说,除了没有尾部调用优化的限制之外,clojure 实现非常出色——这是 jvm 的限制,而不是 clojure 实现的限制。

http://lambda-the-ultimate.org/node/2547

表示在 Python 中实现 TCO 会牺牲

  • 堆栈跟踪转储和
  • 调试规律性。

向我解释一下尾部调用优化的重要意义是什么以及为什么 Python 需要它

对于 TCO 的 jvm 实现是否必须做出同样的牺牲? 还需要牺牲什么吗?

People say that the clojure implementation is excellent apart from the limitation of having no tail call optimisation - a limitation of the jvm not the clojure implementation.

http://lambda-the-ultimate.org/node/2547

It has been said that to implement TCO into Python would sacrifice

  • stack-trace dumps, and
  • debugging regularity.

Explain to me what the big deal with tail call optimization is and why Python needs it

Would the same sacrifices have to be made for a jvm implementation of TCO? Would anything else have to be sacrificed?

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

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

发布评论

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

评论(3

遗忘曾经 2024-07-31 11:15:51

虽然有所不同(因为 il 指令已经存在),但值得注意的是 .Net 64 位 JIT 团队 必须经历尊重所有尾调用。

我特别指出评论:

当然,缺点是,如果您必须调试或分析优化的代码,请准备好处理看起来缺少一些帧的调用堆栈。

我认为 JVM 也不太可能避免这种情况。

鉴于此,在请求尾部调用优化的情况下,JIT 应假定需要避免堆栈溢出,这不能在调试版本中关闭。 如果它们在您到达有趣的部分之前就崩溃了,那么它们对于调试就没有多大用处。 “优化”实际上是一个永久功能,也是受其影响的堆栈跟踪的问题。

值得指出的是,在执行程序员概念上描述/理解为堆栈操作(例如调用函数)的操作时,任何避免创建真实堆栈帧的优化都会固有地导致呈现给用户的内容之间的脱节调试/提供堆栈跟踪和现实时。
这是不可避免的,因为描述操作的代码与执行操作的状态机的机制越来越分离。

Whilst different (in that the il instructions existed already) it's worth noting the additional effort the .Net 64 bit JIT team had to go through to respect all tail calls.

I call out in particular the comment:

The down side of course is that if you have to debug or profile optimized code, be prepared to deal with call stacks that look like they’re missing a few frames.

I would think it highly unlikely the JVM could avoid this either.

Given that, in circumstances where a tail call optimization was requested, the JIT should assume that it is required to avoid a stack overflow this is not something that can just be switched off in Debug builds. They aren't much use for debugging if they crash before you get to the interesting part. The 'optimization' is in fact is a permanent feature and an issue for stack traces affected by it.

It is worth pointing out that any optimization which avoids creating a real stack frame when doing an operation which the programmer conceptually describes/understands as being a stack operation (calling a function for example) will inherently cause a disconnect between what is presented to the user when debugging/providing the stack trace and reality.
This is unavoidable as the code that describes the operation becomes further and further separated from the mechanics of the state machine performing the operation.

属性 2024-07-31 11:15:51

现在正在进行向 JVM 添加尾调用。 有一个wiki 页面讨论了一些细节。

Work is underway now to add tail calls to the JVM. There's a wiki page talking about some details.

兮子 2024-07-31 11:15:51

是的,通常情况下,实施 TCO 会阻止您获得完整的堆栈跟踪。 这是不可避免的,因为 TCO 的重点是避免创建额外的堆栈帧。

还值得注意的是,Clojure 有一个非堆栈消耗的“recur”功能,可以绕过当前 JVM 版本的这一限制。

例子:

(defn triangle [n accumulator] 
  (if 
    (<= n 0)  
      accumulator
      (recur (dec n) (+ n accumulator))))

(triangle 1000000 0)

=> 500000500000     (note stack does not explode here!)

Yes it is generally the case that implementing TCO will prevent you from getting full stack traces. This is inevitable because the whole point of TCO is to avoid creating additional stack frames.

It's also worth interesting to note that Clojure has an non-stack-consuming "recur" feature to get around this constraint on current JVM versions.

Example:

(defn triangle [n accumulator] 
  (if 
    (<= n 0)  
      accumulator
      (recur (dec n) (+ n accumulator))))

(triangle 1000000 0)

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