Functions
  1. Functions and procedures.
  2. Arguments and parameters (or formal parameters or formals).
  3. Parameter passing
    1. Standard parameter passing methods.
      1. Pass by value.
        1. Each parm receives a copy of the arg.
        2. Parms are just variables initialized to the arg.
      2. Pass by reference.
        1. C++ reference parameters. ref.cpp
        2. Implementation.
          1. Parameter is a pointer to the argument.
          2. Operations always performed on the target.
      3. Pass by value-result
        1. Copy argument values to parameters at call, copy back at exit.
        2. Historically used by FORTRAN.
          1. Not a requirement.
          2. Used on early FORTRAN because pointers were expensive on the IBM architecture it ran on.
        3. ref.f
      4. Pass by result.
      5. Pass by name.
        1. Historical: Used by Algol; abandoned since.
        2. Parameters stand exactly for arguments; like macro substitution.
        3. Algol Example
        4. Jensen's Device
        5. Implementation.
    2. Mutable reference.
      1. This is not a standard term.
      2. Form of pass-by-reference.
        1. Parameter is a reference.
        2. Operations using the parameter effect the argument object.
        3. Assignments to the parameter change what it refers to.
      3. Used in Java and many OO languages.
      4. Passref.java.
    3. Different languages use different passing methods based on type, and parameter declaration.
      1. FORTRAN: By reference (presently) or by value-result in the past.
      2. Algol Example: By name, unless declared VALUE.
      3. Pascal: By value, unless declared VAR to make them by reference.
      4. C: By value, except arrays are passed by mutable reference (a C pointer).
      5. C++: C, plus & declarations pass by reference.
      6. Java: simple data pass by value, objects by mutable reference (a Java reference).
      7. Ruby: mutable reference.
      8. Ada
        1. Ada specifies the use, not the means: declare in, out, or in out.
        2. Implementer can choose the appropriate means.
        3. Ada Example
    4. Parameter Passing Method Exercise.
  4. Activation records.
    1. When a function is running, its status is recorded in an activation record.
    2. Contents.
      1. Parameter storage.
      2. Local variables.
      3. Temporary storage needed by the compiler.
      4. For methods of an object, a this pointer.
      5. Assembler-level bookkeeping.
        1. The PC value to jump to upon function return.
        2. Other saved CPU registers.
      6. Static pointer (or context pointer).
        1. Points to the activation record needed to find non-local references.
        2. The chain of static pointers gives the full referencing environment.
        3. Omitted when
          1. The language has dynamic scope, which nothing does anymore.
          2. Methods may not be nested, so the only non-local references are global. This is the case for C and C++.
      7. Dynamic pointer.
        1. Points to the activation record of the caller.
        2. Needed to implement returns, exceptions, and (if any) dynamic scope.
        3. May be omitted if the value can be computed from the storage structure.
    3. Statically-organized.
      1. Each function has a statically-allocated block of memory which is used as an activation record while the function is running.
      2. Used on some early languages (notably FORTRAN), but now considered obsolete.
      3. Will not support recursion, since a function can only have at most one activation record at a time.
    4. Organized as a stack.
      1. When a function is called, a new activation record is pushed on the stack. Popped after return.
      2. Stacks may be linked, but are usually a linear block of memory with a top pointer.
      3. Usually considerable hardware support for this model.
      4. Typical function call:
        1. Push the arguments onto the stack.
        2. Push the hardware return address (PC) into the frame and jump to the function address.
        3. Push the local and temp variables onto the stack.
        4. Establish the static and dynamic pointers (see below).
      5. Frame may be in different places on different calls.
        1. Variables may not take the same location each time. Like this.
        2. Multiple copies of some variables may exist.
        3. Important for recursive functions.
      6. Finding a variable.
        1. The compiler does not know the l-value of a variable, but knows its offset from the start of its AV.
        2. It knows how to find the start of the AV at run time.
        3. To find an l-value, the compiler generates “find frame, add constant”.
        4. For local references, this is just "stack pointer + offset".
        5. On most CPUs, the stack pointer is in a register, and these variables can be fetched or stored in one instruction.
      7. Finding a non-local variable.
        1. In a language like C, there is only one non-local scope (the global one). Offset from that instead of the stack pointer.
          Note: Gcc (but not g++) allows nested functions as an extension.
        2. If there are nested enclosing scopes
          1. The static link in each AV points to the AV of the statically-enclosing scope.
          2. The compiler can compute the difference in scope depth between reference and declaration.
          3. To find a non-local l-value, produce a translation “follow the local pointer n times to give the correct frame, then offset by the constant.”
      8. Establishing the static pointer when fa calls fb.
        1. From fa, the sequence of scopes searched to find a reference can be given Sn,Sn1,Sn2,…,S0, where Sn is the scope defined by the body of fa, from which fb is called.
        2. The activation record for fa is An, starting the static chain of activation records An,An1,An2,…,A0. These frames hold the variables in each of the scopes.
        3. For fa to call fb, fb must visible, so it must appear in one of the the scopes on that list. Say it appears in Si,ni0.
        4. Si is the scope that contains fb, but its local scope (the scope of fb's body) is a different one, which we call SFB. So fb's chain should be AFB,Ai,Ai1,…,A0.
        5. Since subscripts are nesting depths, in is just the difference in nesting depth between the call (within fa) and the called function, fb. To find Ai, follow the static chain from AFB in times to reach Ai. This difference may be zero, in which case Ai is AFB.
        6. The static link of AFB should point to this Ai. This creates the correct search chain, AFB,Ai,Ai1,…,A0.
      9. Closures.
        1. When a closure is created, it includes a static link to represent the non-local part of its referencing environment.
        2. Insert the same static link into the closure when you create it that you would have put in its frame if you were calling it there instead.
        3. When you actually do call the closure, simply copy that link into its new frame.
      10. Languages which need a static link include Pascal, Ada and Java (sort of).
        1. Pascal example
        2. Java example
          1. Functions don't nest, only classes.
          2. Non-local references are to enclosing class data.
          3. Links are between classes, and nesting levels are of classes only.
    5. Calling methods.
      x.f(a,b,c) becomes roughly class::f(x,a,b,c), where the first arg is just the this pointer.