コード例 #1
0
        public GraphDataFlowBlockNode([NotNull] GraphMethodRoot methodRoot) : base(methodRoot)
        {
            StrongConnectivityNode = new ComponentNode <GraphDataFlowBlockNode>(this);
            ((IComponentNodeItem <GraphDataFlowBlockNode>) this).SubscribeToStrongConnectivityNodePropertyChanged();

            RefreshText();
        }
コード例 #2
0
        private static void Print(GraphMethodRoot methodRoot)
        {
            var terminal = methodRoot.Start
                           .IterateGraphNodesRecursive(true)
                           .Where(x => !x.AllOutgoing.Any())
                           .ToArray();

            foreach (var graphNode in terminal)
            {
                switch (graphNode)
                {
                case GraphDataFlowReturnNode graphReturnNode:
                    Print(graphReturnNode.EnterAnalysisContext);
                    break;

                case GraphDataFlowBlockNode graphDataFlowBlockNode:
                    var expressionNode = graphDataFlowBlockNode.Body.Last();
                    Print(expressionNode.ExitAnalysisContext);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(graphNode));
                }
            }
        }
コード例 #3
0
        public GraphDataFlowReturnNode(GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression) : base(
                methodRoot, expression)
        {
            StrongConnectivityNode = new ComponentNode <GraphDataFlowReturnNode>(this);
            ((IComponentNodeItem <GraphDataFlowReturnNode>) this).SubscribeToStrongConnectivityNodePropertyChanged();

            RefreshText();
        }
コード例 #4
0
        private void BuildGraphForMethod(MethodDefinition methodDefinition, ICollection <GraphMethodRoot> methodRoots)
        {
            if (methodRoots.Any(x => x.Name == methodDefinition.Name))
            {
                Log.Warning("{MethodName} is already present in this analysis session", methodDefinition.Name);
                return;
            }

            var methodRoot = new GraphMethodRoot(methodDefinition.Name)
            {
                Code = methodDefinition.Code
            };

            methodRoots.Add(methodRoot);

            methodRoot.Arguments.AddRange(methodDefinition.Arguments);
            methodRoot.ParameterVariables.AddRange(methodDefinition.Body.LocalVariables.OfType <ParameterVariable>());

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            BuildGraphForBlock(methodDefinition.Body, methodRoot);

            SplitBlocksAtMethodJumps(methodRoot);

            CalculateIncoming(methodRoot.Start);

            for (var i = 1; i <= 50; i++)
            {
                var res = SimplifyGraph(methodRoot);
                if (!res)
                {
                    break;
                }
            }

            CalculateIncoming(methodRoot.Start);

            var dataFlowGraphBuilder = new DataFlowGraphBuilder(methodRoot);

            dataFlowGraphBuilder.Convert();

            CallGraphBuilder.Instance.RegisterMethod(methodRoot);

            var analysis = new IntraProceduralDataFlowAnalyzer(methodRoot);

            analysis.Analyze();

            stopwatch.Stop();
            Log.Information("DFG: {Name}: processing: {Time}", methodRoot.Name, stopwatch.Elapsed);
        }
コード例 #5
0
        public GraphDataFlowExpressionNode(
            GraphMethodRoot methodRoot,
            [CanBeNull] ExpressionBase expression,
            [NotNull] GraphDataFlowBlockNode blockNode
            ) : base(methodRoot, expression)
        {
            BlockNode           = blockNode;
            ExitAnalysisContext = new AnalysisContext(EnterAnalysisContext);

            SubscribeToAnalysisContextChanges(ExitAnalysisContext);

            RefreshText();
        }
