File:  [Research Unix] / researchv10no / cmd / sml / src / cps / closure.sml
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Norman

(* Copyright 1989 by AT&T Bell Laboratories *)
signature CLOSURE =
  sig
    val closeCPS : CPS.function * (CPS.lvar -> bool)
				 * (int * int * CPS.cexp -> CPS.cexp) ->
			CPS.function * (CPS.lvar -> bool) * (CPS.lvar -> bool)
  end

functor Closure(val maxfree : int) : CLOSURE =
struct

open CPS Access Profile SortedList
fun partition f l = fold (fn (e,(a,b)) => if f e then (e::a,b) else (a,e::b))
			 l ([],[])
fun sublist test =
  let fun subl(a::r) = if test a then a::(subl r) else subl r
        | subl [] = []
  in  subl
  end
local val save = (!saveLvarNames before saveLvarNames := true)
      val closure = namedLvar(Symbol.symbol "closure")
in    val closureLvar = (saveLvarNames := save; fn () => dupLvar closure)
end
val error = ErrorMsg.impossible
datatype object = Value
		| Function of {label:lvar,free:lvar list}
		| Closure of {functions : (lvar * lvar) list,
			      contents : (lvar * object) list,
			      offset : int,
			      stamp : lvar}
datatype env = Env of (lvar * object) list
datatype access = Direct
		| Path of (lvar * object * accesspath)

fun mkClosure(functions,contents) =
     Closure{functions=functions,contents=contents,
	     offset=0,stamp=mkLvar()}
val env0 = Env []
fun augment(m,Env e) = Env (m::e)

val pr = output std_out
val vp = pr o Access.lvarName
fun plist p l = (app (fn v => (pr " "; p v)) l; pr "\n")
val ilist = plist vp
fun printEnv(Env e) =
  let fun ip i = pr(Integer.makestring i)
      fun sp() = pr " "
      val tlist = plist (fn (a,b) => (vp a; pr "/L"; Integer.print b))
      fun p(indent,l,seen) =
	let fun v(true,(vl,Value)::tl) = (vp vl; sp(); v(true,tl))
	      | v(false,(vl,Value)::tl) = (indent(); vp vl; sp(); v(true,tl))
	      | v(nl,_::tl) = v(nl,tl)
	      | v(true,[]) =  pr "\n"
	      | v(false,[]) = ()
	    fun f(true,(v,Function{label,...})::tl) =
			(vp v; pr "/k"; vp label; sp(); f(true,tl))
	      | f(false,(v,Function{label,...})::tl) =
			(indent(); vp v; pr "/k"; vp label; sp(); f(true,tl))
	      | f(nl,_::tl) = f(nl,tl)
	      | f(true,[]) =  pr "\n"
	      | f(false,[]) = ()
	    fun c(v,Closure{functions,contents,offset,stamp}) =
	       (indent(); pr "Closure "; vp v; pr "/"; ip stamp;
		pr " @"; ip offset;
		if member seen stamp
		then pr "(seen)\n"
		else (pr ":\n";
		      case functions of
		        [] => ()
		      | _ => (indent(); pr "  Funs:"; tlist functions; ());
		      p(fn() => (indent();pr "  "),contents,enter(stamp,seen))))
	      | c _ = ()
	in v(false,l); f(false,l); app c l
	end
  in  p(fn () => (),e,[])
  end

(* "Alpha conversion": the closure converter introduces duplicate bindings
   at function arguments (the free variables of known functions) and at
   SELECT's and OFFSET's from closures.  This function restores unique
   bindings, and also eliminates OFFSET's of 0 (which are introduced as
   a side effect of trying to improve lazy display).  It assumes that a
   FIX has no free variables. *)
