Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders / BlockBuilder.cs
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
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
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
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
64                 public override bool BranchFalse (TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock)
65                 {
66                         return HandleConditionalBranch (pc, target, false, currentBlock);
67                 }
68
69                 public override bool BranchTrue (TLabel pc, TLabel target, Dummy cond, BlockWithLabels<TLabel> currentBlock)
70                 {
71                         return HandleConditionalBranch (pc, target, true, currentBlock);
72                 }
73
74                 public override bool Throw (TLabel pc, Dummy exception, BlockWithLabels<TLabel> currentBlock)
75                 {
76                         currentBlock.AddLabel (pc);
77                         return true;
78                 }
79
80                 public override bool Rethrow (TLabel pc, BlockWithLabels<TLabel> currentBlock)
81                 {
82                         currentBlock.AddLabel (pc);
83                         return true;
84                 }
85
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
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
102                 public override bool Nop (TLabel pc, BlockWithLabels<TLabel> currentBlock)
103                 {
104                         return false;
105                 }
106
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
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
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
138                 public bool Aggregate (TLabel pc, TLabel aggregateStart, bool canBeTargetOfBranch, BlockWithLabels<TLabel> data)
139                 {
140                         TraceAggregateSequentally (aggregateStart);
141                         return false;
142                 }
143                 #endregion
144
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
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
170                 public override bool DefaultVisit (TLabel pc, BlockWithLabels<TLabel> currentBlock)
171                 {
172                         currentBlock.AddLabel (pc);
173                         return false;
174                 }
175
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 }