Clojure does not perform tail call optimization on its own: when you have a tail recursive function and you want to have it optimized, you have to use the special form recur. Similarly, if you have two mutually recursive functions, you can optimize them only by using trampoline.
The Scala compiler is able to perform TCO for a recursive function, but not for two mutually recursive functions.
Whenever I have read about these limitations, they were always ascribed to some limitation intrinsic to the JVM model. I know pretty much nothing about compilers, but this puzzles me a bit. Let me take the example from Programming Scala. Here the function
def approximate(guess: Double): Double =
if (isGoodEnough(guess)) guess
else approximate(improve(guess))
is translated into
0: aload_0
1: astore_3
2: aload_0
3: dload_1
4: invokevirtual #24; //Method isGoodEnough:(D)Z
7: ifeq
10: dload_1
11: dreturn
12: aload_0
13: dload_1
14: invokevirtual #27; //Method improve:(D)D
17: dstore_1
18: goto 2
So, at the bytecode level, one just needs goto. In this case, in fact, the hard work is done by the compiler.
What facility of the underlying virtual machine would allow the compiler to handle TCO more easily?
As a side note, I would not expect actual machines to be much smarter than the JVM. Still, many languages that compile to native code, such as Haskell, do not seem to have issues with optimizing tail calls (well, Haskell can have sometimes due to laziness, but that is another issue).
tailcallinstruction for JVM has already been proposed as early as 2007: Blog on sun.com through the wayback machine. After the Oracle takeover, this link 404's. I'd guess it didn't make it into the JVM 7 priority list. – K.Steff Jul 21 '12 at 23:12tailcallinstruction would only mark a tail call as a tail call. Whether the JVM then actually optimized said tail call is a completely different question. The CLI CIL has a.tailinstruction prefix, yet the Microsoft 64-bit CLR for a long time didn't optimize it. OTOH, the IBM J9 JVM does detect tail calls and optimizes them, without needing a special instruction to tell it which calls are tail calls. Annotating tail calls and optimizing tail calls are really orthogonal. (Apart from the fact that statically deducing which call is a tail call may or may not be undecidable. Dunno.) – Jörg W Mittag Feb 04 '15 at 14:57call something; oreturn. The primary job of a JVM spec update would be not to introduce an explicit tail-call instruction but to mandate that such an instruction is optimized. Such an instruction only makes compiler writers' jobs easier: The JVM author doesn't have to make sure to recognize that instruction sequence before it gets mangled beyond recognition, and the X->bytecode compiler can rest assured that their bytecode is either invalid or actually optimized, never correct-but-stack-overflowing. – Feb 04 '15 at 16:57call something; return;would only be equivalent to a tail call if the thing that is called never asks for a stack trace; if the method in question is virtual or calls a virtual method, the JVM will have no way of knowing whether it could inquire about the stack. – supercat Feb 04 '15 at 21:03