

Tail Call Improvements in .NET Framework 4 - budu
http://extended64.com/blogs/news/archive/2009/05/10/tail-call-improvements-in-net-framework-4.aspx

======
CWuestefeld
_on x64 you should see shorter call stacks in optimized code because the JIT
generated more tail calls (don’t worry this optimization is turned off for
debug code)_

I think it used to be that there was little perf difference between DEBUG and
RELEASE builds, so for simplicity, with internal apps we always just build to
DEBUG.

The above quote suggests that these days, they really are doing worthwhile
optimizations in RELEASE builds. Does anybody know more about that?

~~~
mikedouglas
This sounds like a bad idea.

TCO is not just a perf difference. Once you add it to a language, you've
changed the semantics. The same piece of code will throw a
StackOverflowException in DEBUG mode, yet functional perfectly in RELEASE.
Scheme's spec requires TCO for this very reason.

~~~
Gobiner
If you think a feature that could potentially behave differently in RELEASE
and DEBUG modes is problematic, you'll want to avoid floats and doubles in
.NET. Runtime optimizations that do calculations in the processor's 80-bit FPU
can alter the results of float/double calculations. My personal example:
[http://stackoverflow.com/questions/2225503/clr-jit-
optimizat...](http://stackoverflow.com/questions/2225503/clr-jit-
optimizations-violates-causality)

~~~
pcarmichael
If you want identical results regardless of optimization level or machine
characteristics, you should really be using fixed-point instead.

------
rubyrescue
_However the stack space is ‘recycled’ such that if you have a tail recursive
algorithm, the first tail call that isn’t ‘easy’ will erect the TailCallHelper
stack frame, and subsequent non-easy tail calls may need to grow that frame to
accommodate all the arguments. Hopefully once the algorithm has gone through a
full cycle of recursion the TailCallHelper stack frame has grown to the
maximum sized needed by all the non-easy calls involved in the recursion, and
then never grows, and thus prevents a stack overflow._

\- does this mean that it's possible to use TailCallHelper but still not be
able to guarantee no stack overflow?

~~~
amock
Yes, but I don't think that's more true of TailCallHelper than of any function
calls using a stack. This sounds like it's saying that even with tail call
optimization it's possible for the arguments to a function to be too big for
the stack. For example, if the arguments you pass to the recursive function
call are stack allocated and grow each time then each call will increase stack
usage, even though it's reusing the space from the previous call.

------
trezor
If I'm reading this correctly this only applies to the .NET 4 runtime and not
the old .NET 2.0 runtime (also powering .NET 3.0 and 3.5 solutions).

In that case I guess if you are running tail-recursion heavy algorithms on
x64, just recompiling the same old code for the .NET 4 runtime should yield
runtime improvements.

Would be interesting if someone had any actual measurements for this.

~~~
Gobiner
I'm no CLR JIT expert, but I'm not sure you even need to recompile. It sounds
to me that you just need to run your existing tail-calling code on the .NET 4
x64 CLR, presuming your current code has ``tail'' opcodes.

~~~
DougBTX
Appears to require a small amount of magic:
[http://stackoverflow.com/questions/896629/how-to-run-
clr-2-a...](http://stackoverflow.com/questions/896629/how-to-run-
clr-2-application-as-clr-4-application)

------
topbanana
Filed under: BetIWontNoticeAnyDifference

