private void RunCore( ControlFlowGraph cfg, SortedSet <int> worklist, SortedSet <int> pendingBlocksNeedingAtLeastOnePass, TAnalysisData initialAnalysisDataOpt, DataFlowAnalysisResultBuilder <TAnalysisData> resultBuilder, PooledHashSet <BasicBlock> uniqueSuccessors, PooledDictionary <int, List <BranchWithInfo> > finallyBlockSuccessorsMap, PooledDictionary <ControlFlowRegion, TAnalysisData> catchBlockInputDataMap, PooledDictionary <int, TAnalysisData> inputDataFromInfeasibleBranchesMap, PooledDictionary <int, (int Ordinal, ControlFlowConditionKind BranchKind)?> blockToUniqueInputFlowMap,
private TAnalysisResult Run(TAnalysisContext analysisContext) { var cfg = analysisContext.ControlFlowGraph; var resultBuilder = new DataFlowAnalysisResultBuilder <TAnalysisData>(); var uniqueSuccessors = PooledHashSet <BasicBlock> .GetInstance(); var finallyBlockSuccessorsMap = PooledDictionary <int, List <BranchWithInfo> > .GetInstance(); var catchBlockInputDataMap = PooledDictionary <ControlFlowRegion, TAnalysisData> .GetInstance(); var inputDataFromInfeasibleBranchesMap = PooledDictionary <int, TAnalysisData> .GetInstance(); var unreachableBlocks = PooledHashSet <int> .GetInstance(); var worklist = new SortedSet <int>(); var pendingBlocksNeedingAtLeastOnePass = new SortedSet <int>(cfg.Blocks.Select(b => b.Ordinal)); // Map from Ordinal -> (Ordinal, ControlFlowConditionKind)? with following semantics: // 1. Key is a valid basic block ordinal. // 2. Value tuple indicates the following: // a. Non-null tuple value: Indicates a unique branch entering the block, with following tuple values: // i. Ordinal of the single unique block from which analysis data has been transferred into the Key, // which is normally a predecessor but can be a non-predecessor block for finally/catch. // ii. ControlFlowConditionKind indicating the nature of branch, i.e. conditional or fall through. // This is required as CFG can have both conditional and fall through branches // with the same source and destination blocks. // b. Null tuple value: Block had analysis data flowing into it from multiple different branches. // // This map allows us to optimize the number of merge operations. We can avoid merge and directly // overwrite analysis data into a successor if successor block has no entry or entry with non-null tuple value // with the matching input branch. var blockToUniqueInputFlowMap = PooledDictionary <int, (int Ordinal, ControlFlowConditionKind BranchKind)?> .GetInstance(); // Map from basic block ordinals that are destination of back edge(s) to the minimum block ordinal that dominates it, // i.e. for every '{key, value}' pair in the dictionary, 'key' is the destination of at least one back edge // and 'value' is the minimum ordinal such that there is no back edge to 'key' from any basic block with ordinal > 'value'. var loopRangeMap = PooledDictionary <int, int> .GetInstance(); ComputeLoopRangeMap(cfg, loopRangeMap); TAnalysisData normalPathsExitBlockData = null, exceptionPathsExitBlockDataOpt = null; try { // Add each basic block to the result. foreach (var block in cfg.Blocks) { resultBuilder.Add(block); } var entry = cfg.GetEntry(); // Initialize the input of the entry block. // For context sensitive inter-procedural analysis, use the provided initial analysis data. // Otherwise, initialize with the default bottom value of the analysis domain. var initialAnalysisDataOpt = analysisContext.InterproceduralAnalysisDataOpt?.InitialAnalysisData; UpdateInput(resultBuilder, entry, GetClonedAnalysisDataOrEmptyData(initialAnalysisDataOpt)); // Add the block to the worklist. worklist.Add(entry.Ordinal); RunCore(cfg, worklist, pendingBlocksNeedingAtLeastOnePass, initialAnalysisDataOpt, resultBuilder, uniqueSuccessors, finallyBlockSuccessorsMap, catchBlockInputDataMap, inputDataFromInfeasibleBranchesMap, blockToUniqueInputFlowMap, loopRangeMap, exceptionPathsAnalysisPostPass: false); normalPathsExitBlockData = resultBuilder.ExitBlockOutputData; if (analysisContext.ExceptionPathsAnalysis) { // Clone and save exit block data normalPathsExitBlockData = AnalysisDomain.Clone(normalPathsExitBlockData); OperationVisitor.ExecutingExceptionPathsAnalysisPostPass = true; foreach (var block in cfg.Blocks) { blockToUniqueInputFlowMap[block.Ordinal] = null; // Skip entry block analysis. if (block.Kind == BasicBlockKind.Entry) { continue; } if (block.IsReachable) { worklist.Add(block.Ordinal); } else { pendingBlocksNeedingAtLeastOnePass.Add(block.Ordinal); } } RunCore(cfg, worklist, pendingBlocksNeedingAtLeastOnePass, initialAnalysisDataOpt, resultBuilder, uniqueSuccessors, finallyBlockSuccessorsMap, catchBlockInputDataMap, inputDataFromInfeasibleBranchesMap, blockToUniqueInputFlowMap, loopRangeMap, exceptionPathsAnalysisPostPass: true); exceptionPathsExitBlockDataOpt = resultBuilder.ExitBlockOutputData; OperationVisitor.ExecutingExceptionPathsAnalysisPostPass = false; } var mergedDataForUnhandledThrowOperationsOpt = OperationVisitor.GetMergedDataForUnhandledThrowOperations(); var dataflowAnalysisResult = resultBuilder.ToResult(ToBlockResult, OperationVisitor.GetStateMap(), OperationVisitor.GetPredicateValueKindMap(), OperationVisitor.GetReturnValueAndPredicateKind(), OperationVisitor.InterproceduralResultsMap, resultBuilder.EntryBlockOutputData, normalPathsExitBlockData, exceptionPathsExitBlockDataOpt, mergedDataForUnhandledThrowOperationsOpt, OperationVisitor.AnalysisDataForUnhandledThrowOperations, cfg, OperationVisitor.ValueDomain.UnknownOrMayBeValue); return(ToResult(analysisContext, dataflowAnalysisResult)); } finally { resultBuilder.Dispose(); uniqueSuccessors.Free(); finallyBlockSuccessorsMap.Free(); catchBlockInputDataMap.Values.Dispose(); catchBlockInputDataMap.Free(); inputDataFromInfeasibleBranchesMap.Values.Dispose(); inputDataFromInfeasibleBranchesMap.Free(); unreachableBlocks.Free(); blockToUniqueInputFlowMap.Free(); loopRangeMap.Free(); } }