コード例 #6
0
 private void GraphMethodRootOnStartChanged(GraphMethodRoot sender, GraphMethodRootStartChangedEventArgs e)
 {
     lock (_currentMethodRootsLock)
     {
         if (e.OldValue != null)
         {
             _currentMethodRootsNodeCollection.Remove(e.OldValue);
         }
         if (e.NewValue != null)
         {
             _currentMethodRootsNodeCollection.Add(e.NewValue);
         }
     }
 }
        private bool SimplifyGraph(GraphMethodRoot methodNode)
        {
            var oldStart = methodNode.Start;

            var res = SimplifyNode(oldStart);

            if (res)
            {
                if (oldStart is GraphControlFlowBlockNode oldStartBlockNode)
                {
                    methodNode.Start = oldStartBlockNode.Outgoing;
                    Log.Verbose(
                        "CFG: {MethodName}: simplified away start point {Node}, new start point is {NewNode}",
                        methodNode.Name,
                        oldStart,
                        methodNode.Start
                        );
                }
                else
                {
                    Log.Error(
                        "CFG: {MethodName}: simplified away start point {Node}, but it wasn't {TypeName}",
                        methodNode.Name,
                        oldStart,
                        nameof(GraphControlFlowBlockNode)
                        );
                }
            }

            var graphNodes = methodNode.Start.IterateGraphNodesRecursive(false).ToArray();

            foreach (var graphNode in graphNodes)
            {
                res = SimplifyNode(graphNode) || res;
            }

            return(res);

            bool SimplifyNode(GraphNode graphNode)
            {
                return(graphNode switch
                {
                    null => throw new ArgumentOutOfRangeException(nameof(graphNode)),
                    GraphControlFlowBlockNode blockNode => SimplifyGraph(blockNode),
                    GraphControlFlowConditionalNode _ => false,
                    GraphControlFlowReturnNode _ => false,
                    _ => throw new ArgumentOutOfRangeException(nameof(graphNode))
                });
            }
コード例 #8
0
        private void BuildGraphForBlock([NotNull] SimpleCompoundStatement compoundStatement,
                                        [NotNull] GraphMethodRoot methodRoot)
        {
            var graphNode = new GraphControlFlowBlockNode(methodRoot);

            methodRoot.Start           = graphNode;
            var(preemptiveExits, next) = AddStatementToGraphNode(compoundStatement,
                                                                 methodRoot,
                                                                 graphNode,
                                                                 null,
                                                                 null);

            if (next != null)
            {
                next.Outgoing = new GraphControlFlowReturnNode(methodRoot, null, true);
            }
        }
        private void AssignParentsToContexts(GraphMethodRoot methodNode)
        {
            var graphNodes = methodNode.Start.IterateGraphNodesRecursive(true).ToArray();

            foreach (var graphNode in graphNodes)
            {
                switch (graphNode)
                {
                case null:
                    throw new ArgumentNullException(nameof(graphNode));

                case GraphDataFlowExpressionNodeBase dataFlowExpressionNode:
                    foreach (var parentNode in dataFlowExpressionNode.Incoming)
                    {
                        AssignParentsToContexts(dataFlowExpressionNode, dataFlowExpressionNode, parentNode);
                    }

                    break;

                case GraphDataFlowBlockNode graphDataFlowBlockNode:
                    if (graphDataFlowBlockNode.Body.Count > 0)
                    {
                        var firstExpressionNode = graphDataFlowBlockNode.Body[0];

                        foreach (var parentNode in graphDataFlowBlockNode.Incoming)
                        {
                            AssignParentsToContexts(firstExpressionNode, graphDataFlowBlockNode, parentNode);
                        }

                        for (var i = 1; i < graphDataFlowBlockNode.Body.Count; i++)
                        {
                            var previous = graphDataFlowBlockNode.Body[i - 1];
                            var current  = graphDataFlowBlockNode.Body[i];
                            current.EnterAnalysisContext.AddParent(previous.ExitAnalysisContext);
                        }
                    }

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(graphNode));
                }
            }
        }
        private void SplitBlocksAtMethodJumps(GraphMethodRoot methodRoot)
        {
            var graphNodes = methodRoot.Start.IterateGraphNodesRecursive(true).ToArray();

            foreach (var graphNode in graphNodes)
            {
                switch (graphNode)
                {
                case null:
                    throw new ArgumentNullException(nameof(graphNode));

                case GraphControlFlowBlockNode graphBlockNode:
                {
                    var currentBlockNode = graphBlockNode;
                    while (currentBlockNode != null)
                    {
                        var index = 0;
                        for (; index < currentBlockNode.Body.Count; index++)
                        {
                            var expressionBase = currentBlockNode.Body[index];
                            var functionCall   = ScanExpressionForFunctionCalls(expressionBase.Expression);
                            if (functionCall == null)
                            {
                                continue;
                            }

                            if (index == currentBlockNode.Body.Count - 1)
                            {
                                continue;
                            }

                            // split
                            var node = new GraphControlFlowBlockNode(methodRoot)
                            {
                                Outgoing = currentBlockNode.Outgoing
                            };

                            var moveStart = index + 1;
                            var moveCount = currentBlockNode.Body.Count - moveStart;

                            foreach (var expressionNode in currentBlockNode.Body.ToArray()[moveStart..(moveStart + moveCount)])
 public GraphControlFlowExpressionNode(
     [NotNull] GraphMethodRoot methodRoot,
     [NotNull] ExpressionBase expression
     ) : base(methodRoot, expression)
 {
 }
コード例 #12
0
        AddStatementToGraphNode(StatementBase statement,
                                GraphMethodRoot methodRoot,
                                GraphControlFlowBlockNode target,
                                GraphNode continueTarget,
                                GraphNode breakTarget)
        {
            switch (statement)
            {
            case ContinueStatement _:
                target.Outgoing = continueTarget;
                return(Array.Empty <GraphNode>(), null);

            case ForIterationStatement forStatement:
            {
                var processConditional = ProcessConditional(forStatement);
                if (!processConditional.HasValue)
                {
                    return(Array.Empty <GraphNode>(), target);
                }

                var(conditionalStartNode, conditionalNode) = processConditional.Value;

                var preemptiveExits = new List <GraphNode>();

                // block inside FOR that contains incrementors and stuff
                var iterationExpressionBlock = new GraphControlFlowBlockNode(methodRoot);

                // block after FOR
                var nextBlock = new GraphControlFlowBlockNode(methodRoot);

                {
                    foreach (var expression in forStatement.IterationExpression)
                    {
                        iterationExpressionBlock.Body.Add(
                            new GraphControlFlowExpressionNode(methodRoot, expression)
                            );
                    }

                    iterationExpressionBlock.Outgoing = conditionalStartNode;
                }

                {
                    var trueBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.TrueOutgoing = trueBlock;

                    var(truePreemptiveExits, trueNext) = AddStatementToGraphNode(forStatement.Block,
                                                                                 methodRoot,
                                                                                 trueBlock,
                                                                                 iterationExpressionBlock,
                                                                                 nextBlock);

                    preemptiveExits.AddRange(truePreemptiveExits);

                    if (trueNext != null)
                    {
                        trueNext.Outgoing = iterationExpressionBlock;
                    }
                }

                conditionalNode.FalseOutgoing = nextBlock;

                return(preemptiveExits.ToArray(), nextBlock);
            }

            case IfStatement ifStatement:
            {
                var processConditional = ProcessConditional(ifStatement);
                if (!processConditional.HasValue)
                {
                    return(Array.Empty <GraphNode>(), target);
                }

                var(_, conditionalNode) = processConditional.Value;

                var preemptiveExits = new List <GraphNode>();

                // block after IF
                var nextBlock = new GraphControlFlowBlockNode(methodRoot);

                {
                    var trueBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.TrueOutgoing = trueBlock;

                    var(truePreemptiveExits, trueNext) = AddStatementToGraphNode(ifStatement.Block,
                                                                                 methodRoot,
                                                                                 trueBlock,
                                                                                 continueTarget,
                                                                                 breakTarget);

                    preemptiveExits.AddRange(truePreemptiveExits);

                    if (trueNext != null)
                    {
                        trueNext.Outgoing = nextBlock;
                    }
                }

                if (ifStatement.ElseBlock != null)
                {
                    var falseBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.FalseOutgoing = falseBlock;

                    var(falsePreemptiveExits, falseNext) = AddStatementToGraphNode(ifStatement.ElseBlock,
                                                                                   methodRoot,
                                                                                   falseBlock,
                                                                                   continueTarget,
                                                                                   breakTarget);

                    preemptiveExits.AddRange(falsePreemptiveExits);

                    if (falseNext != null)
                    {
                        falseNext.Outgoing = nextBlock;
                    }
                }
                else
                {
                    conditionalNode.FalseOutgoing = nextBlock;
                }

                return(preemptiveExits.ToArray(), nextBlock);
            }

            case ReturnStatement returnStatement:
            {
                var graphReturnNode = new GraphControlFlowReturnNode(
                    methodRoot,
                    (ExpressionBase)returnStatement.What,
                    false
                    );
                target.Outgoing = graphReturnNode;
                return(new GraphNode[] { graphReturnNode }, null);
            }

            case SimpleCompoundStatement simpleCompoundStatement:
            {
                var preemptiveExits = new List <GraphNode>();
                var currentTarget   = target;

                foreach (var statementBase in simpleCompoundStatement.Body)
                {
                    var(newPreemptiveExits, newNext) = AddStatementToGraphNode(statementBase,
                                                                               methodRoot,
                                                                               currentTarget,
                                                                               continueTarget,
                                                                               breakTarget);

                    preemptiveExits.AddRange(newPreemptiveExits);

                    currentTarget = newNext;
                }

                if (currentTarget != null)
                {
                    var newBlockNode = new GraphControlFlowBlockNode(methodRoot);
                    currentTarget.Outgoing = newBlockNode;
                    currentTarget          = newBlockNode;
                }

                return(preemptiveExits.ToArray(), currentTarget);
            }

            case SimpleDeclarationStatement _:
                return(Array.Empty <GraphNode>(), target);

            case SimpleExpressionStatement simpleExpressionStatement:
            {
                var node = new GraphControlFlowExpressionNode(methodRoot, simpleExpressionStatement.Expression);
                target.Body.Add(node);
                return(Array.Empty <GraphNode>(), target);
            }

            case WhileIterationStatement whileStatement:
            {
                var processConditional = ProcessConditional(whileStatement);
                if (!processConditional.HasValue)
                {
                    return(Array.Empty <GraphNode>(), target);
                }

                var(conditionalStartNode, conditionalNode) = processConditional.Value;

                var preemptiveExits = new List <GraphNode>();

                // block after WHILE
                var nextBlock = new GraphControlFlowBlockNode(methodRoot);

                {
                    var trueBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.TrueOutgoing = trueBlock;

                    var(truePreemptiveExits, trueNext) = AddStatementToGraphNode(whileStatement.Block,
                                                                                 methodRoot,
                                                                                 trueBlock,
                                                                                 conditionalStartNode,
                                                                                 nextBlock);

                    preemptiveExits.AddRange(truePreemptiveExits);

                    if (trueNext != null)
                    {
                        trueNext.Outgoing = conditionalStartNode;
                    }
                }

                conditionalNode.FalseOutgoing = nextBlock;

                return(preemptiveExits.ToArray(), nextBlock);
            }

            case SimpleSelectionStatement _:
                goto default;

            default:
                throw new ArgumentOutOfRangeException(nameof(statement));
            }

            (GraphNode conditionalStartNode, GraphControlFlowConditionalNode conditionalNode)?
            ProcessConditional(SimpleSelectionStatement statement)
            {
                GraphControlFlowConditionalNode conditionalNode;

                if (statement.Condition.Count >= 1)
                {
                    conditionalNode = new GraphControlFlowConditionalNode(methodRoot, statement.Condition[^ 1]);
コード例 #13
0
 public CallGraphMethodNode([NotNull] GraphMethodRoot methodRoot)
 {
     MethodRoot = methodRoot ?? throw new ArgumentNullException(nameof(methodRoot));
 }
コード例 #14
0
 public DataFlowGraphBuilder(GraphMethodRoot methodRoot)
 {
     MethodRoot = methodRoot;
 }
コード例 #15
0
 protected GraphDataFlowExpressionNodeBase(GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression) :
     base(methodRoot, expression)
 {
     SubscribeToAnalysisContextChanges(EnterAnalysisContext);
 }
 public IntraProceduralDataFlowAnalyzer(GraphMethodRoot methodRoot)
 {
     MethodRoot = methodRoot;
 }
コード例 #17
0
 public GraphControlFlowReturnNode(GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression, bool synthetic)
     : base(methodRoot, expression)
 {
     Synthetic = synthetic;
 }
コード例 #18
0
        public void RegisterMethod(GraphMethodRoot methodRoot)
        {
            var node = methodRoot.CallGraphMethodNode;

            if (!_methodNodes.TryAdd(methodRoot.Name, node))
            {
                Log.Warning("Method {Name} is already registered in CallGraphBuilder",
                            methodRoot.Name);
                return;
            }

            if (_callRegistrationQueue.TryGetValue(methodRoot.Name, out var pendingCalls))
            {
                foreach (var callGraphInvocationNode in pendingCalls)
                {
                    callGraphInvocationNode.Target = node;
                }

                _callRegistrationQueue.Remove(methodRoot.Name);
            }

            foreach (var graphNode in methodRoot.Start.IterateGraphNodesRecursive(true))
            {
                switch (graphNode)
                {
                case null:
                    throw new ArgumentNullException(nameof(graphNode));

                case GraphDataFlowBlockNode graphDataFlowBlockNode:
                    foreach (var graphDataFlowExpressionNode in graphDataFlowBlockNode.Body)
                    {
                        RegisterExpression(graphDataFlowExpressionNode);
                    }

                    break;

                case GraphControlFlowBlockNode _:
                    goto default;

                case GraphDataFlowExpressionNodeBase dataFlowExpressionNode:
                    RegisterExpression(dataFlowExpressionNode);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(graphNode));
                }
            }

            void RegisterExpression(GraphDataFlowExpressionNodeBase graphExpressionNodeBase)
            {
                var count = 0;

                foreach (var functionCallOperator in graphExpressionNodeBase.Expression
                         .DescendantValues()
                         .OfType <FunctionCallOperator>())
                {
                    var invocationNode = new CallGraphInvocationNode(graphExpressionNodeBase);

                    count++;
                    if (count > 1)
                    {
                        Log.Warning("Multiple FunctionCallOperator in {Expression}", graphExpressionNodeBase);
                    }
                    else
                    {
                        graphExpressionNodeBase.CallGraphInvocationNode = invocationNode;
                    }

                    node.OutgoingNodes.Add(invocationNode);
                    var targetName = functionCallOperator.Name;
                    if (_methodNodes.TryGetValue(targetName, out var targetNode))
                    {
                        invocationNode.Target = targetNode;
                    }
                    else
                    {
                        _callRegistrationQueue.Add(targetName, invocationNode);
                    }
                }
            }
        }
コード例 #19
0
 public GraphControlFlowBlockNode([System.Diagnostics.CodeAnalysis.NotNull] GraphMethodRoot methodRoot) : base(methodRoot)
 {
 }