public GraphDataFlowBlockNode([NotNull] GraphMethodRoot methodRoot) : base(methodRoot) { StrongConnectivityNode = new ComponentNode <GraphDataFlowBlockNode>(this); ((IComponentNodeItem <GraphDataFlowBlockNode>) this).SubscribeToStrongConnectivityNodePropertyChanged(); RefreshText(); }
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)); } } }
public GraphDataFlowReturnNode(GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression) : base( methodRoot, expression) { StrongConnectivityNode = new ComponentNode <GraphDataFlowReturnNode>(this); ((IComponentNodeItem <GraphDataFlowReturnNode>) this).SubscribeToStrongConnectivityNodePropertyChanged(); RefreshText(); }
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); }
public GraphDataFlowExpressionNode( GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression, [NotNull] GraphDataFlowBlockNode blockNode ) : base(methodRoot, expression) { BlockNode = blockNode; ExitAnalysisContext = new AnalysisContext(EnterAnalysisContext); SubscribeToAnalysisContextChanges(ExitAnalysisContext); RefreshText(); }
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)) }); }
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) { }
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]);
public CallGraphMethodNode([NotNull] GraphMethodRoot methodRoot) { MethodRoot = methodRoot ?? throw new ArgumentNullException(nameof(methodRoot)); }
public DataFlowGraphBuilder(GraphMethodRoot methodRoot) { MethodRoot = methodRoot; }
protected GraphDataFlowExpressionNodeBase(GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression) : base(methodRoot, expression) { SubscribeToAnalysisContextChanges(EnterAnalysisContext); }
public IntraProceduralDataFlowAnalyzer(GraphMethodRoot methodRoot) { MethodRoot = methodRoot; }
public GraphControlFlowReturnNode(GraphMethodRoot methodRoot, [CanBeNull] ExpressionBase expression, bool synthetic) : base(methodRoot, expression) { Synthetic = synthetic; }
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); } } } }
public GraphControlFlowBlockNode([System.Diagnostics.CodeAnalysis.NotNull] GraphMethodRoot methodRoot) : base(methodRoot) { }