analyze method

AnalysisResult<D> analyze(
  1. ControlFlowGraph cfg
)

Analyzes a CFG and returns the abstract state at each program point.

Implementation

AnalysisResult<D> analyze(ControlFlowGraph cfg) {
  final entryStates = <int, AbstractState<D>>{};
  final exitStates = <int, AbstractState<D>>{};
  var wideningApplied = false;
  var iterations = 0;

  // Initialize all blocks with bottom state
  for (final block in cfg.blocks) {
    entryStates[block.id] = AbstractState<D>(_defaultValue);
    exitStates[block.id] = AbstractState<D>(_defaultValue);
    _blockVisitCount[block.id] = 0;
  }

  // Worklist algorithm using Queue for O(1) dequeue
  final worklist = Queue<BasicBlock>()..add(cfg.entry);
  final inWorklist = <int>{cfg.entry.id};

  while (worklist.isNotEmpty && iterations < maxIterations) {
    iterations++;

    final block = worklist.removeFirst();
    inWorklist.remove(block.id);

    // Compute entry state by joining predecessor exit states
    AbstractState<D> entryState;
    if (block.predecessors.isEmpty) {
      entryState = AbstractState<D>(_defaultValue);
    } else {
      entryState = block.predecessors
          .map((p) => exitStates[p.id]!)
          .reduce((a, b) => a.join(b));
    }

    // Apply widening if we've visited this block too many times
    _blockVisitCount[block.id] = (_blockVisitCount[block.id] ?? 0) + 1;
    if (_blockVisitCount[block.id]! > wideningThreshold) {
      entryState = entryStates[block.id]!.widen(entryState);
      wideningApplied = true;
    }

    // Check if entry state changed
    final oldEntryState = entryStates[block.id]!;
    if (_statesEqual(entryState, oldEntryState) &&
        _blockVisitCount[block.id]! > 1) {
      continue; // No change, skip processing
    }

    entryStates[block.id] = entryState;

    // Transfer function: process instructions
    final exitState = _transferBlock(block, entryState, exitStates);
    exitStates[block.id] = exitState;

    // Add successors to worklist
    for (final succ in block.successors) {
      if (!inWorklist.contains(succ.id)) {
        worklist.add(succ);
        inWorklist.add(succ.id);
      }
    }
  }

  // Apply narrowing phase to recover precision after widening
  var narrowingIterations = 0;
  var narrowingApplied = false;
  if (wideningApplied) {
    narrowingIterations = _applyNarrowing(cfg, entryStates, exitStates);
    narrowingApplied = narrowingIterations > 0;
  }

  return AnalysisResult(
    entryStates: entryStates,
    exitStates: exitStates,
    iterations: iterations,
    wideningApplied: wideningApplied,
    narrowingApplied: narrowingApplied,
    narrowingIterations: narrowingIterations,
  );
}