Runtime environments: activation records and static links
Goal and assumptions
Reason about procedure calls, recursion, lexical nesting and storage lifetimes. We use a conventional stack-based implementation with separate activation records for active calls, lexical (static) scope, and explicit static and dynamic links. Exact field order and byte offsets are implementation choices; any problem requiring sizes must specify alignment and field widths. This lesson does not assume that all real compilers use this exact layout.
1. Storage duration versus scope
Static storage is allocated for objects with whole-program lifetimes. Stack allocation supports objects whose lifetimes follow nested calls: a callee's frame is removed when that call returns. Heap allocation supports more general lifetimes, such as an object returned by a function and used after the function ends. Scope determines which declaration a name denotes; lifetime determines when the corresponding object exists. Neither is the same as a source-code line range alone.
Recursion creates multiple simultaneous activations of the same procedure. If f(3) calls f(2), then f(1), there are three f activations even though the procedure has one body. Their parameters and nonstatic local variables need distinct storage. A single static slot for a recursive procedure's ordinary local x would overwrite other active calls' x values.
2. Activation-record fields and a call trace
A frame may contain parameters, a return-value location, return address, saved registers, local variables, temporaries, a dynamic link and a static link. The dynamic/control link points to the caller's activation record. It supports restoration of the caller's environment. The static/access link points to the active frame of the callee's lexically enclosing procedure, enabling access to nonlocal variables under static scope.
For factorial-like f(n), let f(3) call f(2), which calls f(1), which returns 1. The stack grows through f(3),f(2),f(1), then shrinks as f(2) computes 21=2 and f(3) computes 32=6. Return addresses identify where each caller resumes. A return address is not the same as a static link or an integer return value.
For a size question assume each frame needs 24 bytes of fixed fields, 8 bytes per parameter and 16 bytes of locals, with no additional alignment padding. A one-parameter call uses 24+8+16=48 bytes. Five simultaneously active calls use 240 bytes, excluding any outer frame. Do not multiply by the total calls made over time when the question asks for peak stack usage.
3. Static versus dynamic link: worked lexical nesting
Lexical nesting is Main containing procedures P and R; P contains procedure Q. Main has variable x, P has variable y, and Q refers to both. At runtime Main calls P, and P calls Q. Q's dynamic link points to P because P called Q. Q's static link also points to P because P lexically encloses Q. For y, Q follows one static link; for x, Q follows two static links, Q→P→Main.
Now Q calls R, which is declared directly inside Main. R's dynamic link points to Q, but R's static link points to Main. A reference to Main.x in R follows one static link, not the dynamic chain R→Q→P→Main. Runtime caller and lexical parent can differ.
If Q recursively calls Q, the new Q frame's dynamic link points to the old Q frame, while its static link points to the enclosing P activation, not the previous Q activation. Static links reflect declaration nesting, not recursion depth. To supply a callee's static link, the caller finds the current activation of the callee's lexical parent, possibly by traversing its own static chain.
4. Escaping environments and parameter effects
A function value may include a code address and an environment reference (a closure). If a nested function escapes and later accesses its enclosing variables after the enclosing call returns, ordinary stack reclamation alone is insufficient: the needed environment must survive, for example by heap allocation. Returning a pointer to an ordinary dead stack local is not repaired merely by returning its address.
Under call-by-value, a callee receives a copy of the argument value. If that value is a pointer, updating the pointed-to object can still affect the caller-visible object; reassigning the local pointer parameter does not reassign the caller's pointer variable. Under call-by-reference, the parameter denotes the caller's storage location. Distinguish changes to a variable from changes through a pointer.
Pitfalls
Static scope does not imply static allocation. Stack growth direction is machine-dependent. A display is an alternative indexed structure for accessing lexical levels, not a synonym for the dynamic link. Optimization may eliminate frames or keep locals in registers; GATE-style calculations must follow the stated abstract model rather than guessing a platform ABI.
Original practice: six single-correct MCQs
These original teaching questions are not previous-year questions. Choose exactly one answer.
P01. Main contains P and R; P contains Q. If Q calls R, R’s static link points to:
A. Q B. P C. Main D. R itself
Answer: C
A: Q is the caller, hence dynamic-link target.
B: P does not lexically enclose R.
C: R is declared directly within Main.
D: A static link normally targets the enclosing activation.
P02. If Q recursively calls Q inside P, the new Q dynamic link points to:
A. The previous Q activation B. Main always C. P always D. No frame
Answer: A
A: The previous Q is the caller.
B: Main did not make this call.
C: P is the static-link target in this example.
D: A caller activation exists.
P03. Five active one-parameter frames with 24 fixed bytes, 8 parameter bytes and 16 local bytes use:
A. 48 bytes B. 120 bytes C. 200 bytes D. 240 bytes
Answer: D
A: That is one frame.
B: This counts only fixed fields.
C: Each complete frame is 48, not 40 bytes.
D: 5×(24+8+16)=240 under the no-padding assumption.
P04. Which statement distinguishes scope and lifetime?
A. Scope always equals stack duration B. Scope selects a declaration; lifetime describes object existence C. Static scope requires all locals to be static D. A returned address extends any local lifetime
Answer: B
A: The two concepts are separate.
B: Name binding and storage existence are different questions.
C: Lexical binding is compatible with stack allocation.
D: A dangling address does not keep a local alive.
P05. A nested closure used after its enclosing call returns requires:
A. Only the old return address B. An environment whose needed values remain alive C. Reusing reclaimed stack bytes without protection D. No environment even when it reads captured variables
Answer: B
A: A return address does not preserve captured variables.
B: The captured environment must outlive the original stack frame.
C: Those bytes may be overwritten.
D: Reading captured variables requires their environment.
P06. With a pointer parameter passed by value, which operation can alter a caller-visible object?
A. Reassign only the local pointer variable B. Write through the pointer to a shared object C. Change only a local integer copy D. Return without any write
Answer: B
A: This changes only the parameter copy.
B: The copied address can still refer to the same object.
C: The local copy is separate.
D: No mutation occurs in this case.
Sources and scope
Aligned to the official 2026 course. This lesson covers a bounded topic slice; no claim of 2027 completeness. All examples and exercises are original.
Sign in to keep your progress. Sign in