Allocation Strategies

7.2 Storage Organization Computer Science 332 Compiler Construction 7.2-7.3 Storage Organization / Allocation Strategies • Runtime storage consists ...
1 downloads 1 Views 27KB Size
7.2 Storage Organization

Computer Science 332 Compiler Construction 7.2-7.3 Storage Organization / Allocation Strategies

• Runtime storage consists of – Generated target code – Data objects • Static: stored in static data area • Dynamic : stored on heap – Stack to keep track of procedure activations • Procedure call sequence: 1.Status (PC, register contents) is saved on stack 2.Called procedure executes and returns 3.Register values & PC are restored from stack

7.2 Storage Organization • Difference between static and dynamic data is most obvious in a language like C/C++: – static: #import int a [5000]; main(){ ... } – dynamic: void foo() { int size = get_size(); int *a = new int [size]; } Won't matter to us in our “toy ML” compiler

7.2 Storage Organization High

Stack

– As procedures are called, stack “grows” downward. – As dynamic storage is allocated, heap grows

Heap Static Data Low

Code

upward. – NOTE: This is the opposite of what the book has!

Activation Records • Activation record (a.k.a. frame, a.k.a. stack frame) stores info needed to execute a procedure. • A.r. is pushed when proc. is called, popped when it returns. • A.r. typically contains 1.Local data 2.Machine status (PC, registers) 3.Actual parameters (may be passed in registers) 4.Returned value (may be passed in registers)

Compile-Time Layout of Local Data • Local data declaration (e.g., int i; char c;) corresponds to allocating more space on top of stack. • Data are typically aligned in segments corresponding to addressing constraints of processor – e.g., 4-byte segments for most current (32-bit) processors. • Works well for 4-byte types like int, but for others it can be wasteful: char a, b, c; allocates 12 bytes when only 3 are needed; rest is “padding”. • Can avoid doing this by not padding, then generating extra code to “unpack” the data (probably unnecessary nowadays).

7.3 Storage-Allocation Strategies

Calling Sequences

• Static Allocation (e.g., FORTRAN, global arrays in C/C++) : irrelevant to our project • Dynamic Allocation (e.g., C/C++, Java) : ditto • Stack Allocation: necessary for implementing functions in ML – Special register top_sp ($sp in MIPS) marks top of stack – Activation records are allocated (deallocated) at run-time by incrementing (decrementing) value of this register (b/c stack grows downward).

• Call sequence allocates activation record and enters info into its fields 1. Caller evaluates actuals 2.Caller stores return address and old value of top_sp, then increments top_sp. 3.Callee saves register values and other status info 4.Callee initializes its local data and begins execution

Calling Sequences • Return sequence restores state of machine so calling proc. can continue execution 1.Callee places return value next to activation record of caller (or in a special register). 2.Using info in status field, callee restores top_sp and other registers, and jumps to a return address in caller's code ($ra in MIPS) 3.Although top_sp has been decremented, caller can copy returned value into its own activation record and use it.

fact:

L1:

sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp) slt $t0, $a0, 1 beq $t0, $zero, L1 add $v0, $zero, 1 add $sp, $sp, 8 jr $ra sub $a0, $a0, 1 jal fact lw $a0, 0($sp) lw $ra, 4($sp) add $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra

# # # # # # # # # # # # # # #

adjust stack for 2 items save the return address save the argument n test for n < 1 if n >=1, goto L1 return val = 1 pop 2 items off stack return to after jal n >= 1: arg gets (n-1) recur with (n-1) return : restore arg n restore return address pop 2 items return val = n*fact(n-1) return to caller

Concrete Example MIPS for factorial function in C (Patterson & Hennessy p. 137): int fact(int n) { return n == 0 ? 1 : n * fact(n-1); }

fact(2)

$a0 : 2

Stack

$sp

sub $sp, $sp, 8

# adjust stack for 2 items

sub $sp, $sp, 8 sw $ra, 4($sp)

# adjust stack for 2 items # save the return address

$sp $a0 : 2

$a0 : 2

