Topic 7: Activation Records Compiler Design Prof. Hanjun Kim CoreLab (Compiler Research Lab) POSTECH 1
Storage Organization Stack Free Memory Heap Static Code 2
ELF file format example Executable Object File ELF header Program header table (required for executables).init section 0 0x100000000 Kernel virtual memory User stack (created at runtime) Memory outside 32-bit address space %esp (stack pointer).text section.rodata section.data section 0xf7e9ddc0 Memory-mapped region for shared libraries.bss section.symtab Run-time heap (created by malloc) brk.debug.line.strtab Section header table (required for relocatables) 0x08048000 0 Read/write segment (.data,.bss) Read-only segment (.init,.text,.rodata) Unused Loaded from the executable file 3
Activation Records (Stack frame) Local Variables In almost all modern programming language, a function may have local variables Created upon entry to function Destroyed when function returns Stack Each invocation of a function has its own instantiation of local variables Recursive calls to a function require several instantiations to exist simultaneously Functions return only after all functions have returned that it calls -> Last-In First-Out (LIFO) A LIFO structure (stack) is used to hold each instantiation Activation record (stack frame) of a function The portion of the stack used for an invocation of the function 4
Stack Used to hold local variables Large array in memory Grows downwards toward lower addresses Shrink upwards Push(r1) statck_pointer--; M[stack_pointer] = r1; r1 = Pop() r1 = M[stack_pointer]; stack_pointer++; Previous activation records need to be accessed Push/pop are not sufficient Treat stack as array with index of stack_pointer Push and pop entire activation records 5
Example let function g(x:int):int = let var y:= 10 in x + y end function h(y:int):int = y + g(y) in h(4) end Step 1: h(4) called Activation record for h is pushed onto the stack Stack for h y=4 Step 2: g(4) called Activation record for h is pushed onto the stack Stack for h y=4 Stack for g x=4 y=10 6
Example let function g(x:int):int = let var y:= 10 in x + y end function h(y:int):int = y + g(y) in h(4) end Step 3: g(4) returns value 14 Activation record for g is popped from the stack Stack for h y=4 rv=14 Step 4: h(4) returns value 18 Activation record for h is popped from the stack Stack is now empty 7
Recursive Example let function fact(n:int):int = if n = 0 than 1 else n *fact(n-1) in fact(3) end Step 1: fact(3) pushed on stack Stack for fact n=3 Step 2: fact(2) pushed on stack Stack for fact n=3 Stack for fact n=2 Step 3: fact(1) pushed on stack Stack for fact Stack for fact Stack for fact n=3 n=2 n=1 8
Recursive Example let function fact(n:int):int = if n = 0 than 1 else n *fact(n-1) in fact(3) end Step 4: fact(0) pushed on stack Stack for fact n=3 Stack for fact n=2 Stack for fact n=1 Stack for fact n=0 Step 5: fact(0) popped from stack 1 returned Step 6: fact(1) popped from stack 1 returned Step 7: fact(2) popped from stack 2 returned Step 8: fact(3) popped from stack 6 returned 9
Nest functions with returned function Some modern languages (such as ML, Scheme) support nest functions with returned function Requires local variables to remain in existence even after enclosing function as been returned Local variables must be allocated on heap, not stack Let s assume variables are stack allocated fun f(x) = let fun g(y) = x + y in g end Consider: - val z = f(4) - val w = z(5) 10
Nest functions with returned function fun f(x) = let fun g(y) = x + y in g end - val z = f(4) - val w = z(5) Step 1: f(4) called for f(4) pushed Stack for f x=4 g returned, frame for f(4) popped Stack empty Step 2: z(5) called for z(5) pushed Stack for z z=5 Memory for x has been deallocated!! 11
Stack Organizations How is data organized in stack frame? Compiler can use any layout scheme that is convenient Calling convention Microprocessor manufactures specify standard layout schemes used by all compilers If all compilers use the same calling conventions, functions compiled with one compiler can call functions compiled with another Essential for interaction with OS/libraries 12
Typical Stack Higher Addresses Pointer (FP) -> arg n arg 2 arg 1 Previous Callee can access arguments by offset from FP: argument 1: M[FP] argument 2: M[FP+1] local var 1 local var 2 local var n Return Address Current Local variables accessed by offset from FP local variable 1: M[FP-1] local variable 2: M[FP-2] Temporaries Stack Pointer (SP) -> Saved Registers Garbage Lower Addresses 13
Stack Example Suppose f(a1, a2) calls g(b1, b2, b3) Step 1: Pointer (FP) -> a2 a1 Previous Step 2: Stack Pointer (SP) -> Garbage for f Pointer (FP) -> a2 a1 Previous Stack Pointer (SP) -> b3 b2 b1 Garbage for f 14
Stack Example Suppose f(a1, a2) calls g(b1, b2, b3) Step 3: a2 a1 Dynamic Link Previous Pointer (FP) -> Stack Pointer (SP) -> b3 b2 b1 Old FP/Dynamic Link Garbage for f for g Dynamic link (A.K.A. Control link) points to the activation record of the caller Optional if size of caller activation record is known at compile time Used to restore stack pointer during return sequence 15
Stack Example Suppose f(a1, a2) calls g(b1, b2, b3), and returns Step 4: Pointer (FP) -> a2 a1 Previous Stack Pointer (SP) -> b3 b2 b1 Garbage for f 16
Stack Example Suppose f(a1, a2) calls g(b1, b2, b3), and returns Step 5: Pointer (FP) -> a2 a1 Previous Stack Pointer (SP) -> b3 b2/ Garbage b1/garbage Garbage for f 17
Parameter Passing f(a1, a2,, an) Registers are faster than memory Compiler should keep values in register whenever possible Modern calling convention: Put a1,, ak in registers r1,, rk Put ak,, an into stack If registers r1,, rk are needed for other purposes, callee function must save incoming arguments in stack frame 18
Parameter Passing C language allows programmer to take address of formal parameter and guarantees tat formals are located at consecutive memory addresses Ex: varargs in printf, int* f(int x) {return &x;} Space must be allocated even if parameters are passed through register If address argument has address taken, it must be written into stack frame Pointer (FP) -> Stack Pointer (SP) -> a(n) a(k+1) Space for a(k) Space for (a2) Space for (a1) Garbage 19
Registers Calling convention Caller-save registers Calling function saves them into the stack if they will be used after the call Callee function use caller-save registers without saving them Callee-save registers Callee function saves them into the stack before it uses them Caller (calling function) assumes that these registers will contain the same values before and after the call 20
Registers Registers hold: Some parameters Return values Intermediate results of expressions (temporaries) Stack holds: Variable passed by reference or have their address taken (&) Variables that are accessed by procedures nested within current one Variables that are too large to fit into register file Array variables (address arithmetic needed to access array elements) Variables whose registers are needed for a specific purpose (parameter passing) Spilled registers. Too many local variables to fit into register file, so some must be stored in stack frame 21
Registers Compilers typically place variables on stack Register Allocator assigned a variable to a register If the variable is not referenced 22
Return address Address of instruction following the function call When a called function finished, program counter can return to calling function Can be placed on stack or in a register In modern machines, the call instruction places the return address in a designated register Callee-save register 23
Escape variables A variable is escape if If it is passed by reference If its address is taken If it is accessed from a nested function 24
Static Links Some languages allow nested functions Functions must access outer function s stack frame let function f():int = let var a:=5 function g(y:int):int = let var b:=10 function h(z:int):int = if z>10 then h(z/2) else z + b * a in end in g(10) end in f() end y + a + h(16) <- b, a of outer fn <- a of outer fn 25
Static Links Static Link (A.K.A. Access Link) Whenever f is called, it is passed pointer to the closest activation record of g that immediately encloses f in program text f() g(10) Pointer (FP) -> Stack Pointer (SP) -> a = 5 for f Pointer (FP) -> a = 5 y=10 STATIC LINK for f Dynamic Link Stack Pointer (SP) -> b=10 for g &y = FP+1 &a = M[FP]-1 26
Static Links h(8) h(16) a = 5 a = 5 y=10 for f y=10 STATIC LINK Dynamic Link for f STATIC LINK Dynamic Link b=10 for g FP -> SP -> b=10 z=16 STATIC LINK Dynamic Link for g for h &z = FP+1 &y = M[FP]+1 &a = M[M[FP]]-1 FP -> SP -> z=16 STATIC LINK Dynamic Link z=8 STATIC LINK Dynamic Link for h &z = FP+1 &y = M[FP]+1 &a = M[M[FP]]-1 for h 27