fun unrebind ce =
let fun rename rebind v =
      let fun f [] = v
	    | f ((w:int,v')::t) = if v=w then v' else f t
      in  f rebind
      end
    fun f (l,args,b) =
      let val (args',rebind') = fold (fn(v,(args',rebind')) =>
					let val v' = dupLvar v
					in  (v'::args',(v,v')::rebind')
					end)
				     args ([],[])
      in  (l,args',g(b,rebind'))
      end
    and g(ce,rebind) =
      let val rename = rename rebind
	  val rec h =
	       fn RECORD(vl,w,e) =>
		    RECORD(map (fn(v,p) => (rename v,p)) vl,w,h e)
		| OFFSET(0,v,w,e) => g(e,(w,rename v)::rebind)
		| OFFSET(i,v,w,e) =>
			let val w' = dupLvar w
			in  OFFSET(i,rename v,w',g(e,(w,w')::rebind))
			end
		| SELECT(i,v,w,e as APP(x,args)) =>
			let val w' = dupLvar w
			in  if w=x
			    then SELECT(i,rename v,w',APP(w',map rename args))
			    else SELECT(i,rename v,w',g(e,(w,w')::rebind))
			end
		| SELECT(i,v,w,e) =>
			let val w' = dupLvar w
			in  SELECT(i,rename v,w',g(e,(w,w')::rebind))
			end
		| APP(f,vl) => APP(f,map rename vl)
			(* HACK: f is always a label or from a SELECT, so
			   we never need rename. *)
		| FIX(l,e) => FIX(map f l,h e)
		| SWITCH(v,el) => SWITCH(rename v,map h el)
		| PRIMOP(i,vl,wl,el) => PRIMOP(i,map rename vl,wl,map h el)
      in  h ce
      end
in  g(ce,[])
end

(* TEMPORARY DEBUGGING STUFF *)
val alphac = System.Control.CG.alphac
val comment = ref false (* System.Control.CG.comment *)
val unrebind = fn x => if !alphac then unrebind x else x
fun COMMENT f = if !comment then (f(); ()) else ()

fun formap f =
  let fun iter([],_) = []
	| iter(hd::tl,i) = f(hd,i)::iter(tl,i+1)
  in  iter o (fn l => (l,0))
  end

