Ejemplo n.º 1
0
        private DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> Run(ControlFlowGraph cfg)
        {
            var resultBuilder = new DataFlowAnalysisResultBuilder <TAnalysisData>();

            // Add each basic block to the result.
            foreach (var block in cfg.Blocks)
            {
                resultBuilder.Add(block);
            }

            var worklist = new Queue <BasicBlock>();
            var entry    = GetEntry(cfg);

            // Initialize the output of the initial block
            // with the default abstract value of the domain.
            UpdateOutput(resultBuilder, entry, AnalysisDomain.Bottom);

            // Add all successor blocks of the initial
            // block to be processed.
            EnqueueRange(worklist, GetSuccessors(entry));

            while (worklist.Count > 0)
            {
                // Get the next block to process
                // and its associated result.
                var block = worklist.Dequeue();

                // Get the outputs of all predecessor blocks of the current block.
                var inputs = GetPredecessors(block).Select(b => GetOutput(resultBuilder[b]));

                // Merge all the outputs to get the new input of the current block.
                var input = AnalysisDomain.Merge(inputs);

                // Compare the previous input with the new input.
                var compare = AnalysisDomain.Compare(GetInput(resultBuilder[block]), input);

                // The newly computed abstract values for each basic block
                // must be always greater or equal than the previous value
                // to ensure termination.
                Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                // Is old input value < new input value ?
                if (compare < 0)
                {
                    // The newly computed value is greater than the previous value,
                    // so we need to update the current block result's
                    // input values with the new ones.
                    UpdateInput(resultBuilder, block, AnalysisDomain.Clone(input));

                    // Flow the new input through the block to get a new output.
                    var output = Flow(block, input);

                    // Compare the previous output with the new output.
                    compare = AnalysisDomain.Compare(GetOutput(resultBuilder[block]), output);

                    // The newly computed abstract values for each basic block
                    // must be always greater or equal than the previous value
                    // to ensure termination.
                    Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                    // Is old output value < new output value ?
                    if (compare < 0)
                    {
                        // The newly computed value is greater than the previous value,
                        // so we need to update the current block result's
                        // output values with the new ones.
                        UpdateOutput(resultBuilder, block, output);

                        // Since the new output value is different than the previous one,
                        // we need to propagate it to all the successor blocks of the current block.
                        EnqueueRange(worklist, GetSuccessors(block));
                    }
                }
            }

            return(resultBuilder.ToResult(ToResult, OperationVisitor.GetStateMap()));
        }
Ejemplo n.º 2
0
        private DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> Run(ControlFlowGraph cfg, DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> seedResultOpt)
        {
            var resultBuilder = new DataFlowAnalysisResultBuilder <TAnalysisData>();

            // Add each basic block to the result.
            foreach (var block in cfg.Blocks)
            {
                resultBuilder.Add(block);
            }

            var worklist = new Queue <BasicBlock>();
            var pendingBlocksNeedingAtLeastOnePass = new HashSet <BasicBlock>(cfg.Blocks);
            var entry = GetEntry(cfg);

            // Are we computing the analysis data from scratch?
            if (seedResultOpt == null)
            {
                // Initialize the input of the initial block
                // with the default abstract value of the domain.
                UpdateInput(resultBuilder, entry, AnalysisDomain.Bottom);
            }
            else
            {
                // Initialize the input and output of every block
                // with the previously computed value.
                foreach (var block in cfg.Blocks)
                {
                    UpdateInput(resultBuilder, block, GetInputData(seedResultOpt[block]));
                }
            }

            // Add the block to the worklist.
            worklist.Enqueue(entry);

            while (worklist.Count > 0 || pendingBlocksNeedingAtLeastOnePass.Count > 0)
            {
                // Get the next block to process
                // and its associated result.
                var block = worklist.Count > 0 ? worklist.Dequeue() : pendingBlocksNeedingAtLeastOnePass.ElementAt(0);
                var needsAtLeastOnePass = pendingBlocksNeedingAtLeastOnePass.Remove(block);

                // Get the outputs of all predecessor blocks of the current block.
                var inputs = GetPredecessors(block).Select(b => GetOutput(resultBuilder[b]));

                // Merge all the outputs to get the new input of the current block.
                var input = AnalysisDomain.Merge(inputs);

                // Merge might return one of the original input values if only one of them is a valid non-null value.
                if (inputs.Any(i => ReferenceEquals(input, i)))
                {
                    input = AnalysisDomain.Clone(input);
                }

                // Temporary workaround due to lack of *real* CFG
                // TODO: Remove the below if statement once we move to compiler's CFG
                // https://github.com/dotnet/roslyn-analyzers/issues/1567
                if (block.Kind == BasicBlockKind.Exit &&
                    OperationVisitor.MergedAnalysisDataAtReturnStatements != null)
                {
                    input = AnalysisDomain.Merge(input, OperationVisitor.MergedAnalysisDataAtReturnStatements);
                }

                // Compare the previous input with the new input.
                if (!needsAtLeastOnePass)
                {
                    int compare = AnalysisDomain.Compare(GetInput(resultBuilder[block]), input);

                    // The newly computed abstract values for each basic block
                    // must be always greater or equal than the previous value
                    // to ensure termination.
                    Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                    // Is old input value >= new input value
                    if (compare >= 0)
                    {
                        continue;
                    }
                }

                // The newly computed value is greater than the previous value,
                // so we need to update the current block result's
                // input values with the new ones.
                UpdateInput(resultBuilder, block, AnalysisDomain.Clone(input));

                // Flow the new input through the block to get a new output.
                var output = Flow(OperationVisitor, block, input);

                // Compare the previous output with the new output.
                if (!needsAtLeastOnePass)
                {
                    int compare = AnalysisDomain.Compare(GetOutput(resultBuilder[block]), output);

                    // The newly computed abstract values for each basic block
                    // must be always greater or equal than the previous value
                    // to ensure termination.
                    Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                    // Is old output value >= new output value ?
                    if (compare >= 0)
                    {
                        continue;
                    }
                }

                // The newly computed value is greater than the previous value,
                // so we need to update the current block result's
                // output values with the new ones.
                UpdateOutput(resultBuilder, block, output);

                // Since the new output value is different than the previous one,
                // we need to propagate it to all the successor blocks of the current block.
                EnqueueRange(worklist, GetSuccessors(block));
            }

            return(resultBuilder.ToResult(ToResult, OperationVisitor.GetStateMap(),
                                          OperationVisitor.GetPredicateValueKindMap(), OperationVisitor.GetMergedDataForUnhandledThrowOperations(),
                                          cfg, OperationVisitor.ValueDomain.UnknownOrMayBeValue));
        }