2 $ra

Stack

$ra

$a0 : 2

Stack

sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp)

$sp

# adjust stack for 2 items # save the return address # save the argument n

sub sw sw slt

$sp $a0 : 2

Stack

$sp, $ra, $a0, $t0,

$sp, 8 4($sp) 0($sp) $a0, 1

2 $ra

Stack

# # # #

adjust stack for 2 items save the return address save the argument n test for n < 1

$sp

L1:

sub sw sw slt beq ... sub jal

$sp, $ra, $a0, $t0, $t0,

$sp, 8 4($sp) 0($sp) $a0, 1 $zero, L1

$a0, $a0, 1 fact

# # # # #

adjust stack for 2 items save the return address save the argument n test for n < 1 if n >=1, goto L1

sub $sp, $sp, 8

# adjust stack for 2 items

# n >= 1: arg gets (n-1) # recur with (n-1)

$sp

$a0 : 1

2 $ra

$sp $a0 : 1

Stack

sub $sp, $sp, 8 sw $ra, 4($sp)

# adjust stack for 2 items # save the return address

$sp 2 $ra

Stack

Stack

sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp)

1 $ra

$ra

$a0 : 1

2 $ra

$a0 : 1

2 $ra

Stack

# adjust stack for 2 items # save the return address # save the argument n

$sp

L1:

sub sw sw slt beq ... sub jal

$sp, $ra, $a0, $t0, $t0,

$sp, 8 4($sp) 0($sp) $a0, 1 $zero, L1

$a0, $a0, 1 fact

1 $ra

$a0 : 0

# # # # #

adjust stack for 2 items save the return address save the argument n test for n < 1 if n >=1, goto L1

# n >= 1: arg gets (n-1) # recur with (n-1)

1 $ra

$a0 : 0

Stack

# adjust stack for 2 items # save the return address

$sp

2 $ra

Stack

2 $ra

Stack

sub $sp, $sp, 8 sw $ra, 4($sp) sw $a0, 0($sp)

0 $ra 1 $ra

$ra 1 $ra

$a0 : 0

# adjust stack for 2 items

$sp

$sp

2 $ra

sub $sp, $sp, 8 sw $ra, 4($sp)

sub $sp, $sp, 8

$a0 : 0

2 $ra

Stack

# adjust stack for 2 items # save the return address # save the argument n

$sp

sub $sp, sw $ra, sw $a0, slt $t0, beq $t0, add $v0, add $sp, jr $ra

$sp, 8 # adjust stack for 2 items 4($sp) # save the return address 0($sp) # save the argument n $a0, 1 # test for n < 1 $zero, L1 # if n >=1, goto L1 $zero, 1 # return val = 1 $sp, 8 # pop 2 items off stack # return to after jal

1 $ra

$a0 : 0 $v0 : 1

lw $a0, 0($sp) lw $ra, 4($sp) add $sp, $sp, 8

$a0 : 1 $v0 : 1

$sp

2 $ra

# return : restore arg n # restore return address # pop 2 items

Stack

# return : restore arg n

1 $ra

$a0 : 1 $v0 : 1

Stack

2 $ra

lw $a0, 0($sp)

lw $a0, 0($sp) lw $ra, 4($sp) add $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra

$sp $a0 : 1 $v0 : 1

$sp

2 $ra

Stack

# # # # #

return : restore arg n restore return address pop 2 items return val = n*fact(n-1) return to caller

2 $ra

Stack

$sp

lw $a0, 0($sp)

$a0 : 2 $v0 : 1

lw $a0, 0($sp) lw $ra, 4($sp) add $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra

$a0 : 2 $v0 : 2

# return : restore arg n

2 $ra

$a0 : 2 $v0 : 1

return : restore arg n restore return address pop 2 items return val = n*fact(n-1) return to caller

$sp Stack

# return : restore arg n # restore return address # pop 2 items

$sp

Stack

# # # # #

lw $a0, 0($sp) lw $ra, 4($sp) add $sp, $sp, 8

$sp Stack