Chapter 6
Activation Records

powered by FreeFind

Modified: 

OVERVIEW

Procedure data typically includes parameters, local, instance (field) and global variables; this represents the set of data accessible to the procedure. The physical location of the data, whether in memory or registers, is maintained at run-time in an activation record. This record structure is normally defined at compile time.

Many language such as C and Java place activation records in a LIFO (stack) in the order of function calls:

Functions in languages such as ML are treated as general data, can be bound to a variable, passed as parameters, and returned as a function result. ML, supports function nesting, where one function can be nested within the scope or another, for example:

fun f( x ) =
    let
        fun g( y ) = x + 2;
    in
        g
   end;
fun f x  =
    let
fun g y = x + y;

    in
        g
   end;

g 4;       Error, g not visible in current scope
f 3;        Returns a function: fn y => 3+y;
(f 3) 4;   Returns 7

The following presents general issues of generating activation record definitions and details for the Java Virtual Machine (JVM).

6.1 STACK FRAMES

Problem - Memory accesses during a program execution are costly. A key compiler goal is to reduce the number of memory accesses.

Although a stack matches the LIFO allocation and deallocation of activation records, a strict stack using push and pop is not practical as data in the activation record is often accessed repeatedly and randomly at locations other than the top of stack (TOS). Pushing and popping to access data not at TOS would cause excessive memory accesses.

Stack pointer - References memory relative to the last push or pop instruction (on Intel, the eSp, and similar CPU's CALL, INT and other instructions also affect).

Frame pointer - A frame pointer is typically a register that references memory, Intel CPU's have the eBp register. The frame pointer is typically unaffected by push and pop instructions so as to remain fixed during a function execution.

General Rules for C++ Functions

Using functions requires following specific rules or protocol by both the caller and the callee. For MicroSoft C++ on the Intel processor, the rules can be summarized by the following:
 
Caller Callee
  1. Save any necessary registers and flags.
  2. Push parameters on the stack in right to left order.
  3. Call the function.
  4. Remove parameters from stack by adding to eSp number bytes pushed.
  5. Restore saved registers and flags.
  1. Save eBp and any segment registers.
  2. Point eBp to parameters on stack.
  3. Access the parameters on the stack.
  4. Modify Al, Ax, eAx or eDx:eAx to return a result.
  5. Restore eBp and any segment registers.
  6. Return.

Call-by-Value versus Call-by-Reference

The following figure illustrates the difference between value (left figure) and reference (right figure) passing in the program examples that follow later. In value passing the function does not have access to the original parameter, in reference passing the reference allows indirect access to the caller's parameters.
 
Call by Value                    Call by Reference 
Value

int X, B, C;

int Max (int Q, int R) 
{
   if (Q > R)
      return Q;
   else return R; 
}

void main(void) {
   B=3; C=8;
   X = Max( B, C );        
}
Reference

int X, B, C;

int Max (int &Q, int &R) 
{
   if (Q > R)
      return Q;
   else return R; 
}

void main(void) {
   B=3; C=8;
   X = Max( B, C );         
}
Call-by-value and reference Assembly
.data       
000000000     X          dd   ?
000000004     C          dd   8
000000008     B          dd   3
.code

Main Proc   Near     ;; 

     Push   B        ;; Highest=Max(B,C)
     Push   offset C          
     Call   Max
     Add    eSp, 8   ;; Remove B and C    
     Mov    X, eAx 

     Push   0        ;; Stop    
     Call   ExitProcess
Main Endp







Max   Proc  Near     ; int Max( int Q, int &R) {       

;;      ___________       Assuming that the call was
;;     |           |      Max( B, C ); the stack 
;;     |___________|      appears at left after the
;; Q   |   B = 3   | <- eBp+12   instruction sequence:
;;     |___________|                                
;; R   |&C=00000004| <- eBp+8    Push    eBp      
;;     |___________|             Mov     eBp, eSp    
;;     |Return Addr| <- eBp+4                      
;;     |___________|
;;     | Old eBp   | <- eBp = eSp
;;     |___________|
                           
      Push  eBp           ;; Save Caller's Frame Ptr
      Mov   eBp, eSp      ;; New Frame Ptr for Max
        Mov     eAx, [eBp+12]  
Ifa:    Mov     eBx, [eBp+8]
        Cmp     [eBx], eAx   ;;  if (Q > R)
        Jg      Thena
        Jmp     Elsea  
 Thena: Mov     eAx, [eBx]   ;;    eAx = Q;
        Jmp     EndIfa
 Elsea: Mov     eAx, [eBp+12];;  else eAx = R;
EndIfa:                       
        Pop     eBp        ;; Restore Frame Pointer
        Ret                ;; Return maximum in eAx 
Max    Endp                 
       End           Main

 

ACTIVATION RECORD OVERVIEW

 

REGISTERS

 

PARAMETER PASSING

1970 - Machine design used stack for parameter passing (Intel)

Problem - Passing parameters in registers still requires saving and restoring on calls, no savings over use of stack

RETURN ADDRESS

FRAME-RESIDENT VARIABLES

Modern architectures support use of registers for parameters, return address and locals rather than frame in memory

Variables written to frame when:

Escapes - variables escapes if passed by reference, address take (C & operator) or accessed from inner function - requires frame memory

 

6.2 FRAMES IN MiniJava

The target machine for our project will be the JVM, discussed separately from the more general discussion of the text.