Storage Organization / Allocation Strategies

advertisement
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 <stdio.h>
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
Download