Annotation of researchv10no/cmd/sml/src/cps/closure.sml, revision 1.1.1.1

1.1       root        1: (* Copyright 1989 by AT&T Bell Laboratories *)
                      2: signature CLOSURE =
                      3:   sig
                      4:     val closeCPS : CPS.function * (CPS.lvar -> bool)
                      5:                                 * (int * int * CPS.cexp -> CPS.cexp) ->
                      6:                        CPS.function * (CPS.lvar -> bool) * (CPS.lvar -> bool)
                      7:   end
                      8: 
                      9: functor Closure(val maxfree : int) : CLOSURE =
                     10: struct
                     11: 
                     12: open CPS Access Profile SortedList
                     13: fun partition f l = fold (fn (e,(a,b)) => if f e then (e::a,b) else (a,e::b))
                     14:                         l ([],[])
                     15: fun sublist test =
                     16:   let fun subl(a::r) = if test a then a::(subl r) else subl r
                     17:         | subl [] = []
                     18:   in  subl
                     19:   end
                     20: local val save = (!saveLvarNames before saveLvarNames := true)
                     21:       val closure = namedLvar(Symbol.symbol "closure")
                     22: in    val closureLvar = (saveLvarNames := save; fn () => dupLvar closure)
                     23: end
                     24: val error = ErrorMsg.impossible
                     25: datatype object = Value
                     26:                | Function of {label:lvar,free:lvar list}
                     27:                | Closure of {functions : (lvar * lvar) list,
                     28:                              contents : (lvar * object) list,
                     29:                              offset : int,
                     30:                              stamp : lvar}
                     31: datatype env = Env of (lvar * object) list
                     32: datatype access = Direct
                     33:                | Path of (lvar * object * accesspath)
                     34: 
                     35: fun mkClosure(functions,contents) =
                     36:      Closure{functions=functions,contents=contents,
                     37:             offset=0,stamp=mkLvar()}
                     38: val env0 = Env []
                     39: fun augment(m,Env e) = Env (m::e)
                     40: 
                     41: val pr = output std_out
                     42: val vp = pr o Access.lvarName
                     43: fun plist p l = (app (fn v => (pr " "; p v)) l; pr "\n")
                     44: val ilist = plist vp
                     45: fun printEnv(Env e) =
                     46:   let fun ip i = pr(Integer.makestring i)
                     47:       fun sp() = pr " "
                     48:       val tlist = plist (fn (a,b) => (vp a; pr "/L"; Integer.print b))
                     49:       fun p(indent,l,seen) =
                     50:        let fun v(true,(vl,Value)::tl) = (vp vl; sp(); v(true,tl))
                     51:              | v(false,(vl,Value)::tl) = (indent(); vp vl; sp(); v(true,tl))
                     52:              | v(nl,_::tl) = v(nl,tl)
                     53:              | v(true,[]) =  pr "\n"
                     54:              | v(false,[]) = ()
                     55:            fun f(true,(v,Function{label,...})::tl) =
                     56:                        (vp v; pr "/k"; vp label; sp(); f(true,tl))
                     57:              | f(false,(v,Function{label,...})::tl) =
                     58:                        (indent(); vp v; pr "/k"; vp label; sp(); f(true,tl))
                     59:              | f(nl,_::tl) = f(nl,tl)
                     60:              | f(true,[]) =  pr "\n"
                     61:              | f(false,[]) = ()
                     62:            fun c(v,Closure{functions,contents,offset,stamp}) =
                     63:               (indent(); pr "Closure "; vp v; pr "/"; ip stamp;
                     64:                pr " @"; ip offset;
                     65:                if member seen stamp
                     66:                then pr "(seen)\n"
                     67:                else (pr ":\n";
                     68:                      case functions of
                     69:                        [] => ()
                     70:                      | _ => (indent(); pr "  Funs:"; tlist functions; ());
                     71:                      p(fn() => (indent();pr "  "),contents,enter(stamp,seen))))
                     72:              | c _ = ()
                     73:        in v(false,l); f(false,l); app c l
                     74:        end
                     75:   in  p(fn () => (),e,[])
                     76:   end
                     77: 
                     78: (* "Alpha conversion": the closure converter introduces duplicate bindings
                     79:    at function arguments (the free variables of known functions) and at
                     80:    SELECT's and OFFSET's from closures.  This function restores unique
                     81:    bindings, and also eliminates OFFSET's of 0 (which are introduced as
                     82:    a side effect of trying to improve lazy display).  It assumes that a
                     83:    FIX has no free variables. *)
                     84: fun unrebind ce =
                     85: let fun rename rebind v =
                     86:       let fun f [] = v
                     87:            | f ((w:int,v')::t) = if v=w then v' else f t
                     88:       in  f rebind
                     89:       end
                     90:     fun f (l,args,b) =
                     91:       let val (args',rebind') = fold (fn(v,(args',rebind')) =>
                     92:                                        let val v' = dupLvar v
                     93:                                        in  (v'::args',(v,v')::rebind')
                     94:                                        end)
                     95:                                     args ([],[])
                     96:       in  (l,args',g(b,rebind'))
                     97:       end
                     98:     and g(ce,rebind) =
                     99:       let val rename = rename rebind
                    100:          val rec h =
                    101:               fn RECORD(vl,w,e) =>
                    102:                    RECORD(map (fn(v,p) => (rename v,p)) vl,w,h e)
                    103:                | OFFSET(0,v,w,e) => g(e,(w,rename v)::rebind)
                    104:                | OFFSET(i,v,w,e) =>
                    105:                        let val w' = dupLvar w
                    106:                        in  OFFSET(i,rename v,w',g(e,(w,w')::rebind))
                    107:                        end
                    108:                | SELECT(i,v,w,e as APP(x,args)) =>
                    109:                        let val w' = dupLvar w
                    110:                        in  if w=x
                    111:                            then SELECT(i,rename v,w',APP(w',map rename args))
                    112:                            else SELECT(i,rename v,w',g(e,(w,w')::rebind))
                    113:                        end
                    114:                | SELECT(i,v,w,e) =>
                    115:                        let val w' = dupLvar w
                    116:                        in  SELECT(i,rename v,w',g(e,(w,w')::rebind))
                    117:                        end
                    118:                | APP(f,vl) => APP(f,map rename vl)
                    119:                        (* HACK: f is always a label or from a SELECT, so
                    120:                           we never need rename. *)
                    121:                | FIX(l,e) => FIX(map f l,h e)
                    122:                | SWITCH(v,el) => SWITCH(rename v,map h el)
                    123:                | PRIMOP(i,vl,wl,el) => PRIMOP(i,map rename vl,wl,map h el)
                    124:       in  h ce
                    125:       end
                    126: in  g(ce,[])
                    127: end
                    128: 
                    129: (* TEMPORARY DEBUGGING STUFF *)
                    130: val alphac = System.Control.CG.alphac
                    131: val comment = ref false (* System.Control.CG.comment *)
                    132: val unrebind = fn x => if !alphac then unrebind x else x
                    133: fun COMMENT f = if !comment then (f(); ()) else ()
                    134: 
                    135: fun formap f =
                    136:   let fun iter([],_) = []
                    137:        | iter(hd::tl,i) = f(hd,i)::iter(tl,i+1)
                    138:   in  iter o (fn l => (l,0))
                    139:   end
                    140: 
                    141: fun select(i,Closure{functions,contents,offset,stamp}) =
                    142:      (let val index = offset + i - length functions
                    143:       in  (#2 o nth)(contents,index)
                    144:       end handle Nth => error "bad select in cps/closure")
                    145:   | select(_,Value) = Value
                    146:   | select(_,Function _) = error "select from knownfunc in cps/closure"
                    147: fun offset(_,Value,_,_) = error "offset from value in cps/closure"
                    148:   | offset(_,Function _,_,_) = error "offset from knownfunc in cps/closure"
                    149:   | offset(i,Closure{functions,contents,offset,stamp},v,env) =
                    150:       augment((v,Closure{functions=functions,contents=contents,
                    151:                         offset=offset+i,stamp=stamp}),env)
                    152: (* Merge the free variables of recursive register functions, and put
                    153:    free variables into the closure if there are not enough registers.
                    154:    A function which needs the closure for any reason (for example, to
                    155:    call and escaping function of the fix) will always put all its free
                    156:    variables in the closure - you can't use the closure and some registers
                    157:    for free variables. *)
                    158: type info = {v:lvar,fns:lvar list,other:lvar list,args:lvar list,
                    159:          body:cexp,label:lvar,env:env,callc:bool}
                    160: fun regf bindings =
                    161: let fun pack m =
                    162:       let fun getother w =
                    163:            let fun g(({v,...}:info,other,_)::tl) = if v=w then other
                    164:                        else g tl
                    165:                       | g [] = ErrorMsg.impossible "[] 4849 in cps/closure"
                    166:            in  g m
                    167:            end
                    168:          fun getcallc w =
                    169:            let fun g(({v,...}:info,_,callc)::tl) = if v=w then callc
                    170:                        else g tl
                    171:                       | g [] = ErrorMsg.impossible "[] 4848 in cps/closure"
                    172:            in  g m
                    173:            end
                    174:          fun f (x as {args,fns,...}:info, other, callc) =
                    175:                  (x,
                    176:                   foldmerge(other :: map getother fns),
                    177:                   callc orelse
                    178:                   (length args + length other >= maxfree andalso
                    179:                    length other > 1) orelse
                    180:                   exists getcallc fns)
                    181:          val m' = map f m
                    182:       in  if exists (fn ({callc,...}:info,_,callc') => callc <> callc') m'
                    183:          then regf (map (fn ({v,fns,other,args,body,label,callc,env},_,cc') =>
                    184:                                {v=v,fns=fns,other=other,args=args,body=body,
                    185:                                 label=label,env=env,callc=cc'}) m')
                    186:          else if exists (fn x=>x) 
                    187:                        (List2.map2 (fn ((_,other,_),(_,other',_)) => 
                    188:                                length other <> length other')
                    189:                              (m,m'))
                    190:               then pack m'
                    191:          else fold (fn(({v,args,body,label,env,...},other,callc),(b,f)) =>
                    192:                        if callc then 
                    193:                        ({v=v,args=args,body=body,label=label,env=env,
                    194:                         free=[],callc=callc}::b,merge(other,f))
                    195:                        else
                    196:                        ({v=v,args=args,body=body,label=label,env=env,
                    197:                         free=other,callc=callc}::b,f))
                    198:                     m' ([],[])
                    199:       end
                    200: in  pack (map (fn (x as {other,callc,...}) => (x,other,callc)) bindings)
                    201: end
                    202: 
                    203: 
                    204: fun compute_escapes ce =
                    205: let val s = Intset.new()
                    206:     val use = Intset.add s
                    207:     val rec g =
                    208:       fn RECORD (vl,_,e) => (app (use o #1) vl; g e)
                    209:        | SELECT (_,v,_,e) => g e
                    210:        | OFFSET (_,v,_,e) => g e
                    211:        | APP(f,vl) => (app use vl)
                    212:        | FIX(l, e) => (app (g o #3) l; g e)
                    213:        | SWITCH(v,el) => app g el
                    214:        | PRIMOP(_,vl,_,el) => (app use vl; app g el)
                    215:  in g ce; Intset.mem s
                    216: end
                    217: 
                    218: 
                    219: fun closeCPS((f,vl,ce),constant,prof) =
                    220: let
                    221: val escapes = compute_escapes ce
                    222: val unknownset = Intset.new()
                    223: val knownset = Intset.new()
                    224: val markknown = Intset.add knownset
                    225: val markunknown = Intset.add unknownset
                    226: val freevars = FreeMap.freemapClose(ce,constant)
                    227: datatype looking = Found of object * access
                    228:                 | Pending of (lvar * object) list
                    229: exception Lookup
                    230: (* Closures may be duplicated in the 'tree'; don't look at them twice. *)
                    231: fun lookup(env as Env e,target) =
                    232:     let fun bfs([],[],seen) = raise Lookup
                    233:          | bfs([],next,seen) = bfs(next,[],seen)
                    234:          | bfs((Closure{functions,contents,offset,stamp},p)::m,next,seen) =
                    235:            let fun element i =
                    236:                 let val p' = i-offset
                    237:                 in  if p'<0
                    238:                     then (print "\nNegSel target for ";
                    239:                           print(Access.lvarName target); print " in\n";
                    240:                           printEnv env)
                    241:                     else ();
                    242:                     p'::p
                    243:                 end
                    244:                fun cnt([],i,next,seen) = bfs(m,next,seen)
                    245:                  | cnt((v,c as Closure{stamp,...})::t,i,next,seen) =
                    246:                    if target=v
                    247:                    then (element i,0,c)
                    248:                    else cnt(t,i+1,if member seen stamp
                    249:                                   then next
                    250:                                   else (c,element i)::next,seen)
                    251:                  | cnt((v,Value)::t,i,next,seen) =
                    252:                    if target=v
                    253:                    then (element i,0,Value)
                    254:                    else cnt(t,i+1,next,seen)
                    255:                  | cnt((_,Function _)::_,_,next,seen) =
                    256:                    error "Function in closure in lookup"
                    257:                fun fns([],i,seen) = cnt(contents,i,next,seen)
                    258:                  | fns((v,l)::t,i,seen) =
                    259:                        if target=v
                    260:                        then (p,i-offset,Closure{functions=functions,
                    261:                                                 contents=contents,
                    262:                                                 stamp=stamp,
                    263:                                                 offset = i})
                    264:                        else fns(t,i+1,seen)
                    265:            in if member seen stamp
                    266:               then bfs(m,next,seen)
                    267:               else fns(functions,0,enter(stamp,seen))
                    268:            end
                    269:        fun search closures =
                    270:            let val (p,off,r) =
                    271:                    bfs(formap(fn((v,c),i) => (c,[i])) closures,[],[])
                    272:                val (n::t) = rev p
                    273:                fun f [] = OFFp off | f(h::t) = SELp(h,f t)
                    274:                val (v,c) = nth(closures,n)
                    275:            in  (r,Path(v,c,f t))
                    276:            end
                    277:        fun look [] = raise Lookup
                    278:          | look ((v,c as Closure{functions,contents,stamp,offset})::tl) =
                    279:            if target=v then Found(c,Direct)
                    280:            else let fun f(_,[]) = (false,0)
                    281:                       | f(i,(v,_)::t) = if target=v then (true,i) else f(i+1,t)
                    282:                     val (foundit,n) = f(0,functions)
                    283:                     (* this junk is a hack needed for linked closures *)
                    284:                 in if foundit
                    285:                    then Found(Closure{functions=functions,
                    286:                                       contents=contents,
                    287:                                       stamp=stamp,
                    288:                                       offset=n},
                    289:                               Path(v,c,OFFp(n-offset)))
                    290:                    else ((case look tl of
                    291:                             f as Found _ => f
                    292:                           | Pending l => Pending ((v,c)::l))
                    293:                          handle Lookup => Pending [(v,c)])
                    294:                 end
                    295:          | look ((v,f as Function _)::tl) =
                    296:            if target=v then Found(f,Direct) else look tl
                    297:          | look ((v,Value)::tl) =
                    298:            if target=v then Found(Value,Direct) else look tl
                    299:       in if constant target
                    300:         then (Value,Direct)
                    301:         else (case look e of
                    302:                 Found f => f
                    303:               | Pending closures => search closures)
                    304:         handle Lookup =>
                    305:                (print "**LOOKUP: Can't find "; vp target;
                    306:                 print " in environment:\n";
                    307:                 printEnv env;
                    308:                 raise Lookup)
                    309:       end
                    310: 
                    311: fun flat(env,free) =
                    312:  map (fn v => let val (obj,_) = lookup(env,v)
                    313:              in  case obj of Function _ => pr "weird\n"
                    314:                     | _ => ();
                    315:                  (v,obj)
                    316:              end) free
                    317: fun link(env,free) =
                    318:   let val contents = map (fn v => let val (obj,acc) = lookup(env,v)
                    319:                                  in  case obj of Function _ => pr "weird\n"
                    320:                                        | _ => ();
                    321:                                      (v,obj,acc)
                    322:                                  end)
                    323:                         free
                    324:       val direct = fold (fn ((v,obj,Direct),t) => (v,obj)::t
                    325:                          | ((v,obj,Path(_,_,OFFp _)),t) => (v,obj)::t
                    326:                          | (_,t) => t) contents []
                    327:   in  if length direct = length contents then direct
                    328:        else case env of Env l =>
                    329:                let fun getc ((m as (v,Closure _))::_) = m
                    330:                      | getc (_::tl) = getc tl
                    331:                      | getc [] = error "No closure in closureStrat"
                    332:                    val c = getc (rev l)
                    333:                in  c::direct
                    334:                end
                    335:   end
                    336: 
                    337: fun closureStrategy(bindings,free,env) = (* temporary *)
                    338:   let val m = case !CGoptions.closureStrategy
                    339:                of 3 => link(env,free)
                    340:                 | 2 => link(env,free)
                    341:                 | _ => flat(env,free)
                    342:   in  mkClosure(map (fn(v,l,_,_) => (v,l)) bindings,m)
                    343:   end
                    344: 
                    345: (* Take a free variable list and replace knownfuncs by their
                    346:    free variables.  A new environment with the knownfunc mappings is
                    347:    returned.  Function aliasing could be added here. *)
                    348: fun funcAnalysis(free,env) =
                    349:   fold (fn (v,(l,env')) =>
                    350:        let val(obj,_) = lookup(env,v)
                    351:        in  case obj
                    352:              of Function{free,...} => (merge(free,l),augment((v,obj),env'))
                    353:               | _ => (enter(v,l),env')
                    354:        end)
                    355:        free ([],env0)
                    356: (* Function aliasing, separate for now, but always called after funcAnalysis. *)
                    357: fun sameClosureOpt(free,env) =
                    358: case !CGoptions.closureStrategy
                    359:   of 0 => free (* flat without aliasing *)
                    360:    | 2 => free (* linked without aliasing *)
                    361:    | _ => (* all others have aliasing *)
                    362:   let val mapping = map (fn v => let val (obj,_) = lookup(env,v)
                    363:                                 in  (v,obj)
                    364:                                 end) free
                    365:       fun uniq ((hd as (v,Closure{stamp,...}))::tl) =
                    366:        let val m' = uniq tl
                    367:        in  if exists (fn (_,Closure{stamp=stamp',...}) => stamp=stamp'
                    368:                        | _ => false) m'
                    369:            then m' else hd::m'
                    370:        end
                    371:        | uniq (hd::tl) = hd::uniq tl
                    372:        | uniq [] = []
                    373:   in  map #1 (uniq mapping)
                    374:   end
                    375: 
                    376: fun fixAccess(args,env) =
                    377: let
                    378: fun access(rootvar,(env,header)) =
                    379:   let val rec follow =
                    380:        fn (_,Value,_,_,_) => error "fixAccess Value in cps/closure"
                    381:         | (v,cl,env,OFFp off,h) =>
                    382:                  (offset(off,cl,rootvar,env),
                    383:                   h o (fn ce => OFFSET(off,v,rootvar,ce)))
                    384:         | (v,cl,env,SELp(i,OFFp 0),h) =>
                    385:                  (augment((rootvar,select(i,cl)),env),
                    386:                   h o (fn ce => SELECT(i,v,rootvar,ce)))
                    387:         | (v,cl,env,SELp(i,p),h) =>
                    388:                  let val w = mkLvar()
                    389:                      val cl = select(i,cl)
                    390:                      val env = augment((w,cl),env)
                    391:                        (* turn off lazy display here *)
                    392:                  in  follow(w,cl,env,p,h o (fn ce => SELECT(i,v,w,ce)))
                    393:                  end
                    394:       val (obj,acc) = lookup(env,rootvar)
                    395:   in  case acc
                    396:        of Direct => (env,header)
                    397:         | Path(start,cl,path) =>
                    398:             let val a as (env,header) = follow(start,cl,env,path,header)
                    399:             in  if not(!CGoptions.profile) then a
                    400:                 else let val cost = lenp path
                    401:                          val h = if cost=0 then fn x => x else
                    402:                              if cost < LINKSLOTS
                    403:                              then fn ce => prof(LINKS+cost,1,ce)
                    404:                              else fn ce => prof(LINKS,1,prof(LINKOVFL,cost,ce))
                    405:                      in  (env,h o header)
                    406:                      end
                    407:             end
                    408:   end
                    409: in  fold access args (env,fn x => x)
                    410: end
                    411: 
                    412: fun recordEl(l,env) =
                    413: if not(!CGoptions.profile)
                    414: then (map (fn (v,p) => 
                    415:         case lookup(env,v)
                    416:          of (_,Direct) => (v,p)
                    417:           | (_,Path(start,_,path)) => (start,combinepaths(path,p))) l,
                    418:       fn x => x)
                    419: else fold (fn ((v,p),(l,h)) =>
                    420:          let val (_,acc) = lookup(env,v)
                    421:              val (m,cost) = case acc of Direct => ((v,p),0)
                    422:                                | Path(start,_,path) =>
                    423:                                        ((start,combinepaths(path,p)),lenp path)
                    424:              val h' = if cost=0 then fn x => x else
                    425:                      if cost < LINKSLOTS then fn ce => prof(LINKS+cost,1,ce)
                    426:                      else fn ce => prof(LINKS,1,prof(LINKOVFL,cost,ce))
                    427:          in  (m::l,h o h')
                    428:         end) l ([],fn x => x)
                    429: 
                    430: 
                    431: fun makenv(env,bindings: (lvar * lvar list * cexp) list) =
                    432: let
                    433: val _ = COMMENT(fn() => (pr "Beginning makenv.\nInitial environment:\n";
                    434:                         printEnv env; pr "\n"))
                    435: 
                    436: (* A debugging version of freevars *)
                    437: fun fpr(v,free) = COMMENT(fn() => (pr "Free in "; vp v; pr ":"; ilist free))
                    438: val freevars =
                    439:   (fn v => let val free = freevars v
                    440:           in  fpr(v,free);
                    441:               free
                    442:           end)
                    443: 
                    444: (* Separate functions into those that escape and those which are knownfuncs *)
                    445: val (escape,known) = partition (escapes o #1) bindings
                    446: val escaping = uniq(map #1 escape)
                    447: 
                    448: val _ = COMMENT(fn() => pr "Knownfuncs...\n")
                    449: (* Mark each known function of the FIX with its free variables. *)
                    450: val known
                    451:        = map (fn(v,args,body) => {v=v,free=freevars v,args=args,body=body}) known
                    452: 
                    453: (* For each known function of the FIX, remove any escaping functions of the
                    454:    FIX from its free list and mark that the function requires the closure. *)
                    455: val known
                    456:        = map (fn {v,free,args,body} =>
                    457:                let val free' = difference(free,escaping)
                    458:                in  {v=v,free=free',
                    459:                     callc=(free<>free'),
                    460:                     args=args,body=body}
                    461:                end) known
                    462: 
                    463: (* Separate known functions defined in this FIX from other free variables. *)
                    464: local val knownlvars = map #v known
                    465: in    val knownlvar = fn v => exists (fn w => v=w) knownlvars
                    466: end
                    467: val known
                    468:        = map (fn {v,free,callc,args,body} =>
                    469:                let val (fns,other) = partition knownlvar free
                    470:                in  {v=v,fns=fns,other=other,callc=callc,args=args,body=body}
                    471:                end)
                    472:              known
                    473: 
                    474: (* Replace knownfuncs defined in other FIX'es by their free variables, and
                    475:    escaping functions defined in other FIX'es by their closures.  Label
                    476:    each knownfunc. *)
                    477: val known
                    478:        = map (fn{v,fns,other,callc,args,body} =>
                    479:                let val (other,env') = funcAnalysis(other,env)
                    480:                    val other = sameClosureOpt(other,env)
                    481:                in  {v=v,fns=fns,other=other,callc=callc,args=args,body=body,
                    482:                     env=env',label=dupLvar v}
                    483:                end)
                    484:              known
                    485: 
                    486: (* Merge free variables of knownfuncs that call each other. *)
                    487: (* Look at the number of free variables and arguments to each known function
                    488:    to be defined.  The cps converter ensures that there are enough registers
                    489:    to hold the arguments and leaves one register free for the free variables,
                    490:    if any.  Therefore some free variables may have to be spilled into the closure,
                    491:    and these must be collected. *)
                    492: val (known,collected)
                    493:        = regf known
                    494: 
                    495: val _ = COMMENT(fn() => pr "Escaping functions...\n")
                    496: (* Get the combined list of the free variables of all the escaping functions
                    497:    of the FIX. *)
                    498: val free : lvar list = remove(escaping, foldmerge(map (freevars o #1) escape))
                    499: val _ = COMMENT(fn() => (pr "AAA"; ilist free))
                    500: 
                    501: (* Replace knownfuncs defined in this FIX with their free variables. *)
                    502: val free : lvar list
                    503:        = let val (fns,other) = partition knownlvar free
                    504:          in  fold (fn ({v,free,...},b) =>
                    505:                        if exists (fn w => v=w) fns
                    506:                        then merge(free,b)
                    507:                        else b) known other
                    508:          end
                    509: val _ = COMMENT(fn() => (pr "BBB"; ilist free))
                    510: 
                    511: val free = merge(collected,free)
                    512: val _ = COMMENT(fn() => (pr "CCC"; ilist free))
                    513: 
                    514: 
                    515: (* Replace knownfuncs defined elsewhere with their free variables, and escaping
                    516:    functions defined elsewhere with their closures.  The function environment
                    517:    which tells that certain free variables are known functions and gives their
                    518:    free variables must be kept for applications of the functions in the bodies
                    519:    of the escaping functions of the FIX. *)
                    520: val (free,functionEnv) : lvar list * env (* only need function mapping here *)
                    521:        = let val (free,env') = funcAnalysis(free,env)
                    522:              val free = sameClosureOpt(free,env)
                    523:          in  (free,env')
                    524:          end
                    525: val _ = COMMENT(fn() => (pr "DDD"; ilist free))
                    526: 
                    527: 
                    528: (* Given the functions to be defined in the closure (escape), the free variables
                    529:    which should be contained in the closure (free), and their current locations
                    530:    (env), decide on a closure representation. *)
                    531: val escape = map (fn(v,args,body) => (v,dupLvar v,args,body)) escape
                    532: val closure = closureStrategy(escape,free,env)
                    533: val _ = COMMENT(fn() =>
                    534:                let val Closure{contents,...} = closure
                    535:                in  pr "EEE"; ilist (map #1 contents)
                    536:                end)
                    537: 
                    538: fun mkFnMap c : (lvar * object) list
                    539:        = map (fn{v,free,callc,label,...} =>
                    540:                if callc then (v,Function{label=label,free=enter(c,free)})
                    541:                else (v,Function{label=label,free=free}))
                    542:              known
                    543: 
                    544: (* Final construction of the environment for each standard function. *)
                    545: val closureFrags : (lvar * lvar list * cexp * env) list
                    546:        = case escape of [] => []
                    547:        | ((v,_,_,_)::_) =>
                    548:          let val env = fold augment (mkFnMap v) functionEnv
                    549:              fun f ((v,l,args,body),i) =
                    550:                let val cname = closureLvar()
                    551:                    val env = fold (fn (v,b) => augment((v,Value),b))
                    552:                                args (offset(i,closure,cname,env))
                    553:                    val _ = COMMENT(fn () => (print "\nEnvironment at escaping ";
                    554:                                              vp v; print ":\n";
                    555:                                              printEnv env))
                    556:                in  markunknown l; (l,cname::args,body,env)
                    557:                end
                    558:          in  formap f escape
                    559:          end
                    560: 
                    561: 
                    562: (* Final construction of the environment for each known function. *)
                    563: val cname = closureLvar()
                    564: val fnMap = mkFnMap cname
                    565: val registerFrags : (lvar * lvar list * cexp * env) list
                    566:        = map (fn{v,free,callc,args,body,env=env',label} =>
                    567:                let val env =
                    568:                      fold (fn (v,env') =>
                    569:                                case lookup(env,v)
                    570:                                  of (Function _,_) => error "cps/closure.223"
                    571:                                   | (obj,_) => augment((v,obj),env'))
                    572:                           free
                    573:                           (fold (fn (v,b) => augment((v,Value),b))
                    574:                                 args
                    575:                                 (fold augment fnMap
                    576:                                    (if callc
                    577:                                     then (inc System.Control.CG.knowncl;
                    578:                                           augment((cname,closure),env'))
                    579:                                     else env')))
                    580:                    val _ = COMMENT(fn () => (print "\nEnvironment at known ";
                    581:                                              vp v; print ":\n";
                    582:                                              printEnv env))
                    583:                    val args = args @ free @ if callc then [cname] else []
                    584:                in  markknown label; (label,args,body,env)
                    585:                end)
                    586:              known
                    587: 
                    588: 
                    589: val contents = let val Closure{functions,contents,...} = closure
                    590:               in  map #2 functions @ map #1 contents
                    591:               end
                    592: 
                    593: 
                    594: (* Add profiling code if flag is on. *)
                    595: fun mkrexp(contents,cname) =
                    596:   if not(!CGoptions.profile) then fn ce => RECORD(contents,cname,ce)
                    597:   else let val len = length contents
                    598:           val (closures,slots,ovfl) =
                    599:                fold (fn((v,[_],_),b as (closures,_,_)) =>
                    600:                        if closures=CLOSURES then b
                    601:                        else if escapes v
                    602:                             then (CCLOSURES,CCLOSURESLOTS,CCLOSUREOVFL)
                    603:                             else b
                    604:                      |((v,args,_),b as (closures,_,_)) =>
                    605:                        if closures=CLOSURES then b
                    606:                        else if escapes v
                    607:                             then (CLOSURES,CLOSURESLOTS,CLOSUREOVFL)
                    608:                             else b)
                    609:                     bindings (KCLOSURES,KCLOSURESLOTS,KCLOSUREOVFL)
                    610:        in  if len < slots
                    611:           then fn ce => prof(closures+len,1,RECORD(contents,cname,ce))
                    612:           else fn ce => prof(closures,1,
                    613:                              prof(ovfl,len,RECORD(contents,cname,ce)))
                    614:        end
                    615: 
                    616: 
                    617: in  case contents
                    618:       of [] => (fn ce => ce,registerFrags,fold augment fnMap env)
                    619:        | _ =>
                    620:          let val frags = closureFrags@registerFrags
                    621:              val env = fold (fn(a,b) => augment((#1 a,Value),b)) closureFrags env
                    622:              val (contents,header) = recordEl(recordpath contents,env)
                    623:              val env = fold augment fnMap env
                    624:              val env = augment((cname,closure),env)
                    625:              val _ = COMMENT(fn () => (print "\nEnvironment after FIX:\n";
                    626:                                        printEnv env))
                    627:          in  (header o mkrexp(contents,cname),frags,env)
                    628:          end
                    629:      before COMMENT(fn() => pr "makenv done.\n\n")
                    630: end
                    631: 
                    632: 
                    633: val env1 = fold (fn(v,b) => augment((v,Value),b)) (f::vl) env0
                    634: fun close(ce,env) =
                    635:   case ce
                    636:     of FIX(bindings,b) =>
                    637:        (let val (header,frags,env') = makenv(env,bindings)
                    638:        in  FIX(map (fn(v,args,a,env) =>
                    639:                                (v,args,close(a,env))) frags,
                    640:                header(close(b,env')))
                    641:        end handle Lookup => APP(0,[]))
                    642:      | APP(f,args) =>
                    643:        let val(obj,_) = lookup(env,f)
                    644: handle Lookup => (print "LOOKUP FAILS in close(APP)\n"; (Value,Direct))
                    645:        in  case obj
                    646:              of Closure{functions,offset,...} =>
                    647:                   let val (_,header) = fixAccess(f::args,env)
                    648:                       val (_,label) = nth(functions,offset)
                    649:                       val call = APP(label,f::args)
                    650:                   in  if !CGoptions.profile
                    651:                       then header(prof(STDKCALLS,1,call))
                    652:                       else header call
                    653:                   end
                    654:               | Function{label,free} =>
                    655:                   let val args' = args@free
                    656:                       val (_,header) = fixAccess(args',env)
                    657:                       val call = APP(label,args')
                    658:                   in  if !CGoptions.profile
                    659:                       then header(prof(KNOWNCALLS,1,call))
                    660:                       else header call
                    661:                   end
                    662:               | Value =>
                    663:                   let val l = mkLvar()
                    664:                       val (_,header) = fixAccess(f::args,env)
                    665:                       val call = SELECT(0,f,l,APP(l,f::args))
                    666:                   in  if !CGoptions.profile
                    667:                       then case args
                    668:                              of [_] => header(prof(CNTCALLS,1,call))
                    669:                               | _ =>  header(prof(STDCALLS,1,call))
                    670:                       else header call
                    671:                   end
                    672:        end
                    673:      | SWITCH(v,l) =>
                    674:        let val (env',header) = fixAccess([v],env)
                    675:        in  header (SWITCH(v,map (fn c => close(c,env')) l))
                    676:        end
                    677:      | RECORD(l,v,c) =>
                    678:        let val (l,header) = recordEl(l,env)
                    679:            val ce = close(c,augment((v,Value),env))
                    680:            val len = length l
                    681:        in  header(
                    682:            if not(!CGoptions.profile) then RECORD(l,v,ce)
                    683:            else if len < RECORDSLOTS
                    684:            then prof(RECORDS+len,1,RECORD(l,v,ce))
                    685:            else prof(RECORDS,1,prof(RECORDOVFL,len,RECORD(l,v,ce))))
                    686:        end
                    687:      | SELECT(i,v,w,c) =>
                    688:        let val (env,header) = fixAccess([v],env)
                    689:            val (obj,_) = lookup(env,v)
                    690: handle Lookup => (print "LOOKUP FAILS in close(SELECT)\n"; (Value,Direct))
                    691:        in  header(SELECT(i,v,w,close(c,augment((w,select(i,obj)),env))))
                    692:        end
                    693:      | OFFSET(i,v,w,c) => error "OFFSET in cps/closure.sml!"
                    694:      | PRIMOP(i,args,rets,l) =>
                    695:        let val (env,header) = fixAccess(args,env)
                    696:            val env = fold (fn (v,b) => augment((v,Value),b)) rets env
                    697:        in  header (PRIMOP(i,args,rets,map (fn c => close(c,env)) l))
                    698:        end
                    699: in  ((mkLvar(),f::vl,unrebind(close(ce,env1))),
                    700:      Intset.mem knownset,Intset.mem unknownset)
                    701: end
                    702: 
                    703: end (* structure Closure *)
                    704: 
                    705: 

unix.superglobalmegacorp.com

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