Activation Records Mooly Sagiv msagivpost tau ac il

  • Slides: 50
Download presentation
Activation Records Mooly Sagiv msagiv@post. tau. ac. il Schrierber 317 03 -640 -7606 Wed

Activation Records Mooly Sagiv msagiv@post. tau. ac. il Schrierber 317 03 -640 -7606 Wed 14: 00 -15: 00 this week only html: //www. math. tau. ac. il/~msagiv/courses/wcc 01. html Chapter 6

Basic Compiler Phases Source program (string) lexical analysis Tokens syntax analysis Abstract syntax tree

Basic Compiler Phases Source program (string) lexical analysis Tokens syntax analysis Abstract syntax tree semantic analysis Frame Translate Intermediate representation Instruction selection Assembly Register Allocation Fin. Assembly

A Typical Machine CPU memory bus Cache CPU Registers Bus Main adaptor Memory I/O

A Typical Machine CPU memory bus Cache CPU Registers Bus Main adaptor Memory I/O bus I/O I/O controler Disk Graphics output networ k

Typical Virtual Memory Content static area Stack area Heap Lower addresses area

Typical Virtual Memory Content static area Stack area Heap Lower addresses area

Example factorial let function nfactor (n: int): int = if n = 0 then

Example factorial let function nfactor (n: int): int = if n = 0 then 1 else n * nfactor(n-1) in nfactor(10) end

IR for Main /* prologue of main starts with l 1 */ /* body

IR for Main /* prologue of main starts with l 1 */ /* body of main */ MOV(TEMP(RV), CALL(NAME(l 2), Exp. List(CONST(10), null /* next argument */))) /* epilogue of main */

IR for nfact /* Prologue of nfunc starts with l 2 */ /* body

IR for nfact /* Prologue of nfunc starts with l 2 */ /* body of nfunc */ MOV(TEMP(RV), ESEQ( CJUMP(=, “n”, CONST(0), NAME(l 3), NAME(l 4)), LABEL(l 3) /* then-clause */, MOV(TEMP(t 1), CONST(1)), JUMP(NAME(l 5)), LABEL(l 4), /* else-clause */ MOV(TEMP(t 1), BINOP(MUL, “n”, CALL(NAME(l 2), Exp. List(BINOP(MINUS, “n”, CONST(1)), null /* next argument */)))), LABEL(l 5)), TEMP(t 1))) /* epilogue of nfunc */ Where to store the value of n?

Pseudo IR for nfact /* Prologue of nfunc starts with l 2 */ PUSH(TEMP

Pseudo IR for nfact /* Prologue of nfunc starts with l 2 */ PUSH(TEMP t 128) MOVE(TEMP t 128, TEMP t 104) /* body of nfunc */ MOV(TEMP(RV), ESEQ( CJUMP(=, TEMP t 128, CONST(0), NAME(l 3), NAME(l 4)), LABEL(l 3) /* then-clause */, MOV(TEMP(t 1), CONST(1)), JUMP(NAME(l 5)), LABEL(l 4), /* else-clause */ MOV(TEMP(t 1), BINOP(MUL, TEMP t 128, CALL(NAME(l 2), Exp. List(BINOP(MINUS, TEMP t 128, CONST(1)), null /* next argument */)))), LABEL(l 5)), TEMP(t 1))) /* epilogue of nfunc */ POP(TEMP t 128)

function nfactor (n: int): int =. globl nfactor. ent nfactor_framesize=40. frame $sp, nfactor_framesize, $31

function nfactor (n: int): int =. globl nfactor. ent nfactor_framesize=40. frame $sp, nfactor_framesize, $31 nfactor: addiu $sp, -nfactor_framesize L 6: sw $2, 0+nfactor_framesize($sp) # save static link or $25, $0, $4 # save arg 1 or $24, $0, $31 # sw $24, -4+nfactor_framesize($sp) # save ra sw $30, -8+nfactor_framesize($sp) # prev. n

if n = 0 then 1 else n * nfactor(n-1) beq $25, $0, L

if n = 0 then 1 else n * nfactor(n-1) beq $25, $0, L 0 # n = 0? L 2: L 1: or $30, $25 lw $24, 0+nfactor_framesize($sp) or $2, $0, $24 addi $25, -1 # n-1 or $4, $0, $25 # arg 1 = n-1 L 5: jal nfactor or $25, $0, $2 # r 25= (n-1)! mult $30, $25 # r 30=n(n-1)! mflo $30 b L 2 L 0: addi $30, $0, 1 b L 2 or $2, $0, $30 lw $30, -4+nfactor_framesize($sp) or $31, $0, $30 # restore ra. lw $30, -8+nfactor_framesize($sp) b L 5 addiu $sp, nfactor_framesize j $31. end nfactor

