lecture8_implementingsubprograms
lecture8_implementingsubprograms
1-3
Implementing “Simple” Subprograms
• Simple Programs:
– Subprograms cannot be nested
– All local variables are static
– Ex: Early versions of Fortran
• Call Semantics:
– Save the execution status of the caller (caller/callee)
– Pass the parameters (caller)
– Pass the return address to the subprogram (caller)
– Transfer control to the subprogram (caller)
1-4
Implementing “Simple” Subprograms
• Return Semantics:
– If pass-by-value-result or out mode parameters
are used, move the current values of those
parameters to their corresponding actual
parameters (callee)
– If it is a function, move the functional value to a
place the caller can get it (callee)
– Restore the execution status of the caller
(caller/callee)
– Transfer control back to the caller (callee)
1-5
Storage required for call/return
actions
• Required storage:
– Status information about the caller
– Parameters
– return address
– return value for functions
1-7
An Activation Record for “Simple”
Subprograms
Because languages with simple
subprograms do not support
recursion, there can be only one
active version of a given subprogram
at a time
Therefore, there can be only a single instance of the
activation record for a subprogram
Since activation record instance of a simple subprogram
has fixed size it can be statically allocated. It could be
also attached to the code part
1-8
Code and Activation Records of
a Program with “Simple”
Subprograms
1-9
Implementing Subprograms with
Stack-Dynamic Local Variables
• Advantage of Stack-Dynamic Local Variables
– Support for recursion
• More complex activation record
– The compiler must generate code to cause implicit
allocation and deallocation of local variables
– Recursion must be supported (adds the possibility of
multiple simultaneous activations of a subprogram)
– Each activation needs its own activation record and the
number of activations is limited only by the memory size
of the machine.
1-10
Typical Activation Record for a Language
with Stack-Dynamic Local Variables
Return address: pointer to the code
segment of the caller and an offset
address in that code segment of the
instruction following the call
Dynamic link: pointer to the base of the
activation record instance of the caller
In static scoped languages this link is
used to provide traceback information
Because the return when a run-time error occurs.
address, dynamic link, and
parameters are placed in In dynamic-scoped languages, the
the activation record dynamic link is used to access non-local
instance by the caller, these
entries must appear first. variables
1-11
Implementing Subprograms with
Stack-Dynamic Local Variables
• In most languages,
– The format of the activation record is known at
compile time
– In many cases, the size is also known, because all
the local data are of fixed size.
– In some languages, like Ada, the size of a local
array can depend on the value of an actual
parameter, so in those cases the format is static,
but the size can be dynamic.
1-12
Implementing Subprograms with Stack-
Dynamic Local Variables: Activation Record
• An activation record instance is dynamically created when a
subprogram is called
• Because the call and return semantics specify that the
subprogram last called is the first to complete, it is
reasonable to use a stack, so
– Activation record instances reside on the run-time stack
• Every subprogram activation (recursive or non-recursive)
creates a new instance of an activation record on the stack.
• The Environment Pointer (EP) must be maintained by the
run-time system. It always points at the base of the
activation record instance of the currently executing
program unit.
1-13
An Example: C Function
void sub(float total, int part)
{
int list[5];
float sum;
…
}
1-14
Revised Semantic Call/Return Actions
• Create an activation record instance
• Save the execution status of the current
program unit
• Compute and pass the parameters
• Pass the return address of the callee
• Transfer the control to the callee
1-15
Revised Semantic Call/Return Actions
Before (Prologue)
• Save the old EP to the stack as the dynamic link and create
the new value
• Allocate local variables
After (Epilogue)
• If pass-by-value-result or out mode parameters are used,
move the current values of those parameters to their
corresponding actual parameters
• If it is a function, move the functional value to a place the
caller can get it
• Restore the stack pointer by setting it to the value of the
current EP minus one and set the EP to the old dynamic link
• Restore the execution status of the caller
• Transfer control back to the caller
1-16
An Example Without Recursion
void fun1(float r) {
int s, t;
... Point 1
fun2(s);
...
}
void fun2(int x) {
int y;
... Point 2
fun3(y); main calls fun1
... fun1 calls fun2
}
void fun3(int q) { fun2 calls fun3
... Point 3
}
void main() {
float p;
...
fun1(p);
...
}
1-17
An Example Without Recursion
main calls fun1
fun1 calls fun2
fun2 calls fun3
1-18
1-18
Dynamic Chain and Local Offset
• Dynamic chain (call chain): The collection of
dynamic links in the stack at a given time
• Local variables can be accessed by their offset from
the beginning of the activation record, whose
address is in the EP. This offset is called the
local_offset
• The local_offset of a local variable can be
determined by the compiler at compile time
– How?
1-19
Local offset
• The local_offset of a variable in an activation
record can be determined at compile time,
using the order, types, and sizes of variables.
• For simplicity, we assume that all variables
take one position in the activation record.
An Example Without Recursion
main calls fun1
fun1 calls fun2
fun2 calls fun3
1-22
Activation Record for factorial
1-23
Stack contents during execution of
main and factorial
1-24
Stack contents during execution of
main and factorial
1-25
Stack contents during execution of
main and factorial
1-26
Stack contents during execution of
main and factorial
1-27
Stack contents during execution of
main and factorial
1-28
Stack contents during execution of
main and factorial
1-29
Stack contents during execution of
main and factorial
1-30
Nested Subprograms
• Some non-C-based static-scoped languages (e.g.,
Fortran 95, Ada, Python, JavaScript, Ruby, and Lua)
use stack-dynamic local variables and allow
subprograms to be nested
• All variables that can be non-locally accessed
reside in some activation record instance in the
stack
• The process of locating a non-local reference:
1. Find the correct activation record instance
2. Determine the correct offset within that activation
record instance
1-31
Locating a Non-local Reference
• Finding the offset is easy
• Finding the correct activation record instance
– Static semantic rules guarantee that all non-local
variables that can be referenced have been allocated
in some activation record instance that is on the
stack when the reference is made
1-32
Implementing Static Scoping
• The static link in an activation record instance for
subprogram A points to the bottom of one of the
activation record instances of A's static parent
1-37
Stack Contents at
Position 1
1-38
Example Ada
procedure Main_2 is
Program Variable Chain Local
offset offset
X : Integer;
procedure Bigsub is A at 0 3
A, B, C : Integer; position 1
procedure Sub1 is B at 1 4
A, D : Integer;
begin -- of Sub1 position 1
A := B + C; <-----------------------1 C at 1 5
end; -- of Sub1 position 1
procedure Sub2(X : Integer) is
B, E : Integer;
procedure Sub3 is E at 0 4
C, E : Integer;
position 2
begin -- of Sub3
Sub1; B at 1 4
E := B + A: <--------------------2 position 2
end; -- of Sub3
begin -- of Sub2 A at 2 3
Sub3; position 2
A := D + E; <-----------------------3
end; -- of Sub2 }
begin -- of Bigsub A at 1 3
Sub2(7); position 3
end; -- of Bigsub Not in scope - Not in scope -
begin D at
Error Error
Bigsub; position 3
end; of Main_2 } E at 0 5
position 3 1-39
Evaluation of Static Chains
• Problems:
1. A nonlocal reference is slow if the
nesting depth is large
2. Time-critical code is difficult:
a. Costs of nonlocal references are
difficult to determine
b. Code changes can change the
nesting depth, and therefore the cost
1-40
Blocks
• Recall that blocks are user-specified local scopes for
variables
• An example in C
{int temp;
temp = list [upper];
list [upper] = list [lower];
list [lower] = temp
}
• The lifetime of temp in the above example begins
when control enters the block
• An advantage of using a local variable like temp is
that it cannot interfere with any other variable with
the same name
1-41
Implementing Blocks
• Two Methods:
1. Treat blocks as parameter-less subprograms that
are always called from the same location
– Every block has an activation record; an instance is
created every time the block is executed
2. Since the maximum storage required for a block
can be statically determined, this amount of
space can be allocated after the local variables in
the activation record
1-42
Implementing Blocks
• Block variable storage when blocks
are not treated as parameterless
procedures
1-43
Implementing Dynamic Scoping
• Deep Access: non-local references are found
by searching the activation record instances
on the dynamic chain
- Length of the chain cannot be statically
determined
- Every activation record instance must
have variable names
• Shallow Access: put locals in a central place
– One stack for each variable name
– Central table with an entry for each variable name
1-44
Using Shallow Access to Implement
Dynamic Scoping
void sub3() {
int x, z;
x = u + v;
…
}
void sub2() {
int w, x;
…
}
void sub1() {
int v, w;
…
}
void main() { main calls sub1
int v, u; sub1 calls sub1
… sub1 calls sub2
} sub2 calls sub3
1-45
Summary
• Subprogram linkage semantics requires many
action by the implementation
• Simple subprograms have relatively basic
actions
• Stack-dynamic languages are more complex
• Subprograms with stack-dynamic local
variables and nested subprograms have two
components
– actual code
– activation record
1-46
Summary (continued)
• Activation record instances contain formal
parameters and local variables among other
things
• Static chains are the primary method of
implementing accesses to non-local variables
in static-scoped languages with nested
subprograms
• Access to non-local variables in dynamic-
scoped languages can be implemented by use
of the dynamic chain or thru some central
variable table method
1-47