In this set of notes we will consider:
There are many possible ways to organize memory.
We will concentrate mainly on the standard Unix approach,
illustrated below:
Some old implementations of Fortran used this approach:
there is no heap or stack, and
all allocation records are in the static data area, one per method.
This means that every time a method is called, its parameters and
local variables are stored in the same locations (which are known
at compile time).
This approach has some advantages and disadvantages when compared
with stack or heap allocation of activation records:
ADVANTAGES
Assume that static allocation is used, and that each activation record
contains local variables, parameters, the return address, and (for
non-void methods) the return value.
Trace the execution of the following code by filling in the appropriate
fields of the activation records of the three methods.
Also think about where the string literals would be stored.
Stack allocation is used to implement most modern programming languages.
The basic idea is that:
Introduction
Storage Layout
+-------------------+
Lowest -> | CODE |
Address +-------------------+
| Static Data |
| (e.g. constants) |
+-------------------+
| HEAP |
| (grows toward |
| high memory) |
| | |
| \|/ |
| ' |
| , |
| /|\ |
| | |
| STACK |
| (grows toward |
Highest -> | low memory) |
Address +-------------------+
Usually, the stack is used to store one activation record
for each currently active method, and the heap is used for
dynamically allocated memory (i.e., memory allocated as a result of using
the new operator).
An activation record is a data structure used to hold information relevant
to one method call.
The exact structure of an activation record depends both
on the language in use and on the particular implementation;
a typical organization is shown in the following picture
(the individual fields will be discussed in some detail below and in the
next set of notes).
+---------------------+
low address | Local variables |
+---------------------+
| Saved registers |
+---------------------+
| Control Link |
+---------------------+
| Return address |
+---------------------+
| Parameters |
+---------------------+
| Access Link |
+---------------------+
| Return value |
|(for non-void method)|
high address +---------------------+
As mentioned above, activation records are usually stored on the stack.
A new record is pushed onto the stack when a method is called, and is
popped when the method returns.
However, for some languages, activation records may be stored
in the heap (this might be done, for example, in a concurrent language,
in which method calls do not obey the last-in-first-out protocol of a stack)
or in the static data area.
We will briefly consider the latter approach, then look at the most common
case of stack allocation.
In both cases, we will consider what must be done when a method is called,
when it starts executing, and when it returns.
Static Allocation
DISADVANTAGES
Using this approach, when a method is called, the calling
method:
The called method:
When the called method is ready to return, it:
Back in the calling method, the code that follows that call does the
following:
void error(String name, String msg) {
System.out.println("ERROR in method " + name + ": " + msg);
}
int summation(int max) {
int sum = 1;
for (int k=1; k<=max; k++) {
sum += k;
}
return sum;
}
void main() {
int x = summation(3);
if (x != 6) error("main", "bad value returned by summation");
}
Stack Allocation
When a method is called, the calling method:
The called method:
When the method returns, it: