Activation Records - lgxZJ/Tiger-Compiler GitHub Wiki
This phase process all contents relate to a Stack Frame that need to be kept in computer memory. For example, in the tiger function:
function f(x : int) : int =
let var y := x + x
in if y < 10
then f(y)
else y - 1
end
a new instantiation of x is created (and initialized by f's caller) each time that f is called and a new instantiation of y is created each time the body of f is entered.
In the example above, what being processed are local variables. However, there are many other things that are necessary to be coped:
- Local variables
- Formal parameters
- Frame pointer
- Registers
- Static links
- Return address
There are many machine architectures, such as X86, MIPS, PowerPC and so on. Every one often has its own standard Frame Layout, and every user can choose a special call convention for his own tiger compiler since there is no standard for tiger language.
To illustrate what a frame layout is, let me show you a picture:
The frame pointer is used to limit the frame range together with the stack pointer. However, if the frame size can be determined at compile time and this language do not support special features that needs a dynamic stack size (such as alloca() function in C that allocate space in the calling stack frame), then this pointer can be eliminated.
When passing parameters, there are two choices:
- In Stack Frame
- In Registers
This typically happens when calling subroutines. If you choose to keep parameters in stack frames, everything is okay. However, if you choose to keep in registers, you need to pay attention, because register number is limited and one register may be reused to keep other values.
This compiler keeps all parameters in stack frames.
Tiger only support subroutines, when one subroutine finishes, control flow needs go back to the calling place. Thus, a place is needed to hold the address. As before, there are two choices:
- In Stack Frame
- In Registers
If in the stack frame, you also need to decide where to keep it (that work is part of the frame layout designing).
Also, two choices:
- In Stack Frame
- In Registers
In following conditions, variables are necessary to be kept in stack frames:
- the variable will be passed by reference or its address is needed.
- the variable is used in a nested subroutine.
- the variable is too big to fit into a single register.
- the variable is an array, for which address arithmetic is necessary to extract components.
- the variable cannot be kept in registers because all registers are already used.
Variables should be kept in registers as much as possible, since it runs faster than in memory. In this phase, we assume there are as many as possible registers in the target machine and this unreal assumption will be dealt with in a later phase.
We will say that a variable escapes if:
- it is passed by reference
- its address is taken
- it is accessed from a nested function
Variables that are marked as escaped must be kept in stack frames, and the scoped loop variables in For expressions are treated as no-escaped by default.
In languages that allow nested function declarations(such as Pascal, ML, and Tiger), the inner functions may use variables declared in outer functions(or outer scopes).
To access these outer variables, there are many ways:
- Whenever a function f is called, it can be passed a pointer to the frame of the function statically enclosing f; this pointer is the static link.
- A global array can be maintained, containing-in position i-a pointer to the frame of the most recently entered subroutine whose static nesting depth is i. This array is called a display.
- When g calls f, each variable of g that is actually accessed by f (or by any function nested inside f) is passed to f as an extra argument.
This compiler uses static links, and pass it as an extra argument.
There are some features that begins a new scope:
- Subroutines (include procedures and functions)
- Let expressions (because declarations in Let is discarded when these expressions ends)
- For expressions (because of its implicitly declared loop-var)
Support for Frame:
- myFrame.h
- myFrame_X86.c
Support for Scope(Level):
- myTranslate.h
- myTranslate.c
Support for Escape Finding:
- myEscape.h
- myEscape.c
Support for Infinite Registers:
- myTemp.h
- myTemp.c