conts, handlers, and liveness

Stephen Weeks MLton@sourcelight.com
Wed, 18 Jul 2001 11:07:39 -0700


> > I believe that this is introducing bogus flow.  If the block isCont (i.e.,
> > is the continuation of a non-tail call), then the block should do nothing
> > but adjust the stack top (not actually added until codegen), maybe do a
> > limit check, and then do a jump to the actual continuation (i.e., the
> > continuation that appears in the .cps).  If the actual continuation
> > raises, then it will do a jump to the handler block and the flow edge will
> > be added by the Raise case of the transfer.  With this edge, I'm seeing
> > that everything live down to the handler is also live at the
> > continuation, even though the actual continuation does not raise.

I believe that is the correct behavior. 

> The other change that needs to happen is that at the Call case of the
> transfer, if the handler stack is nonempty, then there is an edge from the
> block to the handler block.

This is not good enough.  The problem is that what's live in the handler really
is live in the continuation (at least while the nontail call is going on).
Consider the following.

fun g (): int = ...
fun f () =
   let
      val x: int = ...
   in g () handle _ => x
   end
      
If there is a garbage collection while g() is evaluating then x needs to live
across that collection even though it is not in the contuation, it is only in
the handler continuation.

Of course, once g has returned then x is no longer live.  Thus there is a
distinction between what's live in the stack frame and what's live at the
beginning of the cont.  That distinction is not currently made by live.fun.  I
would be happy to see it be made, by adding an extra field to the result of
Live.live called liveBeginCont or something like that.  The distinction is
already potentially there in allocate-registers, and so shouldn't cause any
other changes.