On Nov 11, 2004, at 9:44 AM, Michael Walter wrote:
On Thu, 11 Nov 2004 12:30:16 -0500, Dan Sugalski <[EMAIL PROTECTED]> wrote:Tail calls should be explicit, compile-time things. Otherwise we're going to run afoul of traceback requirements and suchlike things
Nah, that's just the difference between running optimized and unoptimized. Actually, with a tailcall op that's effectively a hint, it would be ideal to have 3 run modes: a "just obey the hints" mode (for those that trust their compiler), a "never do a tail call" mode (for debugging purposes), and a "do tail calls whenever possible" mode (independent of whether the tailcall op was used). Not sure if those are run modes or assembler (optimizer) modes, though.
Besides, it's a lot easier in general for a language compiler to decide when a tail call's in order than it is for us.
I think it's pretty straightforward to tell, at least at the PIR level. Even at the pasm level, the only requirement is that there's effectively no code between a call from foo to bar, and a return from foo. It's a pure optimization--good fodder for an optimizer.
Even further, it's necessary for some languages (Scheme)/paradigms (loop by recursion) that a "tailcall" is not just a hint but mandatory.
I think that actually doesn't matter. Even in the case where we think we can't do a full tail call optimization (because of a continuation that's been taken), we can still actually remove the calling frame from the call stack--we just can't immediately re-use the register frame. That satisfies the Scheme requirement, I would think. You can still do unbounded recursion, just that GC may need to run to clean up call frames.
Leo said:
$ time parrot -j fact.imc 10000 # [1] maximum recursion depth exceeded
I'd think that long-term our max recursion depth limit should only apply to net frame depth--tail calls shouldn't increase the count. (Probably we'd need 2 counts--net depth and logical depth.)
JEff