Sebesta Chapter 10 -- Implementing Subprograms

.     Subprogam Linkage

.     Activation Records

.     Static Chains

.     Displays

.     Deep access versus shallow access

.     Referencing environments for subprograms passed as 
       parameters

subprogram linkage subprogram and call and return operations

CALL
  - Call Semantics:
     1. Save the execution status of the caller
     2. Carry out the parameter-passing process
     3. Pass the return address
     4. Transfer control to the callee
SUBPROGRAM RETURN
  - Return Semantics:
     1. If pass-by-value-result parameters are used, 
         move the current values of those parameters to 
         their corresponding actual parameters
     2. If it is a function, move the functional value to a 
         place the caller can get it
     3. Restore the execution status of the caller
     4. Transfer control back to the caller

STORAGE
.     status information about caller    .     parameters
.     return address
.     functional value

SUBROGRAM PARTS  fixed size
.     actual code -- static
.     local variables and data dynamic 

ACTIVATION RECORD non-code portion of subprogram
.     no recursion
.     only one at a time
.     can be statically allocated

Fortran 77 Activation Record
                     
   | return address |
   | local variables|
   | return address |
Fortran 77 Code and Activation Records
                          
 MAIN  | COMMON storage |
       | local variables|
       | return address |
   A   | parameters     |
       | local variables|
data   | return address |
   B   | parameters     |
       | local variables|
       | return address |
   C   | parameters     |
       | local variables|
       |                |
 MAIN  |                |
       |                |
       |                |
   A   |                |
       |                |
 code  |                |
   B   |                |
       |                |
       |                |
   C   |                |
       |                |

10.3 Implementing Subprograms with Stack Dynamic Locals
.     call and returns
.     mechanisms for non-local access
          static
          display

Complex Activation Records
.     parameters passed by two methods
.     variables in subprogram dynamically allocated
.     recursion causes simulataneous activations of subprograms
          each AR own copy of formals
                         copy of dynamic locasl
                             return address
.     static scoping access to non-locals

void sub (float total , int part ){
     int list [4]
     float sum;
     ...
     }


Typical activation record format for an ALGOL-like language
                         
       | local variables | 
       | Parameters      | 
       | Dynamic link    |
       | Return address  |



Activation record for procedure sub                

       | local          | sum
       | local          | list[4]
       | local          | list[3]
       | local          | list[2]
       | local          | list[1]
       | local          | list[0]
       | Parameter      | part
       | Parameter      | total
       | Dynamic Link   |
       | Return Address |

Without Recursion 

PROGRAM MAIN_1;
  VAR p : real;
   PROCEDURE A ( X : integer);
     VAR Y : boolean;
     PROCEDURE C (Q : boolean);
      BEGIN
       ...  <----------3
      END; {of PROCEDURE C}
     BEGIN
       ...  <----------2
       C(Y);
       ...
     END; { of PROCEDURE A}
     PROCEDURE B (R: real);
      VAR S,T : integer;
      BEGIN
       ... <----------1
       A(S);
       ...
      END;  {of PROCEDURE B)
  BEGIN  {MAIN_1 }
  ...
    B(P);
  ...
  END.
  
    At 1
                         <-top
       | Dynamic Link --|---
  ARI  | Return Address |   |
 for B | local          | S |
       | local          | T |
       | parameter      |<R |
ARI for| local          | P
MAIN_1
    At 2
                         <-top
       | Dynamic Link --|---
  ARI  | Return Address |   |
 for A | local          | Y |
       | parameter      | X |
       | Dynamic Link --|---
  ARI  | Return Address |   |
 for B | local          | S |
       | local          | T |
       | parameter      |<R |
ARI for| local          | P
MAIN_1    

At 3
                             
       | Dynamic Link --|---
  ARI  | Return Address |   |
 for C | parameter      | Q |
       | Dynamic Link --|---|
  ARI  | Return Address |   |
 for A | local          | Y |
       | parameter      | X |
       | Dynamic Link --|---
  ARI  | Return Address |   |
 for B | local          | S |
       | local          | T |
       | parameter      |<R |
ARI for| local          | P
MAIN_1 

Dynamic chain (call chain)  collection of dynamic links present at any time