. globl nfactor. ent nfactor_framesize=40. frame $sp, nfactor_framesize, $31 nfactor: addiu $sp, -nfactor_framesize L

. globl nfactor. ent nfactor_framesize=40. frame $sp, nfactor_framesize, $31 nfactor: addiu $sp, -nfactor_framesize L 2: L 6: sw $2, 0+nfactor_framesize($sp) or $25, $0, $4 # save arg 1 or $24, $0, $31 sw $24, -4+nfactor_framesize($sp) sw $30, -8+nfactor_framesize($sp) L 0: beq $25, $0, L 0 # n = 0? L 1: or $30, $25 L 5: lw $24, 0+nfactor_framesize($sp) or $2, $0, $24 addi $25, -1 # n-1 or $4, $0, $25 # arg 1 = n-1 jal nfactor or $25, $0, $2 # r 25= (n-1)! mult $30, $25 # r 30=n(n-1)! mflo $30 or $2, $0, $30 lw $30, -4+nfactor_framesize($sp) or $31, $0, $30 lw $30, -8+nfactor_framesize($sp) b L 5 addi $30, $0, 1 b L 2 addiu $sp, nfactor_framesize j $31. end nfactor

Outline of this lecture • • • Properties of variables Stack Frames The Frame

Outline of this lecture • • • Properties of variables Stack Frames The Frame Pointer and Frame Size The Static Pointers and Nesting Levels Machine Architectures Parameter Passing and Return Address Limitations Memory Management in the Tiger Language Summary

Compile-Time Information on Variables • Name • Type • Scope – when is it

Compile-Time Information on Variables • Name • Type • Scope – when is it recognized • Duration – Until when does its value exist • Size – How many bytes are required at runtime • Address – Fixed – Relative – Dynamic

Stack Frames • Allocate a separate space for every procedure incarnation • Relative addresses

Stack Frames • Allocate a separate space for every procedure incarnation • Relative addresses • Provide a simple mean to achieve modularity • Naturally supports recursion • Efficient memory allocation policy – Low overhead – Hardware support may be available • LIFO policy • Not a pure stack – Non local references – Updated using arithmetic

A Typical Stack Frame previous frame outgoing parameters frame pointer current frame higher addresses

A Typical Stack Frame previous frame outgoing parameters frame pointer current frame higher addresses argument 2 argument 1 static link locals return address temporaries saved registers argument 2 outgoing parameters stack frame size argument 1 static link next frame lower addresses

Pseudo IR for nfact LABEL L 2 MOVE(TEMP SP, BINOP(MINUS, TEMP SP, CONST nfactframesize)))

Pseudo IR for nfact LABEL L 2 MOVE(TEMP SP, BINOP(MINUS, TEMP SP, CONST nfactframesize))) MOVE(MEM(BINOP(MINUS, TEMP FP, CONST k)), TEMP t 128) MOVE(TEMP t 128, TEMP t 104) MOV(TEMP(RV), ESEQ( CJUMP(=, TEMP t 128, CONST(0), NAME(l 3), NAME(l 4)), LABEL(l 3) /* then-clause */, MOV(TEMP(t 1), CONST(1)), JUMP(NAME(l 5)), LABEL(l 4), /* else-clause */ MOV(TEMP(t 1), BINOP(MUL, TEMP t 128, CALL(NAME(l 2), Exp. List(BINOP(MINUS, TEMP t 128, CONST(1)), null /* next argument */)))), LABEL(l 5)), TEMP(t 1))) MOVE(TEMP t 128, MEM(BINOP(MINUS, TEMP FP, CONST k))) MOVE(TEMP SP, BINOP(PLUS, TEMP SP, CONST nfactframesize)))

Pascal 80386 Frame higher addresses argument 1 previous frame argument 2 static link return

Pascal 80386 Frame higher addresses argument 1 previous frame argument 2 static link return address bp previous bp locals current frame temporaries saved registers argument 1 outgoing parameters sp argument 2 static link next frame lower addresses

Summary thus far • The structure of the stack frame may depend on –

