1 // 2 // BlockBuilder.cs 3 // 4 // Authors: 5 // Alexander Chebaturkin (chebaturkin@gmail.com) 6 // 7 // Copyright (C) 2011 Alexander Chebaturkin 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 29 using Mono.CodeContracts.Static.AST; 30 using Mono.CodeContracts.Static.AST.Visitors; 31 using Mono.CodeContracts.Static.ControlFlow.Blocks; 32 using Mono.CodeContracts.Static.DataStructures; 33 34 namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders { 35 class BlockBuilder<TLabel> : ILVisitorBase<TLabel, Dummy, Dummy, BlockWithLabels<TLabel>, bool>, 36 IAggregateVisitor<TLabel, BlockWithLabels<TLabel>, bool> { 37 private readonly SubroutineBuilder<TLabel> builder; 38 private BlockWithLabels<TLabel> current_block; 39 BlockBuilder(SubroutineBuilder<TLabel> builder)40 private BlockBuilder (SubroutineBuilder<TLabel> builder) 41 { 42 this.builder = builder; 43 } 44 45 private SubroutineBase<TLabel> CurrentSubroutine 46 { 47 get { return this.builder.CurrentSubroutine; } 48 } 49 50 #region IAggregateVisitor<Label,BlockWithLabels<Label>,bool> Members Branch(TLabel pc, TLabel target, bool leavesExceptionBlock, BlockWithLabels<TLabel> currentBlock)51 public override bool Branch (TLabel pc, TLabel target, bool leavesExceptionBlock, BlockWithLabels<TLabel> currentBlock) 52 { 53 currentBlock.AddLabel (pc); 54 CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.Branch, CurrentSubroutine.GetTargetBlock (target)); 55 56 return true; 57 } 58 BranchCond(TLabel pc, TLabel target, BranchOperator bop, Dummy value1, Dummy value2, BlockWithLabels<TLabel> currentBlock)59 public override bool BranchCond (TLabel pc, TLabel target, BranchOperator bop, Dummy value1, Dummy value2, BlockWithLabels<TLabel> currentBlock) 60 { 61 return HandleConditionalBranch (pc, target, true, currentBlock); 62 } 63 BranchFalse(TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock)64 public override bool BranchFalse (TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock) 65 { 66 return HandleConditionalBranch (pc, target, false, currentBlock); 67 } 68 BranchTrue(TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock)69 public override bool BranchTrue (TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock) 70 { 71 return HandleConditionalBranch (pc, target, true, currentBlock); 72 } 73 Throw(TLabel pc, Dummy exception, BlockWithLabels<TLabel> currentBlock)74 public override bool Throw (TLabel pc, Dummy exception, BlockWithLabels<TLabel> currentBlock) 75 { 76 currentBlock.AddLabel (pc); 77 return true; 78 } 79 Rethrow(TLabel pc, BlockWithLabels<TLabel> currentBlock)80 public override bool Rethrow (TLabel pc, BlockWithLabels<TLabel> currentBlock) 81 { 82 currentBlock.AddLabel (pc); 83 return true; 84 } 85 EndFinally(TLabel pc, BlockWithLabels<TLabel> currentBlock)86 public override bool EndFinally (TLabel pc, BlockWithLabels<TLabel> currentBlock) 87 { 88 currentBlock.AddLabel (pc); 89 CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.EndSubroutine, CurrentSubroutine.Exit); 90 return true; 91 } 92 Return(TLabel pc, Dummy source, BlockWithLabels<TLabel> currentBlock)93 public override bool Return (TLabel pc, Dummy source, BlockWithLabels<TLabel> currentBlock) 94 { 95 currentBlock.AddLabel (pc); 96 CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.Return, CurrentSubroutine.Exit); 97 CurrentSubroutine.AddReturnBlock (currentBlock); 98 99 return true; 100 } 101 Nop(TLabel pc, BlockWithLabels<TLabel> currentBlock)102 public override bool Nop (TLabel pc, BlockWithLabels<TLabel> currentBlock) 103 { 104 return false; 105 } 106 LoadField(TLabel pc, Field field, Dummy dest, Dummy obj, BlockWithLabels<TLabel> data)107 public override bool LoadField (TLabel pc, Field field, Dummy dest, Dummy obj, BlockWithLabels<TLabel> data) 108 { 109 if (CurrentSubroutine.IsMethod) { 110 var methodInfo = (IMethodInfo) CurrentSubroutine; 111 Property property; 112 if (this.builder.MetaDataProvider.IsPropertyGetter (methodInfo.Method, out property)) 113 this.builder.SubroutineFacade.AddReads (methodInfo.Method, field); 114 } 115 this.current_block.AddLabel (pc); 116 return false; 117 } 118 StoreField(TLabel pc, Field field, Dummy obj, Dummy value, BlockWithLabels<TLabel> data)119 public override bool StoreField (TLabel pc, Field field, Dummy obj, Dummy value, BlockWithLabels<TLabel> data) 120 { 121 if (CurrentSubroutine.IsMethod) { 122 var methodInfo = (IMethodInfo) CurrentSubroutine; 123 Property property; 124 if (this.builder.MetaDataProvider.IsPropertySetter (methodInfo.Method, out property)) 125 this.builder.SubroutineFacade.AddReads (methodInfo.Method, field); 126 } 127 this.current_block.AddLabel (pc); 128 return false; 129 } 130 EndOld(TLabel pc, TLabel matchingBegin, TypeNode type, Dummy dest, Dummy source, BlockWithLabels<TLabel> data)131 public override bool EndOld (TLabel pc, TLabel matchingBegin, TypeNode type, Dummy dest, Dummy source, BlockWithLabels<TLabel> data) 132 { 133 this.current_block.AddLabel (pc); 134 CurrentSubroutine.AddSuccessor (this.current_block, EdgeTag.EndOld, CurrentSubroutine.Exit); 135 return false; 136 } 137 Aggregate(TLabel pc, TLabel aggregateStart, bool canBeTargetOfBranch, BlockWithLabels<TLabel> data)138 public bool Aggregate (TLabel pc, TLabel aggregateStart, bool canBeTargetOfBranch, BlockWithLabels<TLabel> data) 139 { 140 TraceAggregateSequentally (aggregateStart); 141 return false; 142 } 143 #endregion 144 BuildBlocks(TLabel entry, SubroutineBuilder<TLabel> subroutineBuilder)145 public static BlockWithLabels<TLabel> BuildBlocks (TLabel entry, SubroutineBuilder<TLabel> subroutineBuilder) 146 { 147 var blockBuilder = new BlockBuilder<TLabel> (subroutineBuilder); 148 blockBuilder.TraceAggregateSequentally (entry); 149 if (blockBuilder.current_block == null) 150 return null; 151 152 SubroutineBase<TLabel> subroutine = blockBuilder.CurrentSubroutine; 153 154 subroutine.AddSuccessor (blockBuilder.current_block, EdgeTag.FallThroughReturn, subroutine.Exit); 155 subroutine.AddReturnBlock (blockBuilder.current_block); 156 157 return blockBuilder.current_block; 158 } 159 TraceAggregateSequentally(TLabel currentLabel)160 private void TraceAggregateSequentally (TLabel currentLabel) 161 { 162 do { 163 if (this.builder.IsBlockStart (currentLabel)) 164 this.current_block = this.builder.RecordInformationForNewBlock (currentLabel, this.current_block); 165 if (this.builder.CodeProvider.Decode<BlockBuilder<TLabel>, BlockWithLabels<TLabel>, bool> (currentLabel, this, this.current_block)) 166 this.current_block = null; 167 } while (this.builder.CodeProvider.Next (currentLabel, out currentLabel)); 168 } 169 DefaultVisit(TLabel pc, BlockWithLabels<TLabel> currentBlock)170 public override bool DefaultVisit (TLabel pc, BlockWithLabels<TLabel> currentBlock) 171 { 172 currentBlock.AddLabel (pc); 173 return false; 174 } 175 HandleConditionalBranch(TLabel pc, TLabel target, bool isTrueBranch, BlockWithLabels<TLabel> currentBlock)176 private bool HandleConditionalBranch (TLabel pc, TLabel target, bool isTrueBranch, BlockWithLabels<TLabel> currentBlock) 177 { 178 currentBlock.AddLabel (pc); 179 EdgeTag trueTag = isTrueBranch ? EdgeTag.True : EdgeTag.False; 180 EdgeTag falseTag = isTrueBranch ? EdgeTag.False : EdgeTag.True; 181 182 AssumeBlock<TLabel> trueBlock = CurrentSubroutine.NewAssumeBlock (pc, trueTag); 183 this.builder.RecordInformationSameAsOtherBlock (trueBlock, this.current_block); 184 CurrentSubroutine.AddSuccessor (currentBlock, trueTag, trueBlock); 185 CurrentSubroutine.AddSuccessor (trueBlock, EdgeTag.FallThrough, CurrentSubroutine.GetTargetBlock (target)); 186 187 AssumeBlock<TLabel> falseBlock = CurrentSubroutine.NewAssumeBlock (pc, falseTag); 188 this.builder.RecordInformationSameAsOtherBlock (falseBlock, this.current_block); 189 CurrentSubroutine.AddSuccessor (currentBlock, falseTag, falseBlock); 190 this.current_block = falseBlock; 191 192 return false; 193 } 194 } 195 } 196