Activation Records
An Activation Record—also called a stack frame—stores the execution state associated with a single procedure call. It is normally created when a routine is called and reclaimed when that routine returns.
Activation records are central to procedure calls, recursion, parameter passing, local-variable storage, return control, and access to nonlocal variables. A call stack is a last-in, first-out structure whose top frame represents the currently executing routine.
Learning objectives
By the end of this section, you should be able to:
- Define an activation record and explain its purpose.
- Identify the usual fields in an activation record.
- Describe how activation records support recursion.
- Distinguish a dynamic link from a static link.
- Explain the calling and return sequences.
- Compare access links with displays.
- Recognize the relationship between activation records, stack allocation, and debugging.
Footnotes
-
Activation Records/Stack Frames - Princeton University - Lecture material defining activation records, their lifetime, recursion, dynamic links, and static links. ↩
-
Call stack - Overview of stack frames, return control, recursion, and access links. ↩
Core idea
An activation record is the runtime representation of one particular execution of a procedure. Two calls to the same procedure have two different activation records.
1. Definition and purpose
When a program invokes a function, the runtime must preserve enough information to:
- Receive the actual arguments.
- Store the function’s local variables.
- Remember where execution must continue after return.
- Preserve registers and machine state when required.
- Store intermediate expression results.
- Access variables declared in enclosing scopes.
- Return a result to the caller.
This information is grouped into an activation record. The exact layout depends on the programming language, processor architecture, compiler, optimization level, and calling convention.
A simplified activation record may be represented as:
| Component | Purpose |
|---|---|
| Return value | Holds or identifies the result produced by the routine |
| Actual parameters | Values or addresses supplied by the caller |
| Return address | Instruction location to resume after the call |
| Dynamic link | Points to the caller’s activation record |
| Static/access link | Points toward the lexically enclosing scope |
| Saved machine status | Preserves registers and processor state |
| Local data | Stores variables declared inside the routine |
| Temporaries | Stores intermediate computation results |
The fields are conceptual rather than universal. Some values may be held in registers, passed in registers, or optimized away entirely.
Footnotes
-
Activation Records/Stack Frames - Princeton University - Lecture material defining activation records, their lifetime, recursion, dynamic links, and static links. ↩
2. Typical layout
A common conceptual layout is shown below. The physical order can differ between systems.
| Region | Typical contents |
|---|---|
| Caller-related area | Arguments, return address, caller-visible result information |
| Control information | Dynamic link, static link, saved frame pointer |
| Callee-saved state | Registers and machine status that must be restored |
| Local storage | Automatic local variables and compiler-generated storage |
| Temporary storage | Intermediate values, spilled registers, and expression results |
A frame pointer, often written as , provides a stable reference point for fields within the frame, while a stack pointer, written as , identifies the current stack position. In many implementations, arguments and local variables are accessed using offsets from .
For example:
The direction and exact offsets depend on stack-growth direction and the target architecture.
Footnotes
-
Activation Records - Discussion of parameters, local variables, frame pointers, and offsets. ↩
3. Important fields
Return value
The return-value area holds the value produced by a function or provides a location where that value can be written. Small scalar results are often returned in registers, whereas large objects may be returned through a hidden pointer or caller-provided memory area.
Parameters
Parameters contain the inputs supplied to a routine. Depending on the calling convention, arguments may be passed:
- In processor registers.
- On the stack.
- Through a mixture of registers and stack locations.
- By value.
- By reference or address.
- Through a hidden structure-return or environment parameter.
The activation record provides the callee with a predictable way to locate arguments, regardless of how the source-level call is written.
Return address
The return address identifies the point in the caller immediately following the procedure call. A call instruction commonly saves this address in a register or on the stack; the called routine or its prologue may then preserve it in the activation record.
Dynamic link
The dynamic link points to the activation record of the routine that made the call. It represents the dynamic calling relationship.
If procedure is called by procedure , then:
The dynamic link is useful for restoring the caller’s frame and stack state. It also reflects the actual order of calls, not the lexical nesting written in the source program.
Static link
The static link—also called an access link—supports lexical or static scoping. It points to the most recent activation of the procedure that lexically encloses the current procedure.
If procedure is declared inside procedure , then an activation of can use its static link to locate the activation record of and access nonlocal variables declared there.
Saved machine status
This area preserves registers, condition codes, frame pointers, and other machine state that must survive the call. The division between caller-saved and callee-saved registers is defined by the calling convention.
Local data
Local data includes variables whose lifetime is associated with the current invocation. Ordinary automatic variables are commonly stored in the activation record, although an optimizing compiler may place them in registers or eliminate them.
Temporaries
Temporaries hold intermediate values generated during expression evaluation, address calculations, argument preparation, and register spilling. Their presence and size depend heavily on compiler implementation.
Footnotes
-
Calling Conventions - Cornell lecture explaining return addresses, stack frames, stack pointers, and procedure calls. ↩
-
Activation Records - Summary of activation-record fields and distinction between access and control links. ↩
-
CSE 428 Lecture Notes 7.2 - Definition and purpose of static links. ↩
Exam distinction
The dynamic link answers “Who called me?” The static link answers “Which lexically enclosing scope contains me?” These links may point to different activation records.
4. Activation records and the runtime stack
In languages with stack-disciplined procedure lifetimes, activation records are placed on the runtime stack.
When a routine is called, its frame is pushed or allocated. When it returns, its frame is popped or reclaimed. This works because a called routine normally finishes before its caller can finish.
The stack supports nested calls naturally:
When returns, is removed first. Control then resumes in . This last-in, first-out behavior is the reason the stack is appropriate for ordinary procedure calls.
Stack allocation advantages
- Fast allocation and deallocation.
- Simple lifetime management.
- Natural support for nested calls.
- Efficient access through stack and frame pointers.
- Automatic isolation of local variables between invocations.
Limitations
- A routine whose data must outlive its caller cannot rely solely on a stack frame.
- Closures may require captured variables to move to the heap.
- Very deep recursion can exhaust available stack space.
- Variable-sized local objects complicate frame layout.
- Exceptions, coroutines, and nonlocal control transfers may require additional runtime metadata.
Footnotes
-
Call stack - Overview of stack frames, return control, recursion, and access links. ↩
Construction and destruction of an activation record
- 1Step 1
The caller evaluates actual arguments and places them in designated registers, stack locations, or memory areas according to the calling convention.
- 2Step 2
The call mechanism records the address at which the caller must resume after the callee returns.
- 3Step 3
Execution jumps to the entry point of the called routine.
- 4Step 4
The callee establishes its frame, saves required registers, records the dynamic link when needed, and reserves space for locals and temporaries.
- 5Step 5
The routine accesses parameters, local data, and nonlocal variables through registers, frame offsets, static links, displays, or other runtime mechanisms.
- 6Step 6
The routine places its result in the agreed return location, such as a result register or caller-provided memory.
- 7Step 7
The epilogue restores saved registers and the previous frame or stack pointer, then transfers control to the saved return address.
- 8Step 8
The activation record becomes inactive and its stack storage can be reused by later calls.
5. Calling sequence and return sequence
The calling sequence is divided between caller and callee responsibilities.
Caller actions
A caller commonly:
- Evaluates arguments.
- Places arguments in registers or memory.
- Saves caller-saved registers if their values are needed later.
- Supplies a static-link or environment argument when nested procedures require one.
- Executes the call instruction.
Callee prologue
The callee commonly:
- Saves the old frame pointer.
- Establishes a new frame pointer.
- Saves callee-saved registers.
- Allocates local-variable and temporary space.
- Initializes runtime metadata if required.
Callee epilogue
Before returning, the callee commonly:
- Places the return value in the designated location.
- Restores saved registers.
- Deallocates local storage.
- Restores the caller’s frame or stack pointer.
- Jumps to the saved return address.
A simplified sequence is:
The compiler and platform ABI determine which actions are performed by the caller, which by the callee, and which are optimized away.
Footnotes
-
Concepts Introduced in Chapter 7: Activation Records - Calling-sequence actions, storage allocation, access links, and displays. ↩
6. Recursion
Recursion requires a separate activation record for every active invocation. A procedure’s code may be shared, but its parameters, locals, return address, and intermediate state must be distinct for each call.
Consider:
For the call , the stack conceptually contains:
| Stack order | Invocation | Important local state |
|---|---|---|
| Bottom | factorial(3) | , return location |
| Above | factorial(2) | , return location |
| Above | factorial(1) | , return location |
| Top | factorial(0) | , return location |
Each invocation returns to a different caller location. If all invocations shared one frame, the value of and the return addresses would be overwritten.
Tail recursion
In tail recursion, the recursive call is the last computation. A compiler may transform it into iteration and reuse the current frame, provided language semantics and calling conventions permit this optimization.
Footnotes
-
Call stack - Overview of stack frames, return control, recursion, and access links. ↩
Conceptual frame growth during recursive factorial
Each active invocation requires a distinct activation record.
7. Dynamic links and static links
The two links solve different runtime problems.
Dynamic link: call history
Suppose the actual call sequence is:
Then the dynamic links are:
This chain follows the call history.
Static link: lexical nesting
Suppose the source nesting is:
1procedure Outer 2 procedure Middle 3 procedure Inner
If Inner accesses a variable declared in Outer, the runtime must follow the lexical nesting relationship. The static-link chain may be:
To find a variable declared two lexical levels outward, the runtime follows two static links and then applies the variable’s frame offset.
A recursive call makes the distinction especially important: the most recent caller and the lexically enclosing procedure need not be the same frame.
Footnotes
-
CSE 428 Lecture Notes 7.2 - Definition and purpose of static links. ↩
Common questions about activation records
8. Access links and displays
Access-link implementation
An access link points from the current frame to the frame of the immediately enclosing lexical procedure. To access a variable at a more distant nesting level, the runtime follows a chain of links.
If the current procedure is at nesting depth and the variable is declared at depth , the number of links followed is related to:
The exact counting convention varies by textbook and implementation, but the key principle is that greater lexical distance generally means more indirect references.
Display implementation
A display stores one pointer for each active lexical nesting level. Instead of following a linked chain, the runtime indexes the display directly.
| Technique | Nonlocal-variable access | Main advantage | Main cost |
|---|---|---|---|
| Static-link chain | Follow one or more links | Simple and flexible | Cost grows with nesting distance |
| Display | Index a nesting-level pointer | Usually constant-depth lookup | Calls must maintain display entries |
A display can reduce nonlocal access to an array lookup followed by a frame offset. However, procedure entry and exit must save and update the relevant display entry.
Footnotes
-
CSE 428 Lecture Notes 7.2 - Definition and purpose of static links. ↩
-
Concepts Introduced in Chapter 7: Activation Records - Comparison of access-link chains and display-based nonlocal access. ↩
A static link points toward the activation record of the lexically enclosing procedure. It is well suited to block-structured languages and follows the static nesting structure.
9. Storage allocation strategies
Activation records are one part of a broader runtime storage model.
Static allocation
With static allocation, storage is reserved before execution and remains available throughout the program. It is simple but does not naturally support an arbitrary number of recursive or simultaneous activations.
Stack allocation
With stack allocation, frames are created and reclaimed as calls begin and end. This is efficient and supports recursion.
Heap allocation
With heap allocation, activation-related data can survive beyond the return of its defining routine. This is important for closures, first-class functions, coroutines, and objects whose lifetimes are not properly nested.
Footnotes
-
Concepts Introduced in Chapter 7: Activation Records - Overview of static, stack, and heap storage strategies. ↩
Stack lifetime limitation
Returning the address of a purely stack-allocated local variable is unsafe because its activation record may be reclaimed immediately after return. Languages and compilers prevent this through restrictions, diagnostics, or heap promotion.
10. Activation records, closures, and escaping variables
A closure may be invoked after the routine that created it has returned.
Example conceptually:
1function makeCounter 2 local count = 0 3 4 function increment 5 count = count + 1 6 return count 7 8 return increment
The function increment uses count, although makeCounter may have already returned. A conventional stack-only activation record for makeCounter would no longer be valid. The compiler or runtime therefore creates a persistent environment, commonly on the heap, and stores the captured variable there.
This illustrates an important rule:
Stack allocation is safe when lifetimes are properly nested; heap allocation is needed when data escapes that nesting discipline.
11. Activation trees and call graphs
An activation tree represents the dynamic execution of a program. Each node is one activation, and a child node represents a call made by its parent.
For:
1main calls A 2A calls B 3A calls C
the activation tree is:
A call graph, in contrast, describes possible calling relationships in the program and may contain cycles due to recursion. An activation tree describes one particular execution and therefore contains concrete invocation instances.
Footnotes
-
Concepts Introduced in Chapter 7: Activation Records - Runtime call and activation concepts. ↩
Tracing activation records in an exam problem
- 1Step 1
List calls from the entry routine downward, such as main → P → Q → P.
- 2Step 2
Do not reuse the same frame for recursive calls. Label repeated calls separately, such as P₁ and P₂.
- 3Step 3
Place each invocation's parameters and locals in its own frame.
- 4Step 4
Point each frame to the frame of the routine that actually called it.
- 5Step 5
Use lexical nesting, not call order, to identify the enclosing frame.
- 6Step 6
For every call, record the instruction or source statement to which control returns.
- 7Step 7
Remove the top frame first, restore the caller's state, and continue at the saved return location.
12. Relationship to compiler implementation
The compiler must decide:
- Which values reside in registers.
- Which values require stack slots.
- How arguments and results are passed.
- Where the return address is stored.
- How frame pointers and stack pointers are managed.
- How nonlocal variables are accessed.
- Whether a frame can be omitted or reused.
- How exception handlers and debugging metadata are represented.
The generated machine code is commonly divided into:
- Prologue: establishes the new frame.
- Body: performs the routine’s computation.
- Epilogue: restores state and returns.
An optimizing compiler may use a frame-pointer omission optimization, where or another register is used directly for addressing. It may also inline a function, eliminating a separate call and activation record altogether.
Therefore, an activation record is best understood as a runtime and compiler abstraction. Its logical fields may exist even when no literal contiguous block with those fields is emitted.
13. Security and reliability considerations
Activation records are also relevant to system reliability and security.
- Incorrect bounds handling can overwrite return addresses or saved control state.
- Stack exhaustion can terminate a program or trigger a runtime exception.
- Calling-convention mismatches can corrupt arguments, registers, or return state.
- Unsafe use of pointers to expired stack data can produce undefined behavior.
- Exception handling may require metadata that identifies handlers and frame-unwinding actions.
Modern systems commonly use defenses such as stack canaries, non-executable stack policies, address-space randomization, and control-flow protections. These mechanisms do not change the conceptual purpose of activation records, but they protect sensitive control information stored near or within stack frames.
Footnotes
-
Calling Conventions - Stack-based procedure-call mechanisms and preservation of return state. ↩
Activation Records: Key Terms
Short-note answer framework
14. Model short note
An activation record, also called a stack frame, is a runtime data structure created for each invocation of a procedure or function. It stores the information required to execute that invocation and return control to its caller. Typical fields include the return value, actual parameters, return address, dynamic link, static or access link, saved machine status, local variables, and temporary values.
Activation records are commonly allocated on the runtime stack. A new record is created when a procedure is called and removed when the procedure returns. The return address identifies where the caller resumes, while the dynamic link points to the caller’s activation record. In languages with nested procedures and lexical scoping, a static link points to the activation record of the lexically enclosing procedure and permits access to nonlocal variables.
Activation records make recursion possible because every recursive call receives a separate frame containing its own parameters, local variables, and return address. The compiler manages the record through a calling sequence, a callee prologue, a procedure body, and a return epilogue. Although the conceptual fields are standard, their physical layout depends on the target architecture, ABI, programming language, and compiler optimizations. Data that outlives its defining call, such as captured variables in closures, may require heap allocation rather than ordinary stack allocation.
Footnotes
-
Activation Records/Stack Frames - Princeton University - Lecture material defining activation records, their lifetime, recursion, dynamic links, and static links. ↩
-
Activation Records - Summary of activation-record fields and distinction between access and control links. ↩
Knowledge Check
Which statement best defines an activation record?
Explore Related Topics
Startup Fundamentals
The course outlines core concepts and stages to build, fund, and scale a startup.
- Define the problem, craft a value proposition, and validate with an MVP.
- Confirm product‑market fit using the “disappointed customer” rule and .
- Monitor burn rate, maintain a 12‑18 month runway, and control cash flow.
- Use a cap table to track equity, prevent over‑dilution, and prepare transparent pitch decks.
Expansion and Extension of Memory: A Comparative Study
Variable Inductance and Capacitance Transducers