> On Sep 29, 2014, at 12:19 PM, Steve Fink <[email protected]> wrote:
> 
>> On 09/29/2014 09:14 AM, Sam Tobin-Hochstadt wrote:
>>> On Mon, Sep 29, 2014 at 10:55 AM, John Lenz <[email protected]> wrote:
>>> I really have no idea what the behavior should be in the faces of optimized
>>> tail calls (which is must broader than simply self recursive methods that
>>> can be rewritten as a loop).   I've seen various suggestions (a capped call
>>> history) but I'm curious how efficient functional languages deal with this.
>> Different functional languages do a variety of things here:
>> 
>> - simply show the current stack, without the functions that made tail
>> calls (this is probably the most common)
>> - have a bounded buffer for stack traces
>> - implement tail calls via a trampoline; this has the side-effect that
>> the stack has "recent" tail calls in it already
>> 
>> I'm sure there are other choices here that people have made.
> 
> "Stack traces" are really an overload of (at least?) 3 different concepts:
> 
> 1. A record of how execution reached the current state. What debuggers
> want, mostly.
> 2. The continuation from this point on - what function will be returned
> to when the current function returns normally, recursively up the call
> chain.
> 3. A description of the actual state of the stack.
> 
> In all of these, the semantics of the youngest frame are different from
> all other frames in the stack trace.
> 
> For #2, thrown exceptions make the implied continuation ordering a lie,
> or at least a little more nuanced. You sort of want to see what frames
> will catch exceptions. (But that's not a trivial determination if you
> have some "native" frames mixed in there, with arbitrary logic for
> determining whether to catch or propagate an exception. Even JS frames
> may re-throw.)
> 
> Inlined functions may cause gaps in #1 and #2, unless the implementation
> takes pains to fill them in with dummy frames (in which case it's not
> really #3 anymore.)

AFAICT, production compilers already take pains to ensure that they leave 
behind sufficient meta-data for the runtime to fill in the missing stack frames 
whenever inlining has happened. This is certainly true in JSC. Crucially, the 
infrastructure to do this is also needed for other random stuff and it imposes 
zero overhead. 

So let's not compare this to inlining. 

-Filip

> 
> Unless the implementation plays games, tail calls can make #1 lie as
> well. You really called f(), but it doesn't appear because its frame was
> used for executing g() before pushing the remaining frames on your
> stack. Tail calls don't really muck with #2 afaict.
> 
> All three meanings are legitimate things to want, and all of them
> require some implementation effort. Even #3 is tricky with a JIT
> involved. And I'm not even considering floating generator frames, which
> may not fit into a linear structure at all. Or when users want "long
> stacks" for callbacks, where the stack in effect when a callback was set
> is relevant.
> 
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to