Summary thus far • The structure of the stack frame may depend on – Machine – Architecture – Programming language – Compiler Conventions • The stack is updated by: – Emitted compiler instructions – Designated hardware instructions

The Frame Pointer • The caller – the calling routine • The callee –

The Frame Pointer • The caller – the calling routine • The callee – the called routine • caller responsibilities: – Calculate arguments and save in the stack – Store static link • call instruction: M[--SP] : = RA PC : = callee • callee responsibilities: – FP : = SP – SP : = SP - frame-size • Why use both SP and FP?

Variable Length Frame Size • C allows allocating objects of unbounded size in the

Variable Length Frame Size • C allows allocating objects of unbounded size in the heap void p() { int i; char *p; scanf(“%d”, &i); p = (char *) alloca(i*sizeof(int)); } • Some versions of Pascal allows conformant array value parameters

Pascal Conformant Arrays program foo ; const max = 4 ; var m 1,

Pascal Conformant Arrays program foo ; const max = 4 ; var m 1, m 2, m 3: array [1. . max, 1. . max] of integer var i, j: integer procedure mult(a, b: array [1. . l, 1. . l] of integer; var c: array [1. . l, 1. . l] of integer)); var i, j, k: integer; begin { mult } for i : = 1 to l do for j : = 1 to l do begin c[i, j] : = 0 ; for k : = 1 to l do c[i, j] : = c[i, j] + a[i, k] * b[k, j]; end; { mult} begin { foo} … mult(m 1, m 2, m 3) end. { foo}

Supporting Static Scoping • References to non-local variables • Language rules – No nesting

Supporting Static Scoping • References to non-local variables • Language rules – No nesting of functions • C, C++, Java – Non-local references are bounded to the most recently enclosed declared procedure and “die” when the procedure end • Algol, Pascal, Tiger • Simplest implementation • Pass the static link as an extra argument to functions – Scope rules guarantee that this can be done • Generate code to traverse the frames

Nesting Depth • The semantic analysis identifies the static nesting hierarchy • A possible

Nesting Depth • The semantic analysis identifies the static nesting hierarchy • A possible implementation – Assign integers to functions and variables – Defined inductively • The main is at level 0 • Updated when new function begins/ends

Nesting Depth 0 let function fun 1(): int = 1 let var d: =0

Nesting Depth 0 let function fun 1(): int = 1 let var d: =0 function fun 2(): int = d+1 in fun 2() end 1 in fun 1() end 0 2

/* prologue starts at t_main: */ MOVE(TEMP t 103, CALL(NAME fun 1, TEMP FP))

/* prologue starts at t_main: */ MOVE(TEMP t 103, CALL(NAME fun 1, TEMP FP)) /* epilogue */ t_main let function fun 1(): int = /* prologue starts at fun 1 */ let 01 ESEQ( d fun 1 MOVE( var d: =0 function fun 2(): int = MEM(BINOP(PLUS, TEMP FP, CONST -4)), d+1 CONST 0), CALL(NAME fun 2, TEMP FP))) in fun 2 /* epilogue */ fun 2() end /* prologue starts at fun 2 */ BINOP(PLUS, in MEM( fun 1() BINOP(PLUS, end MEM(BINOP(PLUS, TEMP FP, CONST 0)), CONST -4)), CONST 1), … /* epilogue */

Realistic Tiger Example type tree = { key: string, left: tree, right: tree }

Realistic Tiger Example type tree = { key: string, left: tree, right: tree } tree function pretyprint(tree: tree): string = link let var output : = “” output function write(s: string) = n output : = concat(output, s) t function show(n: int, t: tree) = link let function indent(s: string) = (for i : = 1 to n do write(“ ”); output : = concat(output, s)) in if t= nil then indent(“. ”) s else (indent(t. key); link show(n+1, t. left); show(n+1, t. right)) end {show} i in show(0, tree); output end main pretyprint show indent

Realistic Tiger Example type tree = { key: string, left: tree, right: tree }

Realistic Tiger Example type tree = { key: string, left: tree, right: tree } tree function pretyprint(tree: tree): string = link let var output : = “” output function write(s: string) = n output : = concat(output, s) t function show(n: int, t: tree) = link let function indent(s: string) = (for i : = 1 to n do write(“ ”); output : = concat(output, s)) n in if t= nil then indent(“. ”) t else (indent(t. key); link show(n+1, t. left); show(n+1, t. right)) n end {show} t in show(0, tree); output link end main pretyprint show

