The semantics of procedures in a language determines how names are bound to storage during allocation. Information needed during an execution of a procedure is kept in a block of storage called an activation record; storage for names local to the procedure also appears in the activation record.
An activation record for a procedure has fields to hold parameters, results, machine-status information, local data, temporaries and the like. Since run-time allocation and de-allocation of activation records occurs as part of the procedure call and return sequences, we focus on the following three-address statements:
1. call
2. return
3. halt
4. action, a placeholder for other statements
For example, the three-address code for procedures c and p in fig. 4 contains just these kinds of statements. The size and layout of activation records are communicated to the code generator via the information about names that is in the symbol table. For clarity, we show the layout in Fig. 4 rather than the form of the symbol-table entries.
We assume that run-time memory is divided into areas for code, static data, and a stack.
STATIC ALLOCATION
Consider the code needed to implement static allocation. A call statement in the intermediate code is implemented by a sequence of two target-machine instructions. A MOV instruction saves the return address, and a GOTO transfers control to the target code for the called procedure:
MOV #here +20, callee.static_area
GOTO callee.code_area
The attributes callee.statatic_area and callee.code_area are constants referring to the address of the activation record and the first instruction for the called procedure, respectively. The source #here+20 in the MOV instruction is the literal return address; it is the address of instruction following the GOTO instruction.
The code for a procedure ends with a return to the calling procedure ends with a return to the calling procedure, except the first procedure has no caller, so its final instruction is HALT, which presumably returns control to the operating system. A return from procedure callee is implemented by
GOTO *callee.static_area
which transfers control to the address saved at the beginning of the activation record.
Example 1: The code in Fig. 5 is constructed from the procedures c and p in Fig. 4. We use the pseudo-instruction ACTION to implement the statement action, which represents three-address code that is not relevant for this discussion. We arbitrarily start the code for these procedures at addresses 100 and 200, respectively, and assume that each ACTION instruction takes 20 bytes. The activation records for the procedures are statically allocated starting at location 300 and 364, respectively.
/*code for c*/
100: ACTION1
120: MOV #140,364 /*save return address 140 */
132: GOTO 200 /* call p */
140: ACTION2
160: HALT
��
/*code for p*/
200: ACTION3
220: GOTO *364 /*return to address saved in location 364*/
��
/*300-363 hold activation record for c*/
300: /*return address*/
304: /*local data for c*/
�� /*364-451 hold activation record for p*/
364: /*return address*/
368: /*local data for p*/
fig 5. Target code for input in fig 4.
The instructions starting at address 100 implement the statements
action1 ; call p; action2; halt
of the first procedure c. Execution therefore starts with the instruction ACTION1 at address 100. The MOV instruction at address 120 saves the return address 140 in the machine-status field, which is the first word in the activation record of p. The GOTO instruction at address 132 transfers control to the first instruction is the target code of the called procedure.
Since 140 was saved at address 364 by the call sequence above, *364 represents 140 when the GOTO statement at address 220 is executed. Control therefore returns to address 140 and execution of procedure c resumes.