Skip to main content

Optimization Passes

React Compiler includes numerous optimization passes that transform code at different stages of compilation. This guide covers the major passes and their purposes.

Pass Categories

Optimization passes are organized into several categories:
  1. HIR Construction & SSA (passes 1-3)
  2. Early Optimization (passes 4-5)
  3. Type & Effect Inference (passes 6-10)
  4. Reactive Scope Construction (passes 11-20)
  5. Reactive Function Optimization (passes 22-29)
  6. Code Generation (passes 30-31)
  7. Optional Transformations (feature-gated)

Early Optimization Passes

Constant Propagation

File: src/Optimization/ConstantPropagation.ts Implements sparse conditional constant propagation (SCCP). What it does:
  • Replaces variables with known constant values
  • Evaluates constant expressions at compile time
  • Simplifies conditional branches with constant tests
Example:

Dead Code Elimination

File: src/Optimization/DeadCodeElimination.ts Removes unreferenced instructions and unreachable code. What it does:
  • Identifies unreferenced values
  • Removes instructions with no side effects that aren’t used
  • Eliminates unreachable basic blocks
Example:

Instruction Reordering

File: src/Optimization/InstructionReordering.ts
Flag: enableInstructionReordering
Reorders instructions to improve memoization opportunities. What it does:
  • Moves independent instructions earlier
  • Groups related computations
  • Improves reactive scope boundaries

Type Inference

InferTypes

File: src/TypeInference/InferTypes.ts Infers types through constraint-based unification. Type Categories:
Example:

Effect Inference

AnalyseFunctions

File: src/Inference/AnalyseFunctions.ts Analyzes nested function expressions and arrow functions. What it does:
  • Determines what values functions capture
  • Identifies function effects (pure, mutating, etc.)
  • Marks functions that can be memoized

InferMutationAliasingEffects

File: src/Inference/InferMutationAliasingEffects.ts Infers mutation and aliasing effects through abstract interpretation. Effects tracked: Data Flow:
  • Capture a -> b: Value a captured into b
  • Alias a -> b: b aliases a
  • Assign a -> b: Direct assignment
  • Freeze value: Make value immutable
Mutation:
  • Mutate value: Direct mutation
  • MutateTransitive value: Transitive mutation
  • MutateConditionally value: Conditional mutation
Special:
  • Render place: Used in JSX/render context
  • Impure place: Contains impure value (Date.now(), ref.current)
Example:

InferReactivePlaces

File: src/Inference/InferReactivePlaces.ts Marks which places are reactive (need memoization). Reactive categories:
  • Component props
  • Hook return values
  • Values derived from reactive values
  • Values used in JSX (render context)

Reactive Scope Passes

InferReactiveScopeVariables

File: src/ReactiveScopes/InferReactiveScopeVariables.ts Groups instructions that should invalidate together. Algorithm:
  1. Build value dependency graph
  2. Find strongly connected components
  3. Create scope boundaries
  4. Compute scope dependencies
Example:

Scope Alignment Passes

AlignMethodCallScopes

File: src/ReactiveScopes/AlignMethodCallScopes.ts Aligns method call scopes with their receivers.

AlignObjectMethodScopes

File: src/ReactiveScopes/AlignObjectMethodScopes.ts Aligns object method definitions to scope boundaries.

AlignReactiveScopesToBlockScopesHIR

File: src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts Ensures reactive scopes respect control flow boundaries.

Scope Merging

MergeOverlappingReactiveScopesHIR

File: src/HIR/MergeOverlappingReactiveScopesHIR.ts Merges scopes with overlapping ranges. Example:

MergeReactiveScopesThatInvalidateTogether

File: src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts Merges scopes that always invalidate together.

Scope Pruning

FlattenReactiveLoopsHIR

File: src/ReactiveScopes/FlattenReactiveLoopsHIR.ts Prunes reactive scopes inside loops (can’t memoize loop iterations).

FlattenScopesWithHooksOrUseHIR

File: src/ReactiveScopes/FlattenScopesWithHooksOrUseHIR.ts Removes scopes containing hook calls (hooks can’t be conditional).

PruneNonEscapingScopes

File: src/ReactiveScopes/PruneNonEscapingScopes.ts Removes scopes for values that don’t escape the function.

PruneNonReactiveDependencies

File: src/ReactiveScopes/PruneNonReactiveDependencies.ts Removes non-reactive dependencies from scope deps.

PruneAlwaysInvalidatingScopes

File: src/ReactiveScopes/PruneAlwaysInvalidatingScopes.ts Removes scopes that always recompute.

Dependency Optimization

PropagateScopeDependenciesHIR

File: src/HIR/PropagateScopeDependenciesHIR.ts Computes minimal precise dependencies for scopes. Example:

Optional Transformations

Drop Manual Memoization

File: src/Inference/DropManualMemoization.ts
Condition: !enablePreserveExistingManualUseMemo
Removes manual useMemo/useCallback calls.

Transform Fire

File: src/Transform/TransformFire.ts
Flag: enableFire
Transforms fire() calls for effect callbacks.

Lower Context Access

File: src/Optimization/LowerContextAccess.ts
Flag: lowerContextAccess
Optimizes React context access with inline selectors.

Outline JSX

File: src/Optimization/OutlineJsx.ts
Flag: enableJsxOutlining
Extracts static JSX into separate components.

Outline Functions

File: src/Optimization/OutlineFunctions.ts
Flag: enableFunctionOutlining
Extracts pure function expressions to module scope.

Optimize for SSR

File: src/Optimization/OptimizeForSSR.ts
Condition: outputMode === 'ssr'
Applies server-side rendering optimizations.

Inline JSX Transform

File: src/Optimization/InlineJsxTransform.ts
Flag: inlineJsxTransform
Inlines JSX as object literals instead of runtime calls.

Code Generation Passes

Rename Variables

File: src/ReactiveScopes/RenameVariables.ts Ensures unique variable names in output.

Promote Used Temporaries

File: src/ReactiveScopes/PromoteUsedTemporaries.ts Promotes compiler temporaries to named variables when referenced across scopes.

Codegen Reactive Function

File: src/ReactiveScopes/CodegenReactiveFunction.ts Generates final JavaScript with memoization:

Pass Ordering

Passes run in a specific order to ensure correctness:
  1. Lower → Convert to HIR
  2. EnterSSA → SSA form
  3. Type/Effect Inference → Understand data flow
  4. Scope Inference → Find memoization boundaries
  5. Scope Optimization → Prune and merge scopes
  6. Codegen → Generate output
Changing the order can break correctness guarantees.

Performance Impact

Pass Complexity

Typical Times

  • Small component (less than 100 LOC): 1-2ms
  • Medium component (100-500 LOC): 2-5ms
  • Large component (500+ LOC): 5-20ms

Next Steps

Architecture

Understand the full pipeline

HIR

Learn about the IR

Configuration

Enable/disable passes

Contributing

Contribute optimizations