rocedre arameters (in ascal) rocedre parameters permit procedres to be invoked ot-of-scope ; 1 program main(inpt, otpt); 2 3 procedre b(fnction h(n : integer): integer); 4 var m : integer; 5 begin m := 6; writeln(h(2)) ; 6 7 procedre c; 8 var m : integer; 9 fnction f(n: integer): integer; 10 begin f := m + n ; 11 begin m := 0; b(f) ; 12 begin c. Qestion: how to get the correct environment when calling h inside b? Soltion: mst pass static link along with f as if it had been called at the point it was passed (line 11). Traditional Stack Scheme parameters and retrned vales STACK (activation records) program conter links and saved stats code temporaries and local data Activation Record HEA (dynamic data) garbage collector STATIC (code and globals) REGISTERS Memory Layot More on Rntime Environments How to efficiently implement procedre call and retrn in the presence of higher-order fnctions? what are higher-order fnctions? how to ext frames to spport higher-order fnctions? efficiency isses (exection time, space sage)? How to efficiently spport memory allocation and de-allocation? what are the data representations? what are the memory layot? explicit vs implicit memory de-allocation? (malloc-free vs. garbage collection) Restrictions in C & ascal C does not allow nested procedres --- names in C are either local to some procedre or are global and visible in all procedres. rocedres in C can be passed as argments or retrned as reslts. ascal (or Modla-2, Modla-3, Algol ) allows procedre declarations to be nested, bt procedre parameters are of restricted se, and procedres cannot be retrned as reslt. Fnctional langages (e.g. ML, Haskell, Scheme, Lisp) spport higherorder fnctions --- spporting both nested procedres and procedres passed as parameters or retrned as reslts. spporting it is a big challenge to the compiler writers!
rocedre Activations (cont d) ested Fnctions in ML val BIG = big() v=big w=x=y=0 access links Q, fn (v,w,x,y) = val = hd(v) R control links... (v,,,y)... v=v,w= x=,y=y Q, in... Q()... val reslt = (BIG,0,0,0) $ Higher-Order Fnctions (cont d) Q lost track of its environment fn (v,w,x,y) = val = hd(v)... (,w+x+y+3)... Q val S = (BIG,0,0,0) & access links # % rocedre Activations ested Fnctions in ML val BIG = big() v=big w=x=y=0 fn (v,w,x,y) = val = hd(v) Q, control links R... (v,,,y)... in... Q()... val reslt = (BIG,0,0,0) Higher-Order Fnctions How to create a closre for Q? v=big w=x=y=0 fn (v,w,x,y) = val = hd(v)... (,w+x+y+3)... Q val S = (BIG,0,0,0)
Higher-Order Fnctions (cont d) Q s environment is in the! fn (v,w,x,y) = val = hd(v) val S = (BIG,0,0,0) ested Higher-Order Fnctions fn (v,w,x,y) = val = hd(v) Qor S R val S = (BIG,0,0,0) val reslt = T() Higher-Order Fnctions (cont d) Q mst copy the frame! v=big w=x=y=0 fn (v,w,x,y) = val = hd(v)... (,w+x+y+3)... val S = (BIG,0,0,0) Applying Higher-Order Fnctions Accessing the Closre Q! Qor S fn (v,w,x,y) = val = hd(v) R val S = (BIG,0,0,0)
R or T R w x y copying!!! Linked Closres : O( 2 ) R -1 Flat Closres : O() R w x y $ Flat Closres fn (v,w,x,y) = val = hd(v) val S = (BIG,0,0,0) val reslt = T() Slow creation, Fast access! Space Usage Space Leaks for Linked Closres fn (v,w,x,y) = val = hd(v) (,w+x+y+3) fn loop (n,res) = if n<1 then res else ( val S = (big(),0,0,0) in loop(n-1,t::res) ) val reslt = loop(,[]) Linked Closres fn (v,w,x,y) = val = hd(v) R or T R val S = (BIG,0,0,0) val reslt = T() Fast creation, Slow access! Better Representations? Closres cannot point to frame (different life time, so yo mst copy.) Linked closres --- fast creation, slow access Flat closres --- slow creation, fast access Stack frames with access links are similar to linked closres (accessing non-local variables is slow.) GOAL : We need good closre representations that have both fast access and fast creation! #
Better Space Usage? The safe for space complexity rle : Local variable mst be assmed dead after its last se within its scope! Stacks and linked closres are OT safe for space Flat closres are safe for space SML/J : nsafe version = (2 to 80) x safe version & Efficient Heap-based Compilation An efficient -based scheme has the following advantages: very good space sage (safe for space complexity!) very fast closre creation and closre access closres can be shared with activation records fast call/cc and fast generational GC simple implementation % Space Usage (cont d) -1 Q,v,w n= Space Leaks for Stack Allocations Q,v,w n=-1 fn (x) =... -1-2 -2-3 Q,v,w n=-2 Use O( 2 ) Space! fn Q(n) = val = big(n) val v = () val w = hd() in if n > 0 then Q(n-1)+v(w) else... val reslt = Q() is dead after this call! Drawbacks of Stack Allocation inefficient space sage slow access to non-local variables expensive copying between and (activation records cannot be shared by closres) scanning roots is expensive in generational GC very slow first-class continations (call/cc) correct implementation is complicated and messy
Safely Linked Closres THE TRICK: Safe for Space : se O() space Variables w,x,y have same life time! R fn (v,w,x,y) = val = hd(v) (,w+x+y+3) w x y Q v fn loop (n,res) = if n<1 then res else ( val S = (big(),0,0,0) in loop(n-1,t::res) ) -1 val reslt = loop(,[]) Good Use of Registers To avoid memory traffic, modern compilers often pass argments, retrn reslts, and allocate local variables in machine registers. Typical parameter-passing convention on modern machines: the first k argments ( k = 4 or 6) of a fnction are passed in registers R p,..., R p+k-1, the rest are passed on the. roblem : extra memory traffic cased by passing args. in registers fnction g(x : int, y : int, z :int) : int = x*y*z fnction f(x : int, y : int, z : int) = val a := g(z+3, y+3, x+4) in a*x+y+z Sppose fnction f and g pass their argments 1, R 2, R 3 ; then f mst save R 1, R 2, and R 3 to the memory before calling g, re Heap-based Scheme Ideas: no rntime! program conter safely linked closres good se of registers code HEA (dynamic data) (activation records) garbage collector STATIC (code and globals) REGISTERS Memory Layot Safely Linked Closres (cont d) THE TRICK: Shorter Access ath! Variables w,x,y have same life time! S R w x y fn (v,w,x,y) = val = hd(v) fn S() = w+x+y+3 in (S,) Q v val T = (big(),0,0,0) -1 The nmber of links traversed is at most 1.
Closres egisters? o! pred is an escaping fnction! Modle FOO: (in file foo.sml ) Its closre mst be bilt on the! fn pred(x) =...v(w,x)... val reslt = BAR.filter(pred,...) Modle BAR : (in file bar.sml ) Escaping fnctions: fnctions whose call sites are not all known at compile time! fn filter(p,l) = fn h(s,z) = if (s=[]) then rev z else ( val a = car s val r = cdr s in if p a then h(r,a::z) else h(r,z) ) in h(l,[]) $ Lambda Lifting fn filter(p,l) = r 0 r 1 r 2 r 3 s z rev p h s=[] fn h(s,z,rev,p) = if (s=[]) then rev z else ( val a = car s val r = cdr s in if p a then h(r,a::z,rev,p) else h(r,z,rev,p) ) p a in h(l,[],rev,p) rev z known fnctions can be rewritten into fnctions that are flly closed! (i.e. with no free variables!) & Good Use of Registers (cont d) how to avoid extra memory traffic? Leaf procedres (or fnctions) are procedres that do not call other procedres; e.g, the fnction exchange. The parameters of leaf procedres can be allocated in registers withot casing any extra memory traffic. Use global register allocation, different fnctions se different set of registers to pass their argments. Use register windows (as on SARC) --- each fnction invocation can allocate a fresh set of registers. Allocate closres in registers or se callee-save registers When all fails --- save to the frame or to the. # Closres egisters? es! Known fnctions: fn filter(p,l) = fnctions whose call sites are all known at compile time! h fn h(s,z) = if (s=[]) then rev z else ( val a = car s val r = cdr s in if p a then h(r,a::z) else h(r,z) ) s=[] in h(l,[]) p a h is a known fnction! Its closre can be pt in registers! (e.g., {rev,p}) rev z %
Callee-save Registers callee-save registers general registers Convention : r 4 r 5 r 6 r 0 r 1 r 2 r 3 Reserve k special registers! A B C g v w f A B C Every fnction promises to always preservethese registers! w g g v g Example : k=3 (r 4,r 5,r 6 ) x w x g x w g y A B C f retrn fn f(g,,v,w) = val x =g(,v) val y = g(x,w) in x+y+w Smmary : A Uniform Soltion Take advantage of variable life time and compiime control flow information! Spilled activation records are also thoght as closres! no rntime ---------- everything is sharable all se safely-linked closres ---------- to maximize sharing pass argments and retrn reslts in registers allocating most closres in registers good se of callee-save registers Spilled Activation Records We do not know how p treats the registers! r 0 r 1 r 2 r 3 r 4 r 5 s z rev p h s=[] r 0 r 1 r 2 r 3 r 4 r 5 a::z r z rev p a p a r 0 r 1 r 2 r 3 r 4 r 5 r rev p a r 0 r 1 r 2 r 3 r 4 r 5 r z rev p a Mst save and load everything here! rev z Callee-save Registers (cont d) A B C D E F r 0 r 1 r 2 r 3 s z rev p 6 callee-save registers : r 4,r 5,r 6,r 7,r 8,r 9 A B C D E F h s z rev p recover everything! s=[] a::z r z rev p a p a r rev p a r z rev p a no need to save and load anymore! rev z