HIR and SSA Representation
The React Compiler uses a specialized High-level Intermediate Representation (HIR) to analyze and optimize your components. By transforming standard JavaScript into HIR and subsequently into Static Single Assignment (SSA) form, the compiler can perform sophisticated data-flow analysis to determine exactly when and how to apply memoization.
High-level Intermediate Representation (HIR)
HIR is a representation of your code designed specifically for React-aware optimizations. While a standard Abstract Syntax Tree (AST) represents the nested structure of the code, HIR flattens this structure into a sequence of instructions organized into blocks.
Core Concepts
The HIR consists of several key structures:
- HIRFunction: The top-level representation of a React component or Hook. It contains the function's parameters, environment configuration, and a control-flow graph.
- Basic Blocks: A sequence of instructions with exactly one entry point and one exit point. Blocks are connected to form the control-flow graph (CFG).
- Instructions: The individual operations within a block (e.g., function calls, property loads, assignments).
- Identifiers and Places: Every value in HIR is tracked via an
Identifier. APlacerepresents a specific usage of an identifier at a particular location in the code.
Why HIR?
Standard JavaScript is highly dynamic and flexible, which makes it difficult to reason about side effects and dependencies. HIR provides a "normalized" view of the code where:
- Control flow is explicit (conditionals and loops are broken into blocks).
- Value dependencies are clear.
- React-specific patterns (like Hooks and JSX) are first-class citizens in the analysis.
Static Single Assignment (SSA)
React Compiler converts HIR into Static Single Assignment (SSA) form. In SSA, every variable (Identifier) is assigned exactly once. If a variable is reassigned in the source code, the compiler creates a new version of that identifier (e.g., x_0, x_1).
Benefits of SSA for React
SSA is critical for the compiler's Escape Analysis. Because every identifier is unique and assigned only once, the compiler can easily track:
- Definitions: Exactly where a value was created.
- Uses: Exactly where a value is consumed.
- Mutations: Which instructions might modify a value's underlying data.
This precision allows the compiler to safely group instructions into Reactive Scopes—the units of memoization—without fear of stale values or hidden side effects.
Analysis and Pruning
A primary goal of HIR analysis is to identify which values actually need to be memoized. Not every object or array created in a component requires useMemo.
Escape Analysis
The compiler performs "Escape Analysis" to determine if a value "escapes" the current component. A value escapes if it is:
- Returned from the component.
- Passed as an argument to a Hook (which might store the reference).
- Passed as a prop to a child component.
If a value does not escape and does not affect an escaping value, the compiler may prune its reactive scope to reduce runtime overhead.
Interleaved Dependencies
HIR allows the compiler to handle complex cases where independent values are mutated in an interleaved way.
function Component(props) {
// 'a' is a dependency of 'b'
const a = [props.a];
// 'b' and 'c' are interleaved in the source code
const b = [];
const c = {};
c.a = a;
b.push(props.b);
return b; // Only 'b' escapes
}
In this example, even if c doesn't escape, HIR analysis ensures that a is correctly memoized because it is a dependency of c, which is interleaved with the creation of the escaping value b. This prevents unnecessary invalidations of b.
Compiler Validations
The HIR also serves as the foundation for the compiler's validation suite. Because the representation is structured, the compiler can enforce React's rules more strictly than a standard linter.
For example, the compiler uses HIR to perform Capitalized Call Validation. In React, capitalized functions are typically components and should be invoked with JSX (<Component />), not called as regular functions (Component()). The HIR allows the compiler to track global bindings and property loads to identify these calls and issue errors:
// HIR analysis catches this as a potential error
function Component() {
const x = SomeFunc(); // Error: Capitalized functions are reserved for components
return <x />;
}
By leveraging HIR and SSA, the React Compiler moves beyond simple syntax transformation and performs true semantic analysis of your React logic.