13 Runtime Systems
13 Runtime Systems
r q(1,9)
5
Control stack
• Flow of control in program corresponds
to depth first traversal of activation tree
• Use a stack called control stack to keep
track of live procedure activations
• Push the node when activation begins
and pop the node when activation ends
• When the node n is at the top of the
stack the stack contains the nodes along
the path from n to the root
6
Scope of declaration
• A declaration is a syntactic construct associating
information with a name
– Explicit declaration :Pascal (Algol class of languages)
var i : integer
– Implicit declaration: Fortran
i is assumed to be integer
• There may be independent declarations of same
name in a program.
• Scope rules determine which declaration applies
to a name
• Name binding
8
Activation Record
• temporaries: used in
expression evaluation Temporaries
• local data: field for local data local data
• saved machine status: holds
info about machine status machine status
before procedure call Access links
• access link : to access non local
data Control links
• control link :points to Parameters
activation record of caller
• actual parameters: field to Return value
hold actual parameters
• returned value: field for
holding value to be returned
9
Activation Records: Examples
• Examples on the next few slides by Prof
Amitabha Sanyal, IIT Bombay
• C/C++ programs with gcc extensions
• Compiled on x86_64
10
Example 1 – Vanilla Program in C
11
Example 2 – Function with Local
Variables
12
Example 3 – Function with
Parameters
13
Example 4 – Reference Parameters
14
Example 5 – Global Variables
15
Example 6 – Recursive Functions
16
Example 7 – Array Access
17
Example 8 – Records and Pointers
18
Example 9 – Dynamically Created
Data
19
Issues to be addressed
• Can procedures be recursive?
• What happens to locals when
procedures return from an activation?
• Can procedure refer to non local
names?
• How to pass parameters?
• Can procedure be parameter?
• Can procedure be returned?
• Can storage be dynamically allocated?
• Can storage be de-allocated?
20
Layout of local data
• Assume byte is the smallest unit
• Multi-byte objects are stored in consecutive
bytes and given address of first byte
• The amount of storage needed is determined
by its type
• Memory allocation is done as the
declarations are processed
– Keep a count of memory locations allocated for
previous declarations
– From the count relative address of the storage
for a local can be determined
– As an offset from some fixed position
21
Layout of local data
• Data may have to be aligned (in a word)
padding is done to have alignment.
• When space is important
– Complier may pack the data so no padding is left
– Additional instructions may be required to
execute packed data
– Tradeoff between space and execution time
22
Storage Allocation Strategies
• Static allocation: lays out storage
at compile time for all data objects
• Stack allocation: manages the
runtime storage as a stack
• Heap allocation :allocates and de-
allocates storage as needed at
runtime from heap
23
Static allocation
• Names are bound to storage as the
program is compiled
• No runtime support is required
• Bindings do not change at run time
• On every invocation of procedure
names are bound to the same
storage
• Values of local names are retained
across activations of a procedure
24
• Type of a name determines the amount of
storage to be set aside
• Address of a storage consists of an offset
from the end of an activation record
• Compiler decides location of each
activation
• All the addresses can be filled at compile
time
• Constraints
– Size of all data objects must be known at
compile time
– Recursive procedures are not allowed
– Data structures cannot be created dynamically
25
Stack Allocation
Sort Sort
Sort Sort
readarray readarray
Sort Sort
qsort(1,9)
readarray qsort(1,9)
Sort Sort
readarray qsort(1,9) qsort(1,9)
array A
array B
Long length
data
array C
activation of Q
activation of Q
Called by P
arrays of Q
30
Dangling references
Referring to locations which have been deallocated
main() {
int *p;
p = dangle(); /* dangling reference */
}
int *dangle() {
int i=23;
return &i;
}
31
Heap Allocation
• Stack allocation cannot be used if:
– The values of the local variables must be
retained when an activation ends
– A called activation outlives the caller
• In such a case de-allocation of activation
record cannot occur in last-in first-out
fashion
• Heap allocation gives out pieces of
contiguous storage for activation records
32
Heap Allocation …
• Pieces may be de-allocated in any order
• Over time the heap will consist of alternate
areas that are free and in use
• Heap manager is supposed to make use of
the free space
• For efficiency reasons it may be helpful to
handle small activations as a special case
33
Heap Allocation …
• For each size of interest keep a linked list of
free blocks of that size
• Fill a request of size s with block of size s′
where s′ is the smallest size greater than or
equal to s.
• When the block is deallocated, return it to
the corresponding list
34
Heap Allocation …
35
Access to non-local names
{ BEGINNING of B3
int b=3 Scope B3
print a, b
} END of B3
print a, b
} END of B1
print a, b
} END of B0
38
Blocks … { // a0
{ // b0
{ // b1
• Blocks are simpler to { // a2
handle than procedures }
{ //b3
• Blocks can be treated as }
parameter less }
}
procedures }
• Either use stack for
memory allocation a0
40
Scope with nested procedures
Program sort; procedure quicksort(m,n:integer);
var a: array[1..n] of integer; var k,v : integer;
x: integer;
procedure readarray; function partition(y,z:integer): integer;
var i: integer; var i,j: integer;
begin begin
end;
end; begin
procedure exchange(i,j:integer) .
begin end;
begin
end; .
end.
41
Nesting Depth
• Main procedure is at depth 1
• Add 1 to depth as we go from enclosing to
enclosed procedure
quicksort(1,9)
quicksort(1,3)
Stack
partition(1,3)
exchange(i,j)
43
Access to non local names …
• Suppose procedure p at depth np refers to a
non-local a at depth na (na ≤ np), then
storage for a can be found as
– follow (np-na) access links from the record at
the top of the stack
– after following (np-na) links we reach
procedure for which a is local
• Therefore, address of a non local a in p can
be stored in symbol table as
– (np-na, offset of a in record of activation
having a )
44
How to setup access links?
• Code to setup access links is part of
the calling sequence.
• suppose procedure p at depth np calls
procedure x at depth nx.
• The code for setting up access links
depends upon whether or not the
called procedure is nested within the
caller.
45
How to setup access links?
np < nx
• Called procedure x is nested more deeply
than p.
• Therefore, x must be declared in p.
• The access link in x must point to the access
link of the activation record of the caller
just below it in the stack
46
How to setup access links?
np ≥ nx
• From scoping rules enclosing procedure at
the depth 1,2,… ,nx-1 must be same.
• Follow np-(nx-1) links from the caller.
• We reach the most recent activation of the
procedure that statically encloses both p
and x most closely.
• The access link reached is the one to which
access link in x must point.
• np-(nx-1) can be computed at compile
time.
47
Procedure Parameters
program param (input,output);
procedure b( function h(n:integer): integer);
begin
print (h(2))
end;
procedure c;
var m: integer;
function f(n: integer): integer;
begin
return m + n
end;
begin
m :=0; b(f)
end;
begin
c
end.
48
Procedure Parameters …
• Scope of m does not include procedure b
• within b, call h(2) activates f
• how is access link for activation of f is set
up?
• a nested procedure must take its access
link along with it
• when c passes f:
– it determines access link for f as if it were
calling f
– this link is passed along with f to b
• When f is activated, this passed access link
is used to set up the activation record of f
49
Procedure Parameters …
param
<f, >
50
Displays
• Faster access to non
locals d[1]
d[2] s
d[3] q(1,9)
• Uses an array of
saved d[2]
pointers to
activation records q(1,3)
saved d[2]
p(1,3)
• Non locals at depth i saved d[3]
are in the activation
e(1,3)
record pointed to by saved d[2]
d[i]
51
Setting up Displays
• When a new activation record for a
procedure at nesting depth i is set up:
• Save the value of d[i] in the new activation
record
• Set d[i] to point to the new activation
record
• Just before an activation ends, d[i] is reset
to the saved value
52
Justification for Displays
• Suppose procedure at depth j calls procedure at
depth i
• Case j < i then i = j + 1
– called procedure is nested within the caller
– first j elements of display need not be changed
– old value of d[i] is saved and d[i] set to the new
activation record
• Case j ≥ i
– enclosing procedure at depths 1…i-1 are same and are
left un-disturbed
– old value of d[i] is saved and d[i] points to the new
record
– display is correct as first i-1 records are not disturbed
53
Dynamic Scoping: Example
• Consider the following program
procedure show;
begin write(r) end;
procedure small;
var r: real;
begin r := 0.125; show end;
begin
r := 0.25; // writeln prints a newline character
show; small; writeln;
show; small; writeln;
end.
54
Example …
• Output under lexical scoping
0.250 0.250
0.250 0.250
56
Implementing Dynamic Scope
• Deep Access
– Dispense with access links
– use control links to search into the stack
– term deep access comes from the fact that
search may go deep into the stack
• Shallow Access
– hold current value of each name in static
memory
– when a new activation of p occurs a local name
n in p takes over the storage for n
– previous value of n is saved in the activation
record of p
57
Parameter Passing
• Call by value
– actual parameters are evaluated and
their r-values are passed to the called
procedure
– used in Pascal and C
– formal is treated just like a local name
– caller evaluates the actual parameters
and places rvalue in the storage for
formals
– call has no effect on the activation
record of caller
58
Parameter Passing …
• Call by reference (call by address)
– the caller passes a pointer to each
location of actual parameters
– if actual parameter is a name then
l-value is passed
– if actual parameter is an expression then
it is evaluated in a new location and the
address of that location is passed
59
Parameter Passing …
• Copy restore (copy-in copy-out, call by
value result)
– actual parameters are evaluated, rvalues
are passed by call by value, lvalues are
determined before the call
– when control returns, the current rvalues
of the formals are copied into lvalues of
the locals
60
Parameter Passing …
• Call by name (used in Algol)
– names are copied
– local names are different from
names of calling procedure
– Issue: swap(x, y) { swap(i,a[i]):
temp = x temp = i
x =y i = a[i]
y = temp a[i] = temp
}
61
3AC for Procedure Calls
S call id ( Elist )
Elist Elist , E
Elist E
• Calling sequence
– allocate space for activation record
– evaluate arguments
– establish environment pointers
– save status and return address
– jump to the beginning of the procedure
81
Procedure Calls …
Example
• parameters are passed by reference
• storage is statically allocated
• use param statement as place holder
for the arguments
• called procedure is passed a pointer to
the first parameter
• pointers to any argument can be
obtained by using proper offsets
82
Procedue Calls
• Generate three address code needed to evaluate
arguments which are expressions
• Generate a list of param three address
statements
• Store arguments in a list
S call id ( Elist )
for each item p on queue do emit('param' p)
emit('call' id.place)
Elist Elist , E
append E.place to the end of queue
Elist E
initialize queue to contain E.place
83
Procedure Calls
• Practice Exercise:
How to generate intermediate code for
parameters passed by value? Passed by
reference?
84