/// <summary> /// Visits WhileStmt(do while and while) and builds controlflow graf for while cycle. /// </summary> /// <param name="x">WhileStmt</param> public override void VisitWhileStmt(WhileStmt x) { BasicBlock aboveLoop = currentBasicBlock; BasicBlock startLoop = new BasicBlock(); BasicBlock underLoop = new BasicBlock(); aboveLoop.CreateWorklistSegment(underLoop); // Connect above loop to start of the loop and under loop if (x.LoopType == WhileStmt.Type.While) { // while => above loop is connected conditionally to start of the loop and under loop BasicBlockEdge.ConnectConditionalBranching(DeepCopyAstExpressionCopyVisitor(x.CondExpr), currentBasicBlock, startLoop, underLoop); } else { // do ... while => above loop is connected just to the start of the loop BasicBlockEdge.ConnectDirectEdge(aboveLoop, startLoop); } // Generate CFG for loop body loopData.Push(new LoopData(startLoop, underLoop)); currentBasicBlock = startLoop; x.Body.VisitMe(this); loopData.Pop(); // Connect the end of loop body to start of the loop and under the loop BasicBlockEdge.ConnectConditionalBranching(x.CondExpr, currentBasicBlock, startLoop, underLoop); currentBasicBlock = underLoop; }
/// <summary> /// Visits try catch statement and connects thrown exceptions to catch blocks or function sink. /// </summary> /// <param name="x">TryStmt</param> public override void VisitTryStmt(TryStmt x) { BasicBlock followingBlock = new BasicBlock(); TryBasicBlock tryBlock = new TryBasicBlock(); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, tryBlock); currentBasicBlock = tryBlock; //throwBlocks.Push(new List<BasicBlock>()); VisitStatementList(x.Statements); currentBasicBlock.EndIngTryBlocks.Add(tryBlock); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, followingBlock); foreach (var catchItem in x.Catches) { CatchBasicBlock catchBlock = new CatchBasicBlock(catchItem.Variable, catchItem.ClassName); tryBlock.catchBlocks.Add(catchBlock); currentBasicBlock = catchBlock; VisitStatementList(catchItem.Statements); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, followingBlock); } //throwBlocks.Pop(); currentBasicBlock = followingBlock; }
/// <summary> /// Visits foreach statement and creates the foreach contruct in cfg. /// </summary> /// <param name="x">ForeachStmt</param> public override void VisitForeachStmt(ForeachStmt x) { BasicBlock foreachHead = new BasicBlock(); BasicBlock foreachBody = new BasicBlock(); BasicBlock foreachSink = new BasicBlock(); foreachHead.CreateWorklistSegment(foreachSink); //Input edge to the foreach statement BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, foreachHead); foreachHead.AddElement(x); //Conditional edge to the foreach body BasicBlockEdge.ConnectForeachEdge(foreachHead, foreachBody); //Visits foreach body loopData.Push(new LoopData(foreachHead, foreachSink)); currentBasicBlock = foreachBody; x.Body.VisitMe(this); loopData.Pop(); //Connect end of foreach with foreach head BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, foreachHead); //Output edge to the sink BasicBlockEdge.ConnectDirectEdge(foreachHead, foreachSink); currentBasicBlock = foreachSink; }
/// <summary> /// Visits IfStmt and constructs if branch basic block. /// /// Does not decompose the condition expression using logical operations (&&, ||, and xor). /// Note that this is no longer supported - analyzer now expects that the expression is decomposed /// on the level of CFG and it does not deal with logical operations explicitly. /// See <see cref="VisitIfStmt"/>. /// </summary> /// <param name="x">IfStmt</param> public void VisitIfStmtOld(IfStmt x) { //Merge destination for if and else branch BasicBlock bottomBox = new BasicBlock(); currentBasicBlock.CreateWorklistSegment(bottomBox); foreach (var condition in x.Conditions) { if (condition.Condition != null) { //IF or ELSEIF branch currentBasicBlock = constructIfBranch(bottomBox, condition); } else { //ELSE branch condition.Statement.VisitMe(this); } } //Connect else branch to bottomBox //Must be here becouse in the construc phase we dont know whether the else block would split in the future BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, bottomBox); currentBasicBlock = bottomBox; }
/// <summary> /// Makes the control flow graph for the function or method declaration. /// </summary> /// <typeparam name="T">Type of function declaration container</typeparam> /// <param name="functionDeclaration">The function declaration.</param> /// <param name="functionBody">The function body.</param> /// <returns>The first basic block of the function's CFG.</returns> public BasicBlock MakeFunctionCFG <T>(T functionDeclaration, List <Statement> functionBody) where T : LangElement { //Store actual basic block BasicBlock current = currentBasicBlock; BasicBlock functionBasicBlock = new BasicBlock(); currentBasicBlock = functionBasicBlock; //Store actual Label data - function has its own label namespace labelDictionary = new LabelDataDictionary(); //Add function sink to the stack for resolving returns BasicBlock functionSink = new BasicBlock(); functionSinkStack.Push(functionSink); VisitStatementList(functionBody); /* foreach (var block in throwBlocks.ElementAt(0)) * { * block.Statements.RemoveLast(); * DirectEdge.MakeNewAndConnect(block, functionSink); * }*/ //Connects return destination functionSinkStack.Pop(); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, functionSink); //Loads previous labels currentBasicBlock = current; return(functionBasicBlock); }
/// <summary> /// Visit LabelStmt, stores the label in dictionary and creates new basic block. /// </summary> /// <param name="x">LabelStmt</param> public override void VisitLabelStmt(LabelStmt x) { BasicBlock labelBlock = new BasicBlock(); labelDictionary.GetOrCreateLabelData(x.Name, x.Position) .AsociateLabel(labelBlock, x.Position); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, labelBlock); currentBasicBlock = labelBlock; //Next line could be used for label visualization, label statement shouldnt be in resulting cgf //labelBlock.AddElement(x); }
/// <summary> /// Constructs if branch basic block. /// </summary> /// <param name="bottomBox">Merge destination for if and else branch.</param> /// <param name="condition">The condition of the if branch.</param> /// <returns>Empty basic block for the else branch</returns> private BasicBlock constructIfBranch(BasicBlock bottomBox, ConditionalStmt condition) { BasicBlock thenBranchBlock = new BasicBlock(); BasicBlock elseBranchBlock = new BasicBlock(); BasicBlockEdge.ConnectConditionalBranching(condition.Condition, currentBasicBlock, thenBranchBlock, elseBranchBlock, false); currentBasicBlock = thenBranchBlock; condition.Statement.VisitMe(this); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, bottomBox); return(elseBranchBlock); }
/// <summary> /// Visits the Globalcode element and solves the uncatch exceptions in globalcode. /// </summary> /// <param name="x">Globalcode</param> public override void VisitGlobalCode(GlobalCode x) { foreach (Statement statement in x.Statements) { statement.VisitMe(this); } var peek = functionSinkStack.Peek(); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, functionSinkStack.Peek()); /* foreach (var block in throwBlocks.ElementAt(0)) { * block.Statements.RemoveLast(); * DirectEdge.MakeNewAndConnect(block, functionSinkStack.Peek()); * }*/ }
/// <summary> /// Visits ForStmt and builds controlflow graf for for cycle. /// </summary> /// <param name="x">ForStmt</param> public override void VisitForStmt(ForStmt x) { BasicBlock forTest = new BasicBlock(); BasicBlock forBody = new BasicBlock(); BasicBlock forEnd = new BasicBlock(); BasicBlock forIncrement = new BasicBlock(); currentBasicBlock.CreateWorklistSegment(forEnd); // Create CFG for initialization of the for cycle VisitExpressionList(x.InitExList); //Adds initial connection from initialization to the test block BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, forTest); // Connects test block with body of the for cycle and end of the for cycle var forCondition = (x.CondExList.Count > 0) ? constructSimpleCondition(x.CondExList) : new BoolLiteral(Position.Invalid, true); var currBl = currentBasicBlock; BasicBlockEdge.ConnectConditionalBranching(forCondition, forTest, forBody, forEnd); // Create CFG for Loop body loopData.Push(new LoopData(forIncrement, forEnd)); currentBasicBlock = forBody; x.Body.VisitMe(this); loopData.Pop(); // Connect end of the loop body to the increment BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, forIncrement); // Generate CFG for the loop increment currentBasicBlock = forIncrement; VisitExpressionList(x.ActionExList); // Connect for increment to the test block BasicBlockEdge.ConnectDirectEdge(forIncrement, forTest); currentBasicBlock = forEnd; }
/// <summary> /// Visits IfStmt and constructs if branch basic block. /// /// Decomposes the condition expression using logical operations with respect to shortcircuit evaluation. /// </summary> /// <param name="x">IfStmt</param> //public override void VisitIfStmt(IfStmt x) public override void VisitIfStmt(IfStmt x) { //Merge destination for if and else branch BasicBlock bottomBox = new BasicBlock(); currentBasicBlock.CreateWorklistSegment(bottomBox); foreach (var cond in x.Conditions) { if (cond.Condition != null) { //IF or ELSEIF branch (then branch) var thenBranchBlock = new BasicBlock(); var elseBranchBlock = new BasicBlock(); // Decompose the condition BasicBlockEdge.ConnectConditionalBranching(cond.Condition, currentBasicBlock, thenBranchBlock, elseBranchBlock); // Create CFG for then branch currentBasicBlock = thenBranchBlock; cond.Statement.VisitMe(this); // Connect the end of then branch to the bottom box BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, bottomBox); currentBasicBlock = elseBranchBlock; } else { //ELSE branch cond.Statement.VisitMe(this); } } //Connect then end of else branch to bottomBox //Must be here becouse in the construc phase we dont know whether the else block would split in the future BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, bottomBox); currentBasicBlock = bottomBox; }
/// <summary> /// Visits JumpStmt (break, continue, return). /// </summary> /// <param name="x">JumpStmt</param> public override void VisitJumpStmt(JumpStmt x) { switch (x.Type) { case JumpStmt.Types.Break: case JumpStmt.Types.Continue: if (x.Expression == null) //break without saying how many loops to break { BasicBlock target; //break/continue if (loopData.Count == 0) { if (x.Type == JumpStmt.Types.Break) { throw new ControlFlowException(ControlFlowExceptionCause.BREAK_NOT_IN_CYCLE, x.Position); } else { throw new ControlFlowException(ControlFlowExceptionCause.CONTINUE_NOT_IN_CYCLE, x.Position); } } if (x.Type == JumpStmt.Types.Break) { target = loopData.Peek().BreakTarget; } else { target = loopData.Peek().ContinueTarget; } BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, target); } else { int breakValue = 1; for (int i = loopData.Count - 1; i >= 0; --i) { BasicBlock target; if (x.Type == JumpStmt.Types.Break) { target = loopData.ElementAt(i).BreakTarget; } else { target = loopData.ElementAt(i).ContinueTarget; } BinaryEx condition = new BinaryEx(x.Position, Operations.Equal, new IntLiteral(Position.Invalid, breakValue), x.Expression); graph.cfgAddedElements.Add(condition); BasicBlockEdge.ConnectConditionalBranching(condition, currentBasicBlock, target, new BasicBlock()); //BasicBlockEdge.AddConditionalEdge(currentBasicBlock, target, condition); ++breakValue; } } break; case JumpStmt.Types.Return: PHP.Core.Debug.Assert(functionSinkStack.Count > 0); currentBasicBlock.AddElement(x); BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, functionSinkStack.Peek()); currentBasicBlock = new BasicBlock(); break; } currentBasicBlock = new BasicBlock(); }
/// <summary> /// Visits switch statement and builds controlflow graf for switch construct. /// /// </summary> /// <param name="x">SwitchStmt</param> public override void VisitSwitchStmt(SwitchStmt x) { var aboveCurrentCaseBlock = currentBasicBlock; BasicBlock lastDefaultStartBlock = null; BasicBlock lastDefaultEndBlock = null; currentBasicBlock = new BasicBlock(); //in case of switch statement, continue and break means the same so we make the edge always to the block under the switch BasicBlock underLoop = new BasicBlock(); loopData.Push(new LoopData(underLoop, underLoop)); aboveCurrentCaseBlock.CreateWorklistSegment(underLoop); for (int j = 0; j < x.SwitchItems.Count; j++) { var switchItem = x.SwitchItems[j]; var caseItem = switchItem as CaseItem; // The basic block corresponding to current switch item var switchBlock = new BasicBlock(); // Connect previous switch item (implicitly, subsequent switch items are connected - break must // be there to force the flow to not go to subsequent switch item) if (j > 0) { BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, switchBlock); } if (caseItem == null) { // Default branch // Just mark the last default branch lastDefaultStartBlock = switchBlock; } else { // Case branch // Create condition of the current case branch BinaryEx condition = new BinaryEx(caseItem.CaseVal.Position, Operations.Equal, x.SwitchValue, caseItem.CaseVal); graph.cfgAddedElements.Add(condition); // Create conditional branching: true condition goes to the case, else condition goes above the next switch item var elseBlock = new BasicBlock(); BasicBlockEdge.ConnectConditionalBranching(condition, aboveCurrentCaseBlock, switchBlock, elseBlock); aboveCurrentCaseBlock = elseBlock; } // Builds CFG for the body of the switch element currentBasicBlock = switchBlock; switchItem.VisitMe(this); if (caseItem == null) { // Just to mark the last default branch lastDefaultEndBlock = currentBasicBlock; } } loopData.Pop(); if (lastDefaultStartBlock == null) // No default branch { // Connect the last case with the code under the switch BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, underLoop); // Connect the else of the last case with the code under the switch BasicBlockEdge.ConnectDirectEdge(aboveCurrentCaseBlock, underLoop); } else // There is default branch { // The last default branch is the else of the last case BasicBlockEdge.ConnectDirectEdge(aboveCurrentCaseBlock, lastDefaultStartBlock); if (lastDefaultEndBlock.DefaultBranch == null) // break/continue in the default branch // Connect it with the code under the swithch { BasicBlockEdge.ConnectDirectEdge(lastDefaultEndBlock, underLoop); } else // no break/continue in the default branch // Connect the last case with the code under the switch { BasicBlockEdge.ConnectDirectEdge(currentBasicBlock, underLoop); } } currentBasicBlock = underLoop; }
/// <summary> /// Connects goto basic block with the basic block of the label. /// </summary> /// <param name="gotoBlock">The goto block.</param> void _asociateGoto(BasicBlock gotoBlock) { PHP.Core.Debug.Assert(labelBlock != null); BasicBlockEdge.ConnectDirectEdge(gotoBlock, labelBlock); }