local refs

Matthew Fluet Matthew Fluet <fluet@CS.Cornell.EDU>
Fri, 7 Dec 2001 15:48:58 -0500 (EST)


> > stored values by using atomicBegin/End.  So, maybe a better
> > correspondence is:
> > 
> > > 	    val copyCurrent: unit -> preThread
> > corresponds to:  (atomicBegin (); copyCurrent () ; saved (); atomicEnd ())
> 
> Yes, this is done in cont.sml.  It is not done in thread.sml because
> the call to copyCurrent there happens before any threads (or signal
> handlers) exist.

That makes sense.

> There is one other issue about the separation that is ringing alarms
> in my brain.  Notice that all ot the uses of Thread.saved immediately
> follow the call to copy or copyCurrent, except for one.  In
> Cont.callcc, the use of Thread.saved is carefully placed down the
> Original branch of the case instead of immediately after the
> Thread.copyCurrent.  I remember moving it down there at some point.
> 
> Aha -- it's there because it only makes sense to call Thread.saved ()
> after the original call to copyCurrent.  When threads/conts return
> there later, a call to Thread.saved doesn't make sense.  What a mess.
> I would think that for later returns, gcState.savedThread would be ==
> 0x1, so it shouldn't matter.  But I have some vague recollection of a
> segfault or assertion failure when the Tread.saved was before the
> branch.

Yeah, it looks like Thread.c will always write over the saved thread.

> Any thoughts on whether it matters or not?  If not, then I would like
> to make the uses of (Thread.copyCurrent (); Thread.saved ()) in
> cont.sml and thread.sml consistent.  Either both calls to Thread.saved
> are before the case or both are down the original branch.

I don't see that it really matters.

> > I think we need "live across a call to a potential Thread_copyCurrent", by
> > which I mean either an actual call to Thread_copyCurrent or a non-tail
> > call to a function that reaches a call to Thread_copyCurrent.
> 
> Agreed.  So we first compute a fixed-point on functions to determine
> whether or not they call Thread_copyCurrent.  Then, backpropagate ref
> uses to determine if they are live at copy points.  All as you
> described before.

Sounds easy enough.  We still need to compute multi-threaded and
multi-used.  Do you think constant propagation would benefit significantly
from redoing the Once pass to have:

val once: Program.t -> {multiThreadedF: Func.t -> bool,
                        multiUsedF: Func.t -> bool,
                        multiThreadedL: Label.t -> bool,
                        multiUsedL: Func.t -> bool}

(or some variant thereof; that type looks ugly to me).  That is, something
that can be shared by both constant prop. and localRef.

Any thoughts about whether or not we should make Thread_copyCurrent a
transfer?