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?