Other Implementations of Static Scoping • Display – An array of static links –

Other Implementations of Static Scoping • Display – An array of static links – d[i] is static link nesting level i – Can be stored in the stack • lambda-lifting – Pass non-local variables as extra parameters

Machine Registers • Every year – CPUs are improving by 50%-60% – Main memory

Machine Registers • Every year – CPUs are improving by 50%-60% – Main memory speed is improving by 10% • Machine registers allow efficient accesses – Utilized by the compiler • Other memory units exist – Cache

RISC vs. CISC Machines Feature RISC CISC Registers 32 6, 8, 16 Register Classes

RISC vs. CISC Machines Feature RISC CISC Registers 32 6, 8, 16 Register Classes One Some Arithmetic Operands Registers Memory+Registers Instructions 3 -addr 2 -addr Addressing Modes r M[r+c] (l, s) several Instruction Length 32 bits Variable Side-effects None Some Instruction-Cost “Uniform” Varied

Caller-save vs. Callee-Save Registers • Compile every procedure separately • Partition the machine registers

Caller-save vs. Callee-Save Registers • Compile every procedure separately • Partition the machine registers into two sets – Caller-Save registers – Callee-Save registers • Hardware support may be available • Register allocation algorithm will be described later

Parameter Passing • 1960 s – In memory • No recursion is allowed •

Parameter Passing • 1960 s – In memory • No recursion is allowed • 1970 s – In stack • 1980 s – In registers – First k parameters are passed in registers (k=4 or k=6) – Where is time saved? • Most procedures are leaf procedures • Interprocedural register allocation • Many of the registers may be dead before another invocation • Register windows are allocated in some architectures per call (e. g. , sun Sparc)

Modern Architectures • return-address – also normally saved in a register on a call

Modern Architectures • return-address – also normally saved in a register on a call – a non leaf procedure saves this value on the stack – No stack support in the hardware • function-result – Normally saved in a register on a call – A non leaf procedure saves this value on the stack

Limitations • The compiler may be forced to store a value on a stack

Limitations • The compiler may be forced to store a value on a stack instead of registers • The stack may not suffice to handle some language features

Frame-Resident Variables • A variable x cannot be stored in register when: – x

Frame-Resident Variables • A variable x cannot be stored in register when: – x is passed by reference – Address of x is taken (&x) – is addressed via pointer arithmetic on the stack-frame (C varags) – x is accessed from a nested procedure – The value is too big to fit into a single register – The variable is an array – The register of x is needed for other purposes – Too many local variables • An escape variable: – Passed by reference – Address is taken – Addressed via pointer arithmetic on the stack-frame – Accessed from a nested procedure

type tree = { key: string, left: tree, right: tree } function pretyprint(tree: tree):

type tree = { key: string, left: tree, right: tree } function pretyprint(tree: tree): string = let var output : = “” function write(s: string) = output : = concat(output, s) function show(n: int, t: tree) = let function indent(s: string) = (for i : = 1 to n do write(“ ”); output : = concat(output, s)) in if t= nil then indent(“. ”) else (indent(t. key); show(n+1, t. left); show(n+1, t. right)) end {show} in show(0, tree); output end

Limitations of Stack Frames • A local variable of P cannot be stored in

Limitations of Stack Frames • A local variable of P cannot be stored in the activation record of P if its duration exceeds the duration of P • Example 1: Static variables in C (own variables in Algol) void p(int x) { static int y = 6 ; y += x; } • Example 2: Features of the C language int * f() { int x ; return &x ; } • Example 3: Dynamic allocation int * f() { return (int *) malloc(sizeof(int)); }

Higher Order Functions fun f(x) = let fun g(y) = x + y in

Higher Order Functions fun f(x) = let fun g(y) = x + y in g end val h = f(3) val j = f(4) val z = h(5) val w = j(7) int (*)() f(int x) { int g(int y) { return x + y; } return g ; } int (*h)() = f(3); int (*j)() = f(4); int z = h(5); int w = j(7);

Memory Management in the Tiger Compiler • Isolate architecture dependent parts in a separate

Memory Management in the Tiger Compiler • Isolate architecture dependent parts in a separate module – Frame • Isolate programming language dependent parts in a separate module – Translate • Isolate labels and register temporaries in a separate module – Temp