fun select(i,Closure{functions,contents,offset,stamp}) =
     (let val index = offset + i - length functions
      in  (#2 o nth)(contents,index)
      end handle Nth => error "bad select in cps/closure")
  | select(_,Value) = Value
  | select(_,Function _) = error "select from knownfunc in cps/closure"
fun offset(_,Value,_,_) = error "offset from value in cps/closure"
  | offset(_,Function _,_,_) = error "offset from knownfunc in cps/closure"
  | offset(i,Closure{functions,contents,offset,stamp},v,env) =
      augment((v,Closure{functions=functions,contents=contents,
			 offset=offset+i,stamp=stamp}),env)
(* Merge the free variables of recursive register functions, and put
   free variables into the closure if there are not enough registers.
   A function which needs the closure for any reason (for example, to
   call and escaping function of the fix) will always put all its free
   variables in the closure - you can't use the closure and some registers
   for free variables. *)
type info = {v:lvar,fns:lvar list,other:lvar list,args:lvar list,
	  body:cexp,label:lvar,env:env,callc:bool}
fun regf bindings =
let fun pack m =
      let fun getother w =
	    let fun g(({v,...}:info,other,_)::tl) = if v=w then other
			else g tl
                      | g [] = ErrorMsg.impossible "[] 4849 in cps/closure"
	    in  g m
	    end
	  fun getcallc w =
	    let fun g(({v,...}:info,_,callc)::tl) = if v=w then callc
			else g tl
                      | g [] = ErrorMsg.impossible "[] 4848 in cps/closure"
	    in  g m
	    end
	  fun f (x as {args,fns,...}:info, other, callc) =
		  (x,
		   foldmerge(other :: map getother fns),
		   callc orelse
		   (length args + length other >= maxfree andalso
		    length other > 1) orelse
		   exists getcallc fns)
	  val m' = map f m
      in  if exists (fn ({callc,...}:info,_,callc') => callc <> callc') m'
	  then regf (map (fn ({v,fns,other,args,body,label,callc,env},_,cc') =>
				{v=v,fns=fns,other=other,args=args,body=body,
				 label=label,env=env,callc=cc'}) m')
	  else if exists (fn x=>x) 
			(List2.map2 (fn ((_,other,_),(_,other',_)) => 
				length other <> length other')
			      (m,m'))
	       then pack m'
	  else fold (fn(({v,args,body,label,env,...},other,callc),(b,f)) =>
			if callc then 
			({v=v,args=args,body=body,label=label,env=env,
			 free=[],callc=callc}::b,merge(other,f))
			else
			({v=v,args=args,body=body,label=label,env=env,
			 free=other,callc=callc}::b,f))
		     m' ([],[])
      end
in  pack (map (fn (x as {other,callc,...}) => (x,other,callc)) bindings)
end


fun compute_escapes ce =
let val s = Intset.new()
    val use = Intset.add s
    val rec g =
      fn RECORD (vl,_,e) => (app (use o #1) vl; g e)
       | SELECT (_,v,_,e) => g e
       | OFFSET (_,v,_,e) => g e
       | APP(f,vl) => (app use vl)
       | FIX(l, e) => (app (g o #3) l; g e)
       | SWITCH(v,el) => app g el
       | PRIMOP(_,vl,_,el) => (app use vl; app g el)
 in g ce; Intset.mem s
end


fun closeCPS((f,vl,ce),constant,prof) =
let
val escapes = compute_escapes ce
val unknownset = Intset.new()
val knownset = Intset.new()
val markknown = Intset.add knownset
val markunknown = Intset.add unknownset
val freevars = FreeMap.freemapClose(ce,constant)
datatype looking = Found of object * access
		 | Pending of (lvar * object) list
exception Lookup
(* Closures may be duplicated in the 'tree'; don't look at them twice. *)
fun lookup(env as Env e,target) =
    let fun bfs([],[],seen) = raise Lookup
	  | bfs([],next,seen) = bfs(next,[],seen)
	  | bfs((Closure{functions,contents,offset,stamp},p)::m,next,seen) =
	    let fun element i =
		 let val p' = i-offset
		 in  if p'<0
		     then (print "\nNegSel target for ";
			   print(Access.lvarName target); print " in\n";
			   printEnv env)
		     else ();
		     p'::p
		 end
		fun cnt([],i,next,seen) = bfs(m,next,seen)
		  | cnt((v,c as Closure{stamp,...})::t,i,next,seen) =
		    if target=v
		    then (element i,0,c)
		    else cnt(t,i+1,if member seen stamp
				   then next
				   else (c,element i)::next,seen)
		  | cnt((v,Value)::t,i,next,seen) =
		    if target=v
		    then (element i,0,Value)
		    else cnt(t,i+1,next,seen)
		  | cnt((_,Function _)::_,_,next,seen) =
		    error "Function in closure in lookup"
		fun fns([],i,seen) = cnt(contents,i,next,seen)
		  | fns((v,l)::t,i,seen) =
			if target=v
			then (p,i-offset,Closure{functions=functions,
						 contents=contents,
						 stamp=stamp,
						 offset = i})
			else fns(t,i+1,seen)
	    in if member seen stamp
	       then bfs(m,next,seen)
	       else fns(functions,0,enter(stamp,seen))
	    end
	fun search closures =
	    let val (p,off,r) =
		    bfs(formap(fn((v,c),i) => (c,[i])) closures,[],[])
		val (n::t) = rev p
		fun f [] = OFFp off | f(h::t) = SELp(h,f t)
		val (v,c) = nth(closures,n)
	    in  (r,Path(v,c,f t))
	    end
	fun look [] = raise Lookup
	  | look ((v,c as Closure{functions,contents,stamp,offset})::tl) =
	    if target=v then Found(c,Direct)
	    else let fun f(_,[]) = (false,0)
		       | f(i,(v,_)::t) = if target=v then (true,i) else f(i+1,t)
	             val (foundit,n) = f(0,functions)
		     (* this junk is a hack needed for linked closures *)
	         in if foundit
		    then Found(Closure{functions=functions,
			 	       contents=contents,
				       stamp=stamp,
				       offset=n},
		               Path(v,c,OFFp(n-offset)))
		    else ((case look tl of
		             f as Found _ => f
			   | Pending l => Pending ((v,c)::l))
			  handle Lookup => Pending [(v,c)])
		 end
	  | look ((v,f as Function _)::tl) =
	    if target=v then Found(f,Direct) else look tl
	  | look ((v,Value)::tl) =
	    if target=v then Found(Value,Direct) else look tl
      in if constant target
	 then (Value,Direct)
	 else (case look e of
	         Found f => f
	       | Pending closures => search closures)
	 handle Lookup =>
		(print "**LOOKUP: Can't find "; vp target;
		 print " in environment:\n";
		 printEnv env;
		 raise Lookup)
      end

fun flat(env,free) =
 map (fn v => let val (obj,_) = lookup(env,v)
	      in  case obj of Function _ => pr "weird\n"
		     | _ => ();
		  (v,obj)
	      end) free
fun link(env,free) =
  let val contents = map (fn v => let val (obj,acc) = lookup(env,v)
				  in  case obj of Function _ => pr "weird\n"
					| _ => ();
				      (v,obj,acc)
				  end)
			 free
      val direct = fold (fn ((v,obj,Direct),t) => (v,obj)::t
			  | ((v,obj,Path(_,_,OFFp _)),t) => (v,obj)::t
			  | (_,t) => t) contents []
  in  if length direct = length contents then direct
	else case env of Env l =>
		let fun getc ((m as (v,Closure _))::_) = m
		      | getc (_::tl) = getc tl
		      | getc [] = error "No closure in closureStrat"
		    val c = getc (rev l)
		in  c::direct
		end
  end

fun closureStrategy(bindings,free,env) = (* temporary *)
  let val m = case !CGoptions.closureStrategy
		of 3 => link(env,free)
		 | 2 => link(env,free)
		 | _ => flat(env,free)
  in  mkClosure(map (fn(v,l,_,_) => (v,l)) bindings,m)
  end

(* Take a free variable list and replace knownfuncs by their
   free variables.  A new environment with the knownfunc mappings is
   returned.  Function aliasing could be added here. *)
fun funcAnalysis(free,env) =
  fold (fn (v,(l,env')) =>
	let val(obj,_) = lookup(env,v)
	in  case obj
	      of Function{free,...} => (merge(free,l),augment((v,obj),env'))
	       | _ => (enter(v,l),env')
	end)
	free ([],env0)
(* Function aliasing, separate for now, but always called after funcAnalysis. *)
fun sameClosureOpt(free,env) =
case !CGoptions.closureStrategy
  of 0 => free (* flat without aliasing *)
   | 2 => free (* linked without aliasing *)
   | _ => (* all others have aliasing *)
  let val mapping = map (fn v => let val (obj,_) = lookup(env,v)
				 in  (v,obj)
				 end) free
      fun uniq ((hd as (v,Closure{stamp,...}))::tl) =
	let val m' = uniq tl
	in  if exists (fn (_,Closure{stamp=stamp',...}) => stamp=stamp'
			| _ => false) m'
	    then m' else hd::m'
	end
	| uniq (hd::tl) = hd::uniq tl
	| uniq [] = []
  in  map #1 (uniq mapping)
  end

fun fixAccess(args,env) =
let
fun access(rootvar,(env,header)) =
  let val rec follow =
	fn (_,Value,_,_,_) => error "fixAccess Value in cps/closure"
	 | (v,cl,env,OFFp off,h) =>
		  (offset(off,cl,rootvar,env),
		   h o (fn ce => OFFSET(off,v,rootvar,ce)))
	 | (v,cl,env,SELp(i,OFFp 0),h) =>
		  (augment((rootvar,select(i,cl)),env),
		   h o (fn ce => SELECT(i,v,rootvar,ce)))
	 | (v,cl,env,SELp(i,p),h) =>
		  let val w = mkLvar()
		      val cl = select(i,cl)
		      val env = augment((w,cl),env)
			(* turn off lazy display here *)
		  in  follow(w,cl,env,p,h o (fn ce => SELECT(i,v,w,ce)))
		  end
      val (obj,acc) = lookup(env,rootvar)
  in  case acc
	of Direct => (env,header)
	 | Path(start,cl,path) =>
	     let val a as (env,header) = follow(start,cl,env,path,header)
	     in  if not(!CGoptions.profile) then a
		 else let val cost = lenp path
			  val h = if cost=0 then fn x => x else
			      if cost < LINKSLOTS
			      then fn ce => prof(LINKS+cost,1,ce)
			      else fn ce => prof(LINKS,1,prof(LINKOVFL,cost,ce))
		      in  (env,h o header)
		      end
	     end
  end
in  fold access args (env,fn x => x)
end

fun recordEl(l,env) =
if not(!CGoptions.profile)
then (map (fn (v,p) => 
        case lookup(env,v)
	  of (_,Direct) => (v,p)
	   | (_,Path(start,_,path)) => (start,combinepaths(path,p))) l,
      fn x => x)
else fold (fn ((v,p),(l,h)) =>
	  let val (_,acc) = lookup(env,v)
	      val (m,cost) = case acc of Direct => ((v,p),0)
				| Path(start,_,path) =>
					((start,combinepaths(path,p)),lenp path)
	      val h' = if cost=0 then fn x => x else
		      if cost < LINKSLOTS then fn ce => prof(LINKS+cost,1,ce)
		      else fn ce => prof(LINKS,1,prof(LINKOVFL,cost,ce))
	  in  (m::l,h o h')
 	 end) l ([],fn x => x)


fun makenv(env,bindings: (lvar * lvar list * cexp) list) =
let
val _ = COMMENT(fn() => (pr "Beginning makenv.\nInitial environment:\n";
			 printEnv env; pr "\n"))

(* A debugging version of freevars *)
fun fpr(v,free) = COMMENT(fn() => (pr "Free in "; vp v; pr ":"; ilist free))
val freevars =
  (fn v => let val free = freevars v
	   in  fpr(v,free);
	       free
	   end)

(* Separate functions into those that escape and those which are knownfuncs *)
val (escape,known) = partition (escapes o #1) bindings
val escaping = uniq(map #1 escape)

val _ = COMMENT(fn() => pr "Knownfuncs...\n")
(* Mark each known function of the FIX with its free variables. *)
val known
	= map (fn(v,args,body) => {v=v,free=freevars v,args=args,body=body}) known

(* For each known function of the FIX, remove any escaping functions of the
   FIX from its free list and mark that the function requires the closure. *)
val known
	= map (fn {v,free,args,body} =>
		let val free' = difference(free,escaping)
		in  {v=v,free=free',
		     callc=(free<>free'),
		     args=args,body=body}
		end) known

(* Separate known functions defined in this FIX from other free variables. *)
local val knownlvars = map #v known
in    val knownlvar = fn v => exists (fn w => v=w) knownlvars
end
val known
	= map (fn {v,free,callc,args,body} =>
		let val (fns,other) = partition knownlvar free
    		in  {v=v,fns=fns,other=other,callc=callc,args=args,body=body}
		end)
	      known

(* Replace knownfuncs defined in other FIX'es by their free variables, and
   escaping functions defined in other FIX'es by their closures.  Label
   each knownfunc. *)
val known
	= map (fn{v,fns,other,callc,args,body} =>
		let val (other,env') = funcAnalysis(other,env)
		    val other = sameClosureOpt(other,env)
		in  {v=v,fns=fns,other=other,callc=callc,args=args,body=body,
		     env=env',label=dupLvar v}
		end)
	      known

(* Merge free variables of knownfuncs that call each other. *)
(* Look at the number of free variables and arguments to each known function
   to be defined.  The cps converter ensures that there are enough registers
   to hold the arguments and leaves one register free for the free variables,
   if any.  Therefore some free variables may have to be spilled into the closure,
   and these must be collected. *)
val (known,collected)
	= regf known

val _ = COMMENT(fn() => pr "Escaping functions...\n")
(* Get the combined list of the free variables of all the escaping functions
   of the FIX. *)
val free : lvar list = remove(escaping, foldmerge(map (freevars o #1) escape))
val _ = COMMENT(fn() => (pr "AAA"; ilist free))

(* Replace knownfuncs defined in this FIX with their free variables. *)
val free : lvar list
	= let val (fns,other) = partition knownlvar free
	  in  fold (fn ({v,free,...},b) =>
			if exists (fn w => v=w) fns
			then merge(free,b)
			else b) known other
	  end
val _ = COMMENT(fn() => (pr "BBB"; ilist free))

val free = merge(collected,free)
val _ = COMMENT(fn() => (pr "CCC"; ilist free))


(* Replace knownfuncs defined elsewhere with their free variables, and escaping
   functions defined elsewhere with their closures.  The function environment
   which tells that certain free variables are known functions and gives their
   free variables must be kept for applications of the functions in the bodies
   of the escaping functions of the FIX. *)
val (free,functionEnv) : lvar list * env (* only need function mapping here *)
	= let val (free,env') = funcAnalysis(free,env)
	      val free = sameClosureOpt(free,env)
	  in  (free,env')
	  end
val _ = COMMENT(fn() => (pr "DDD"; ilist free))


(* Given the functions to be defined in the closure (escape), the free variables
   which should be contained in the closure (free), and their current locations
   (env), decide on a closure representation. *)
val escape = map (fn(v,args,body) => (v,dupLvar v,args,body)) escape
val closure = closureStrategy(escape,free,env)
val _ = COMMENT(fn() =>
		let val Closure{contents,...} = closure
		in  pr "EEE"; ilist (map #1 contents)
		end)

fun mkFnMap c : (lvar * object) list
	= map (fn{v,free,callc,label,...} =>
		if callc then (v,Function{label=label,free=enter(c,free)})
		else (v,Function{label=label,free=free}))
	      known

(* Final construction of the environment for each standard function. *)
val closureFrags : (lvar * lvar list * cexp * env) list
	= case escape of [] => []
	| ((v,_,_,_)::_) =>
	  let val env = fold augment (mkFnMap v) functionEnv
	      fun f ((v,l,args,body),i) =
		let val cname = closureLvar()
		    val env = fold (fn (v,b) => augment((v,Value),b))
				args (offset(i,closure,cname,env))
		    val _ = COMMENT(fn () => (print "\nEnvironment at escaping ";
					      vp v; print ":\n";
					      printEnv env))
		in  markunknown l; (l,cname::args,body,env)
		end
	  in  formap f escape
	  end


(* Final construction of the environment for each known function. *)
val cname = closureLvar()
val fnMap = mkFnMap cname
val registerFrags : (lvar * lvar list * cexp * env) list
	= map (fn{v,free,callc,args,body,env=env',label} =>
		let val env =
		      fold (fn (v,env') =>
				case lookup(env,v)
				  of (Function _,_) => error "cps/closure.223"
				   | (obj,_) => augment((v,obj),env'))
			   free
			   (fold (fn (v,b) => augment((v,Value),b))
				 args
				 (fold augment fnMap
				    (if callc
				     then (inc System.Control.CG.knowncl;
					   augment((cname,closure),env'))
			  	     else env')))
		    val _ = COMMENT(fn () => (print "\nEnvironment at known ";
					      vp v; print ":\n";
					      printEnv env))
		    val args = args @ free @ if callc then [cname] else []
		in  markknown label; (label,args,body,env)
		end)
	      known


val contents = let val Closure{functions,contents,...} = closure
	       in  map #2 functions @ map #1 contents
	       end


(* Add profiling code if flag is on. *)
fun mkrexp(contents,cname) =
  if not(!CGoptions.profile) then fn ce => RECORD(contents,cname,ce)
  else let val len = length contents
	   val (closures,slots,ovfl) =
		fold (fn((v,[_],_),b as (closures,_,_)) =>
			if closures=CLOSURES then b
			else if escapes v
			     then (CCLOSURES,CCLOSURESLOTS,CCLOSUREOVFL)
			     else b
		      |((v,args,_),b as (closures,_,_)) =>
			if closures=CLOSURES then b
			else if escapes v
			     then (CLOSURES,CLOSURESLOTS,CLOSUREOVFL)
			     else b)
		     bindings (KCLOSURES,KCLOSURESLOTS,KCLOSUREOVFL)
       in  if len < slots
	   then fn ce => prof(closures+len,1,RECORD(contents,cname,ce))
	   else fn ce => prof(closures,1,
			      prof(ovfl,len,RECORD(contents,cname,ce)))
       end


in  case contents
      of [] => (fn ce => ce,registerFrags,fold augment fnMap env)
       | _ =>
	  let val frags = closureFrags@registerFrags
	      val env = fold (fn(a,b) => augment((#1 a,Value),b)) closureFrags env
	      val (contents,header) = recordEl(recordpath contents,env)
	      val env = fold augment fnMap env
	      val env = augment((cname,closure),env)
	      val _ = COMMENT(fn () => (print "\nEnvironment after FIX:\n";
					printEnv env))
	  in  (header o mkrexp(contents,cname),frags,env)
	  end
     before COMMENT(fn() => pr "makenv done.\n\n")
end


val env1 = fold (fn(v,b) => augment((v,Value),b)) (f::vl) env0
fun close(ce,env) =
  case ce
    of FIX(bindings,b) =>
       (let val (header,frags,env') = makenv(env,bindings)
	in  FIX(map (fn(v,args,a,env) =>
				(v,args,close(a,env))) frags,
		header(close(b,env')))
	end handle Lookup => APP(0,[]))
     | APP(f,args) =>
	let val(obj,_) = lookup(env,f)
handle Lookup => (print "LOOKUP FAILS in close(APP)\n"; (Value,Direct))
	in  case obj
	      of Closure{functions,offset,...} =>
		   let val (_,header) = fixAccess(f::args,env)
		       val (_,label) = nth(functions,offset)
		       val call = APP(label,f::args)
		   in  if !CGoptions.profile
		       then header(prof(STDKCALLS,1,call))
		       else header call
		   end
	       | Function{label,free} =>
		   let val args' = args@free
		       val (_,header) = fixAccess(args',env)
		       val call = APP(label,args')
		   in  if !CGoptions.profile
		       then header(prof(KNOWNCALLS,1,call))
		       else header call
		   end
	       | Value =>
		   let val l = mkLvar()
		       val (_,header) = fixAccess(f::args,env)
		       val call = SELECT(0,f,l,APP(l,f::args))
		   in  if !CGoptions.profile
		       then case args
			      of [_] => header(prof(CNTCALLS,1,call))
			       | _ =>  header(prof(STDCALLS,1,call))
		       else header call
		   end
	end
     | SWITCH(v,l) =>
	let val (env',header) = fixAccess([v],env)
	in  header (SWITCH(v,map (fn c => close(c,env')) l))
	end
     | RECORD(l,v,c) =>
	let val (l,header) = recordEl(l,env)
	    val ce = close(c,augment((v,Value),env))
	    val len = length l
	in  header(
	    if not(!CGoptions.profile) then RECORD(l,v,ce)
	    else if len < RECORDSLOTS
	    then prof(RECORDS+len,1,RECORD(l,v,ce))
	    else prof(RECORDS,1,prof(RECORDOVFL,len,RECORD(l,v,ce))))
	end
     | SELECT(i,v,w,c) =>
	let val (env,header) = fixAccess([v],env)
	    val (obj,_) = lookup(env,v)
handle Lookup => (print "LOOKUP FAILS in close(SELECT)\n"; (Value,Direct))
	in  header(SELECT(i,v,w,close(c,augment((w,select(i,obj)),env))))
	end
     | OFFSET(i,v,w,c) => error "OFFSET in cps/closure.sml!"
     | PRIMOP(i,args,rets,l) =>
	let val (env,header) = fixAccess(args,env)
	    val env = fold (fn (v,b) => augment((v,Value),b)) rets env
	in  header (PRIMOP(i,args,rets,map (fn c => close(c,env)) l))
	end
in  ((mkLvar(),f::vl,unrebind(close(ce,env1))),
     Intset.mem knownset,Intset.mem unknownset)
end

end (* structure Closure *)



unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.