1 //
2 // SubroutineBuilder.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 System.Collections.Generic;
30 using Mono.CodeContracts.Static.AST;
31 using Mono.CodeContracts.Static.ControlFlow.Blocks;
32 using Mono.CodeContracts.Static.DataStructures;
33 using Mono.CodeContracts.Static.Providers;
34 
35 namespace Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders {
36 	abstract class SubroutineBuilder<Label> {
37 		public readonly SubroutineFacade SubroutineFacade;
38 
39 		private readonly Dictionary<Label, Pair<Method, bool>> labels_for_call_sites = new Dictionary<Label, Pair<Method, bool>> ();
40 		private readonly Dictionary<Label, Method> labels_for_new_obj_sites = new Dictionary<Label, Method> ();
41 		private readonly HashSet<Label> labels_starting_blocks = new HashSet<Label> ();
42 		private readonly HashSet<Label> target_labels = new HashSet<Label> ();
43 
SubroutineBuilder(ICodeProvider<Label> codeProvider, SubroutineFacade subroutineFacade, Label entry)44 		protected SubroutineBuilder (ICodeProvider<Label> codeProvider,
45 		                             SubroutineFacade subroutineFacade,
46 		                             Label entry)
47 		{
48 			this.SubroutineFacade = subroutineFacade;
49 			CodeProvider = codeProvider;
50 			AddTargetLabel (entry);
51 		}
52 
53 		public ICodeProvider<Label> CodeProvider { get; private set; }
54 		public abstract SubroutineBase<Label> CurrentSubroutine { get; }
55 
56 		public IMetaDataProvider MetaDataProvider
57 		{
58 			get { return this.SubroutineFacade.MetaDataProvider; }
59 		}
60 
61 		protected IContractProvider ContractProvider
62 		{
63 			get { return this.SubroutineFacade.ContractProvider; }
64 		}
65 
AddTargetLabel(Label target)66 		public void AddTargetLabel (Label target)
67 		{
68 			AddBlockStart (target);
69 			this.target_labels.Add (target);
70 		}
71 
AddBlockStart(Label target)72 		public void AddBlockStart (Label target)
73 		{
74 			this.labels_starting_blocks.Add (target);
75 		}
76 
Initialize(Label entry)77 		protected void Initialize (Label entry)
78 		{
79 			new BlockStartGatherer<Label> (this).TraceAggregateSequentally (entry);
80 		}
81 
IsBlockStart(Label label)82 		public bool IsBlockStart (Label label)
83 		{
84 			return this.labels_starting_blocks.Contains (label);
85 		}
86 
IsTargetLabel(Label label)87 		public bool IsTargetLabel (Label label)
88 		{
89 			return this.target_labels.Contains (label);
90 		}
91 
IsMethodCallSite(Label label, out Pair<Method, bool> methodVirtPair)92 		public bool IsMethodCallSite (Label label, out Pair<Method, bool> methodVirtPair)
93 		{
94 			return this.labels_for_call_sites.TryGetValue (label, out methodVirtPair);
95 		}
96 
IsNewObjSite(Label label, out Method constructor)97 		public bool IsNewObjSite (Label label, out Method constructor)
98 		{
99 			return this.labels_for_new_obj_sites.TryGetValue (label, out constructor);
100 		}
101 
BuildBlocks(Label entry)102 		protected BlockWithLabels<Label> BuildBlocks (Label entry)
103 		{
104 			return BlockBuilder<Label>.BuildBlocks (entry, this);
105 		}
106 
RecordInformationSameAsOtherBlock(BlockWithLabels<Label> newBlock, BlockWithLabels<Label> currentBlock)107 		public virtual void RecordInformationSameAsOtherBlock (BlockWithLabels<Label> newBlock, BlockWithLabels<Label> currentBlock)
108 		{
109 		}
110 
RecordInformationForNewBlock(Label currentLabel, BlockWithLabels<Label> previousBlock)111 		public virtual BlockWithLabels<Label> RecordInformationForNewBlock (Label currentLabel, BlockWithLabels<Label> previousBlock)
112 		{
113 			BlockWithLabels<Label> block = CurrentSubroutine.GetBlock (currentLabel);
114 			if (previousBlock != null) {
115 				BlockWithLabels<Label> newBlock = block;
116 				BlockWithLabels<Label> prevBlock = previousBlock;
117 				if (block is MethodCallBlock<Label> && previousBlock is MethodCallBlock<Label>) {
118 					BlockWithLabels<Label> ab = CurrentSubroutine.NewBlock ();
119 					RecordInformationSameAsOtherBlock (ab, previousBlock);
120 					newBlock = ab;
121 					prevBlock = ab;
122 					CurrentSubroutine.AddSuccessor (previousBlock, EdgeTag.FallThrough, ab);
123 					CurrentSubroutine.AddSuccessor (ab, EdgeTag.FallThrough, block);
124 				} else
125 					CurrentSubroutine.AddSuccessor (previousBlock, EdgeTag.FallThrough, block);
126 
127 				InsertPostConditionEdges (previousBlock, newBlock);
128 				InsertPreConditionEdges (prevBlock, block);
129 			}
130 			return block;
131 		}
132 
InsertPreConditionEdges(BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)133 		protected void InsertPreConditionEdges (BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)
134 		{
135 			var methodCallBlock = newBlock as MethodCallBlock<Label>;
136 			if (methodCallBlock == null || CurrentSubroutine.IsContract || CurrentSubroutine.IsOldValue)
137 				return;
138 
139 			if (CurrentSubroutine.IsMethod) {
140 				var methodInfo = CurrentSubroutine as IMethodInfo;
141 				Property property;
142 				if (methodInfo != null && MetaDataProvider.IsConstructor (methodInfo.Method)
143 				    && MetaDataProvider.IsPropertySetter (methodCallBlock.CalledMethod, out property)
144 				    && MetaDataProvider.IsAutoPropertyMember (methodCallBlock.CalledMethod))
145 					return;
146 			}
147 
148 			EdgeTag callTag = methodCallBlock.IsNewObj ? EdgeTag.BeforeNewObj : EdgeTag.BeforeCall;
149 			Subroutine requires = this.SubroutineFacade.GetRequires (methodCallBlock.CalledMethod);
150 
151 			CurrentSubroutine.AddEdgeSubroutine (previousBlock, newBlock, requires, callTag);
152 		}
153 
InsertPostConditionEdges(BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)154 		protected void InsertPostConditionEdges (BlockWithLabels<Label> previousBlock, BlockWithLabels<Label> newBlock)
155 		{
156 			var methodCallBlock = previousBlock as MethodCallBlock<Label>;
157 			if (methodCallBlock == null)
158 				return;
159 
160 			if (CurrentSubroutine.IsMethod) {
161 				var methodInfo = CurrentSubroutine as IMethodInfo;
162 				Property property;
163 				if (methodInfo != null && MetaDataProvider.IsConstructor (methodInfo.Method)
164 				    && MetaDataProvider.IsPropertyGetter (methodCallBlock.CalledMethod, out property)
165 				    && MetaDataProvider.IsAutoPropertyMember (methodCallBlock.CalledMethod))
166 					return;
167 			}
168 
169 			EdgeTag callTag = methodCallBlock.IsNewObj ? EdgeTag.AfterNewObj : EdgeTag.AfterCall;
170 			Subroutine ensures = this.SubroutineFacade.GetEnsures (methodCallBlock.CalledMethod);
171 
172 			CurrentSubroutine.AddEdgeSubroutine (previousBlock, newBlock, ensures, callTag);
173 		}
174 
BeginOldHook(Label label)175 		public virtual void BeginOldHook (Label label)
176 		{
177 		}
178 
EndOldHook(Label label)179 		public virtual void EndOldHook (Label label)
180 		{
181 		}
182 
AddMethodCallSite(Label pc, Pair<Method, bool> methodVirtPair)183 		public void AddMethodCallSite (Label pc, Pair<Method, bool> methodVirtPair)
184 		{
185 			this.labels_for_call_sites [pc] = methodVirtPair;
186 		}
187 
AddNewObjSite(Label pc, Method method)188 		public void AddNewObjSite (Label pc, Method method)
189 		{
190 			this.labels_for_new_obj_sites [pc] = method;
191 		}
192 	}
193 }
194