5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2011 Alexander Chebaturkin
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
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;
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;
40 private BlockBuilder (SubroutineBuilder<TLabel> builder)
42 this.builder = builder;
45 private SubroutineBase<TLabel> CurrentSubroutine
47 get { return this.builder.CurrentSubroutine; }
50 #region IAggregateVisitor<Label,BlockWithLabels<Label>,bool> Members
51 public override bool Branch (TLabel pc, TLabel target, bool leavesExceptionBlock, BlockWithLabels<TLabel> currentBlock)
53 currentBlock.AddLabel (pc);
54 CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.Branch, CurrentSubroutine.GetTargetBlock (target));
59 public override bool BranchCond (TLabel pc, TLabel target, BranchOperator bop, Dummy value1, Dummy value2, BlockWithLabels<TLabel> currentBlock)
61 return HandleConditionalBranch (pc, target, true, currentBlock);
64 public override bool BranchFalse (TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock)
66 return HandleConditionalBranch (pc, target, false, currentBlock);
69 public override bool BranchTrue (TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock)
71 return HandleConditionalBranch (pc, target, true, currentBlock);
74 public override bool Throw (TLabel pc, Dummy exception, BlockWithLabels<TLabel> currentBlock)
76 currentBlock.AddLabel (pc);
80 public override bool Rethrow (TLabel pc, BlockWithLabels<TLabel> currentBlock)
82 currentBlock.AddLabel (pc);
86 public override bool EndFinally (TLabel pc, BlockWithLabels<TLabel> currentBlock)
88 currentBlock.AddLabel (pc);
89 CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.EndSubroutine, CurrentSubroutine.Exit);
93 public override bool Return (TLabel pc, Dummy source, BlockWithLabels<TLabel> currentBlock)
95 currentBlock.AddLabel (pc);
96 CurrentSubroutine.AddSuccessor (currentBlock, EdgeTag.Return, CurrentSubroutine.Exit);
97 CurrentSubroutine.AddReturnBlock (currentBlock);
102 public override bool Nop (TLabel pc, BlockWithLabels<TLabel> currentBlock)
107 public override bool LoadField (TLabel pc, Field field, Dummy dest, Dummy obj, BlockWithLabels<TLabel> data)
109 if (CurrentSubroutine.IsMethod) {
110 var methodInfo = (IMethodInfo) CurrentSubroutine;
112 if (this.builder.MetaDataProvider.IsPropertyGetter (methodInfo.Method, out property))
113 this.builder.SubroutineFacade.AddReads (methodInfo.Method, field);
115 this.current_block.AddLabel (pc);
119 public override bool StoreField (TLabel pc, Field field, Dummy obj, Dummy value, BlockWithLabels<TLabel> data)
121 if (CurrentSubroutine.IsMethod) {
122 var methodInfo = (IMethodInfo) CurrentSubroutine;
124 if (this.builder.MetaDataProvider.IsPropertySetter (methodInfo.Method, out property))
125 this.builder.SubroutineFacade.AddReads (methodInfo.Method, field);
127 this.current_block.AddLabel (pc);
131 public override bool EndOld (TLabel pc, TLabel matchingBegin, TypeNode type, Dummy dest, Dummy source, BlockWithLabels<TLabel> data)
133 this.current_block.AddLabel (pc);
134 CurrentSubroutine.AddSuccessor (this.current_block, EdgeTag.EndOld, CurrentSubroutine.Exit);
138 public bool Aggregate (TLabel pc, TLabel aggregateStart, bool canBeTargetOfBranch, BlockWithLabels<TLabel> data)
140 TraceAggregateSequentally (aggregateStart);
145 public static BlockWithLabels<TLabel> BuildBlocks (TLabel entry, SubroutineBuilder<TLabel> subroutineBuilder)
147 var blockBuilder = new BlockBuilder<TLabel> (subroutineBuilder);
148 blockBuilder.TraceAggregateSequentally (entry);
149 if (blockBuilder.current_block == null)
152 SubroutineBase<TLabel> subroutine = blockBuilder.CurrentSubroutine;
154 subroutine.AddSuccessor (blockBuilder.current_block, EdgeTag.FallThroughReturn, subroutine.Exit);
155 subroutine.AddReturnBlock (blockBuilder.current_block);
157 return blockBuilder.current_block;
160 private void TraceAggregateSequentally (TLabel currentLabel)
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));
170 public override bool DefaultVisit (TLabel pc, BlockWithLabels<TLabel> currentBlock)
172 currentBlock.AddLabel (pc);
176 private bool HandleConditionalBranch (TLabel pc, TLabel target, bool isTrueBranch, BlockWithLabels<TLabel> currentBlock)
178 currentBlock.AddLabel (pc);
179 EdgeTag trueTag = isTrueBranch ? EdgeTag.True : EdgeTag.False;
180 EdgeTag falseTag = isTrueBranch ? EdgeTag.False : EdgeTag.True;
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));
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;