local_offset  reference to local variables relative to beginning of activation record

RECURSION
 
PROGRAM Test;
   VAR VALUE : integer;

   FUNCTION Factorial (N : integer) : integer;
      BEGIN  <----------------1
        IF N <= 1
           THEN Factorial := 1
           ELSE Factorial := N * Factorial (N-1);
        END;
  BEGIN  {body of Test}
    Value := Factorial (3);
    writeln ('Factorial of 3 is : " , Value) <-----3
  END.

Activation record format for factorial
       |                 |
       | Dynamic link    |
       | Static link     |
       | Return address  |
       | Functional value|
       | parameter       | N

       |                 |top
       | Dynamic link    |--|----
       | Static link     |  |    |
       | Return (to Test)   |    |
       | Functional value| ?|    |
       | parameter       | 3|< N |
ARItest|     Local       | ?| VALUE 
        
       |                 |top
       | Dynamic link    |--|----
2nd ARI| Return(to Factorial|    |
       | Functional value| ?|    |
       | parameter       | 2|< N |
       |     Local       | ?| VALUE 
       | Dynamic link    |--|----
1st ARI| Return (to Test)   |    |
       | Functional value| ?|    |
       | parameter       | 3|< N |
ARItest|     Local       | ?| VALUE 

       |                 |top
       | Dynamic link    |--|----
3rd ARI| Return(to Factorial|    |
       | Functional value| ?|    |
       | parameter       | 1|< N |
       |     Local       | ?| VALUE 
       | Dynamic link    |--|----
2nd ARI| Return(to Factorial|    |
       | Functional value| ?|    |
       | parameter       | 2|< N |
       |     Local       | ?| VALUE 
       | Dynamic link    |--|----
1st ARI| Return (to Test)   |    |
       | Functional value| ?|    |
       | parameter       | 3|< N |
ARItest|     Local       | ?| VALUE 


At position 2 in Factorial
       |                 |top
       | Dynamic link    |--|----
3rd ARI| Return(to Factorial|    |
       | Functional value| 1|    |
       | parameter       | 1|< N |
       |     Local       | ?| VALUE 
       | Dynamic link    |--|----
2nd ARI| Return(to Factorial|    |
       | Functional value| ?|    |
       | parameter       | 2|< N |
       |     Local       | ?| VALUE 
       | Dynamic link    |--|----
1st ARI| Return (to Test)   |    |
       | Functional value| ?|    |
       | parameter       | 3|< N |
ARItest|     Local       | ?| VALUE 

At position 2 in Factorial
       |                 |top
       | Dynamic link    |--|----
       | Static link     |  |    |
2nd ARI| Return(to Factorial|    |
       | Functional value| 2|    |
       | parameter       | 2|< N |
       |     Local       | ?| VALUE 
       | Dynamic link    |--|----
1st ARI| Static link     |  |    |
       | Return (to Test)   |    |
       | Functional value| ?|    |
       | parameter       | 3|< N |
ARItest|     Local       | ?| VALUE 


At position 2 in Factorial
       |                 |top
       | Dynamic link    |--|----
       | Return (to Test)   |    |
       | Functional value| 6|    |
       | parameter       | 3|< N |
ARItest|     Local       | ?| VALUE 

At position 3 in Factorial
                             
ARItest|     Local       | 6| VALUE


10.4 Nested Subprograms
Fortran 95, Ada Javascript

              main ----- static_depth = 0
                  A    ----- static_depth = 1
                      B ----- static_depth = 2
   
         
                 
                  C      ----- static_depth = 1

 - Def: The chain_offset or nesting_depth of a 
         nonlocal reference is the difference between
         the static_depth of the reference and that of
         the scope where it is declared

 - A reference can be represented by the pair:

      (chain_offset, local_offset)

   where local_offset is the offset in the activation 
   record of the variable being referenced
10.4 Implementing Nested Subprograms with 
Example Program:

program MAIN_2;
  var X : integer;
  procedure BIGSUB;
    var A, B, C : integer;
    procedure SUB1;
      var A, D : integer;
      begin { SUB1 }
      A := B + C;  <-----------------------1
      end;  { SUB1 }
    procedure SUB2(X : integer);
      var B, E : integer;
      procedure SUB3;
        var C, E : integer;
        begin { SUB3 }
        SUB1;
        E := B + A:   <--------------------2
        end; { SUB3 }
      begin { SUB2 }
      SUB3;
      A := D + E;  <-----------------------3
      end; { SUB2 }
    begin { BIGSUB }
    SUB2(7);
    end; { BIGSUB }
  begin
  BIGSUB;
  end. { MAIN_2 }
10.4 Implementing Nested Subprograms with 
Call sequence for MAIN_2
   MAIN_2 calls BIGSUB
   BIGSUB calls SUB2
   SUB2 calls SUB3
   SUB3 calls SUB1

---> SHOW FIGURE 10.9 (p. 414)

At position 1 in SUB1:
   A - (0, 3)
   B - (1, 4)
   C - (1, 5)

At position 2 in SUB3:
   E - (0, 4)
  B  - (1, 4)
  A - (2, 3)

At position 3 in SUB2:
  A  - (1, 3)
   D - an error
   E - (0, 5)

  
At the call (assume there are no parameters that are
  subprograms and no pass-by-name parameters:
    - The activation record instance must be built
    - The dynamic link is just the old stack top 
       pointer
    - The static link must point to the most recent ari
       of the static parent (in most situations)
   Two Methods:
       1. Search the dynamic chain until the first ari
           for the static parent is found--easy, but slow
       2. Treat procedure calls and definitions like
           variable references and definitions 
           (have the compiler compute the nesting depth,
           or number of enclosing scopes between the
           caller and the procedure that declared the
           called procedure; store this nesting depth
           and send it with the call)
           e.g. Look at MAIN_2 and Figure 10.9
                  At the call to SUB1  in SUB3, this nesting
                  depth is 1, which is sent to SUB1 with
                  the call. The static link in the new ari for
                  SUB1 is set to point to the ari that is 
                  pointed to by the second static link in
                  the static chain from the ari for SUB3              
- Evaluation of the Static Chain Method

   - Problems:
    1. A nonlocal reference is slow if the number of
        scopes between the reference and the 
        declaration of the referenced variable is large

    2. Time-critical code is difficult, because the costs
        of nonlocal references are not equal, and can 
        change with code upgrades and fixes


 - Technique 2 - Displays

 - The idea: Put the static links in a separate stack 
   called a display.  The entries in the display are 
   pointers to the ari's that have the variables in the 
   referencing environment.

  - Represent references as 

       (display_offset, local_offset)
 
     where display_offset is the same as chain_offset
- Mechanics of references:  

   - Use the display_offset to get the pointer into the
     display to the ari with the variable 

   - Use the local_offset to get to the variable within
     the ari

 - Display maintenance (assuming no parameters that 
   are subprograms and no pass-by-name parameters)

   - Note that display_offset depends only on the static
     depth of the procedure whose ari is being built.  It
     is exactly the static_depth of the procedure.

   - There are k+1 entries in the display, where k is the 
     static depth of the currently executing unit (k=0 is
     for the main program)

   - For a call to procedure P with a static_depth of k:

       a. Save, in the new ari, a copy of the display 
           pointer at position k
       b. Put the link to the ari for P at position k in the
          display 
- At an exit, move the saved display pointer from
     the ari back into the display at position k

 - To see that this works:
  
   - Let Psd be the static_depth of P, and
           Qsd be the static_depth of Q
     - Assume Q calls P
     - There are three possible cases:
          1. Qsd = Psd
          2. Qsd < Psd
          3. Qsd > Psd

Example skeletal program:
        program MAIN_3;
          procedure BIGSUB;
            procedure SUB1;
              end; { SUB1 }
            procedure SUB2;
              procedure SUB3;
                end; { SUB3 }
              end; { SUB2 }
            end; { BIGSUB }
          end. { MAIN_3 }

    MAIN_3 can illustrate all three cases
Case 1: SUB2 calls SUB1

Before the call, we have:

  ARI for SUB2

  ARI for BIGSUB                                2
                                        1
  ARI for MAIN_3                                0

      Stack                     Display



 After the call, we have:

  ARI for SUB1

  ARI for SUB2

  ARI for BIGSUB                                2
                                        1       
  ARI for MAIN_3                                0

     Stack                      Display
Case 2: SUB2 calls SUB3
  Before the call, we have:


  ARI for SUB2

  ARI for BIGSUB                        2
                                        1
  ARI for MAIN_3                                0

     Stack                      Display


  After the call, we have:


  ARI for SUB3

  ARI for SUB2
                                        3
  ARI for BIGSUB                        2
                                        1
  ARI for MAIN_3                                0

     Stack                      Display
Case 1: SUB2 calls SUB1

Before the call, we have:

  ARI for SUB2

  ARI for BIGSUB                                2
                                        1
  ARI for MAIN_3                                0

      Stack                     Display



 After the call, we have:

  ARI for SUB1

  ARI for SUB2

  ARI for BIGSUB                                2
                                        1       
  ARI for MAIN_3                                0

     Stack                      Display
Case 2: SUB2 calls SUB3
  Before the call, we have:


  ARI for SUB2

  ARI for BIGSUB                        2
                                        1
  ARI for MAIN_3                                0

     Stack                      Display


  After the call, we have:


  ARI for SUB3

  ARI for SUB2
                                        3
  ARI for BIGSUB                        2
                                        1
  ARI for MAIN_3                                0

     Stack                      Display
Case 3: SUB3 calls SUB1
  Before the call, we have:

  ARI for SUB3

  ARI for SUB2
                                        3
  ARI for BIGSUB                        2
                                        1
  ARI for MAIN_3                                0

        Stack                   Display

After the call, we have:


  ARI for SUB1

  ARI for SUB3

  ARI for SUB2
                                        3
  ARI for BIGSUB                        2
                                        1
  ARI for MAIN_3                                0
     Stack                      Display
- The display can be kept in registers, if there are
   enough--it speeds up access and maintenance

 - Comparing the Static Chain and Display Methods

   1. References to locals 
       - Not much difference

   2. References to nonlocals
        - If it is one level away, they are equal
        - If it is farther away, the display is faster
        - Display is better for time-critical code, 
           because all nonlocal references cost the same

   3. Procedure calls
        - For one or two levels of depth, static chain is
          faster
        - Otherwise, the display is faster

   4. Procedure returns
       - Both have fixed time, but the static chain is
         slightly faster
   - Overall: Static chain is better, unless the display
                    can be kept in registers
10.5 Implementing Blocks

 - Two Methods:
    1. Treat blocks as parameterless subprograms
         - Use activation records

    2. Allocate locals on top of the ari of the 
         subprogram
        - Must use a different method to access locals
        - A little more work for the compiler writer


10.6 Implementing Dynamic Scoping

1. Deep Access - nonlocal references are found by 
     searching the activation record instances on
     the dynamic chain (See Figure 10.16, p. 424)
     - Length of chain cannot be statically determined
     - Every activation record instance must have
        variable names

2. Shallow Access - put locals in a central place

    Methods:
      a. One stack for each variable name (See Figure
           10.11, p. 421)
      b. Central table with an entry for each variable 
           name
10.6 Implementing Parameters that are 
    Subprogram Names (deep binding)

1. Static chain
    - Compiler simply passes the link to the static
       parent of the parameter, along with the 
       parameter

2. Display
    - All pointers to static ancestors must be saved,
       because none are necessarily in the 
       environment of the parameter

    - In many implementations, the whole display is
       saved for calls that pass subprogram 
       parameters
- Another look at the referencing environment for
 a passed subprogram

program MAIN_7;
  procedure SUB1;
    begin  { SUB1 }
    ...
    end;   { SUB1 }
  procedure SUB2(procedure SUBX);
    var SUM : real;
    procedure SUB3;
      begin  { SUB3 }
      SUM := 0.0;
      ...
      end;   { SUB3 }
    begin  { SUB2 }
    SUBX;
    SUB2(SUB3);
    ...
    end;   { SUB2 }
  begin  { MAIN_7 }
  ...
  SUB2(SUB1);
  ...
  end.   { MAIN_7 }


   - Which activation of SUB2 has the SUM that SUB3
      assigns?