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