Two Layers of Abstraction semant. c translate. h translate. c frame. h temp. h

Two Layers of Abstraction semant. c translate. h translate. c frame. h temp. h mipsframe. c temp. c

Temporaries and Labels /* temp. h */ typedef struct Temp_temp_ *Temp_temp; Temp_temp Temp_newtemp(void); typedef

Temporaries and Labels /* temp. h */ typedef struct Temp_temp_ *Temp_temp; Temp_temp Temp_newtemp(void); typedef struct Temp_temp. List_ *Temp_temp. List; struct Temp_temp. List_ { Temp_temp head; Temp_temp. List tail; } Temp_temp. List Temp_Temp. List(Temp_temp h, Temp_temp. List t); typedef S_symbol Temp_label; Temp_label Temp_newlabel(void); Temp_label Temp_namedlabel(string name); string Temp_labelstring(Temp_label s);

Example frame invocations (translate. c) • When a function g(x, y, z) where x

Example frame invocations (translate. c) • When a function g(x, y, z) where x escapes is encountered f = F_new. Frame (g, U_Bool. List(TRUE, U_Bool. List(FALSE, NULL)))) ; • When a local variable v is encountered a = F_alloc. Local(f, escape) – Causes to reserve a space for v in f or in register • When a variable is accessed F_Exp(a, access) returns the generated code – access is the code for computing the static link • Ignored when a is in register

Hidden in frame. c • Word size • The location of the formals •

Hidden in frame. c • Word size • The location of the formals • Machine instructions to implement “shift-ofview”' (prologue) • The number of locals allocated so far • The label in which the machine code starts

The frame interface /* frame. h */ typedef struct F_frame_ *F_Frame; typedef struct F_access_

The frame interface /* frame. h */ typedef struct F_frame_ *F_Frame; typedef struct F_access_ *F_access; typedef struct F_access. List_ *F_access. List; struct F_access. List_ { F_access head; F_access. List tail; } F_frame F_new. Frame(Temp_label name, U_bool. List formals); F_label F_name(F_frame d); F_access. List F_formals(F_frame f); F_access f_alloc. Local(F_frame f, bool escape); Temp_temp F_FP(void); extern const int F_wordsize; T_exp F_Exp(F_access acc, T_EXP static_link);

MIPS frame implementation /* frame. c */ … #include “temp. h” F_access F_alloc. Local(F_frame

MIPS frame implementation /* frame. c */ … #include “temp. h” F_access F_alloc. Local(F_frame f, #include “frame. h” bool escape) struct F_frame_ {Temp_label name; { int formals. Count; assert(f); int locals. Count; F_access. List formals; if (escape) return … F_alloc. In. Frame(-1 * }; F_word. Size * typedef enum {in. Frame, in. Reg} F_access_kind; + f locals. Count); struct F_access { else return F_alloc. In. Register(); F_access_kind; } union { int offset; /* frame offset */ Temp_temp reg; /* register */ } u; };

The Frames in Different Architectures g(x, y, z) where x escapes Pentium MIPS Sparc

The Frames in Different Architectures g(x, y, z) where x escapes Pentium MIPS Sparc In. Frame(8) In. Frame(0) In. Frame(68) y In. Frame(12) In. Reg(t 157) z In. Frame(16) In. Reg(t 158) M[sp+0] fp fp sp sp sp-K save %sp, -K, %sp x View Change M[sp+K+0] r 2 t 157 r 4 t 158 r 5 M[fp+68] i 0 t 157 i 1 t 158 i 2

The Need for Register Copies function m(x: int, y: int) = (h(y, y); h(x,

The Need for Register Copies function m(x: int, y: int) = (h(y, y); h(x, x))

Nesting Blocks in Tiger function f() = let var v : = 6 in

Nesting Blocks in Tiger function f() = let var v : = 6 in print(v); let var v : = 7 in print(v) end; print(v); let var v : = 8 in print(v) end; print(v); end

Managing Static Links • Implemented in the translate module (translate. c) • The static

Managing Static Links • Implemented in the translate module (translate. c) • The static pointer is passed as extra argument • For every function records the frame of function in which it is defined • Generate instruction sequences for non-local references

Summary • Stack frames provide a simple compile-time memory management scheme – Locality of

Summary • Stack frames provide a simple compile-time memory management scheme – Locality of references is supported • Can be complex to implement – What about procedure parameters? • Memory allocation is one of most interesting areas