new register allocator and calling convention

Stephen Weeks sweeks@wasabi.epr.com
Fri, 3 Dec 1999 10:57:51 -0800 (PST)


>  (1) I assume that the reason why you moved stacks onto
> the heap would be to support multiple stacks, one for
> each thread.  Of course, the alternative would have been
> to still retain one stack, marshalling it out to the heap
> whenever a context-switch occurs.  Was this option discarded
> for a particular reason?

Yes.  Thread switch would be way too expensive if you had to copy the
entire stack.

Just to be clear, the memory for the stack is on the heap but it is
still used like a stack.  That is push'es and pop's still side effect
the data structure.  This is not NJ-style stack frame allocation.

>  (2) Your rule on where stacks go implies that a variable 
> declared outside a loop header, but used inside will go into
> a stack slot, correct?  Doesn't this seem overly restrictive?
> (Although, I can't think of any easy way offhand to avoid this.)

Yes.  Yes.  In fact, it is worse.  It means that all the formal
parameters of the loop (i.e. the loop variables) go in stack slots.
This may be death on other machines, but as you see, it's ok on X86.

>  (3) Is your idea to express threads just using call/cc, or are
> you thinking of introducing a new primitive thread type?

Threads are a primitive type.  Callcc is implemented in terms of
threads.  Here is the implementation.

--------------------------------------------------------------------------------

structure Cont: CONT =
struct

structure Thread = Thread

type 'a cont = 'a -> unit
   
fun 'a callcc(f: 'a cont -> 'a): 'a =
   let
      val r: 'a option ref = ref NONE
      val () = Thread.copyCurrent()
   in case !r of
      NONE => let val t = Thread.saved()
	      in f(fn v => (r := SOME v
			    ; Thread.switchTo(Thread.copy t)))
	      end
    | SOME v => (r := NONE (* for space safety *)
		 ; Thread.clearSaved()
		 ; v)
   end

exception ThrowBug
fun ('a, 'b) throw(k: 'a cont) (v: 'a): 'b = (k v; raise ThrowBug)
   
end