I have never quite understood the reason (or excuse) for not supporting tail call optimization in environments that support GC. Why is it an issue at all? If a function has nothing left to do, its activation record ought to be simply reclaimable. Why do the .NET IL and LLVM require an explicit 'tail' annotation, and why doesn't Java just support it out of the box?

The ability to debug using a stacktrace is a rather weak argument. Other than that, I can see that varargs would pose a problem in C, but surely not in Java/.NET. What am I missing?