public void Convert() { MethodRoot.Start = ConvertNode(MethodRoot.Start); var graphNodes = MethodRoot.Start.IterateGraphNodesRecursive(false).ToArray(); foreach (var graphNode in graphNodes) { ConvertNode(graphNode); } GraphNode ConvertNode(GraphNode graphNode) { return(graphNode switch { null => throw new ArgumentOutOfRangeException(nameof(graphNode)), GraphDataFlowBlockNode _ => graphNode, GraphDataFlowExpressionNode _ => graphNode, GraphControlFlowBlockNode blockNode => ConvertControlFlowNode(blockNode), GraphControlFlowConditionalNode conditionalNode => ConvertControlFlowNode(conditionalNode), GraphControlFlowReturnNode returnNode => ConvertControlFlowNode(returnNode), GraphDataFlowConditionalNode _ => graphNode, GraphDataFlowReturnNode _ => graphNode, _ => throw new ArgumentOutOfRangeException(nameof(graphNode)) }); }
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 bool SimplifyGraph(GraphControlFlowBlockNode blockNode) { if (blockNode.Body.Count != 0) { return(false); } var child = blockNode.Outgoing; child.ReplaceIncomingNode(blockNode, blockNode.Incoming, true); foreach (var parentNode in blockNode.Incoming) { parentNode.ReplaceOutgoingNode(blockNode, child); } blockNode.Incoming.Clear(); return(true); }
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)])
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]);