1 //
2 // RemoveBranchDelegator.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.AST.Visitors;
32 using Mono.CodeContracts.Static.DataStructures;
33 using Mono.CodeContracts.Static.Providers;
34 
35 namespace Mono.CodeContracts.Static.ControlFlow {
36 	/// <summary>
37 	/// This class wraps underlying visitor.
38 	/// Replaces: branches to nop; branchCond to binary.
39 	///
40 	/// EdgeTag.Requires: (inside method) => assume, (outside method) => assert
41 	/// EdgeTag.Ensures:  (inside method) => assert, (outside method) => assume
42 	/// </summary>
43 	struct RemoveBranchDelegator<Data, Result, Visitor> : IILVisitor<APC, Dummy, Dummy, Data, Result>
44 		where Visitor : IILVisitor<APC, Dummy, Dummy, Data, Result> {
45 		private readonly IMetaDataProvider meta_data_provider;
46 		private readonly Visitor visitor;
47 
RemoveBranchDelegatorMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator48 		public RemoveBranchDelegator (Visitor visitor,
49 		                              IMetaDataProvider metaDataProvider)
50 		{
51 			this.visitor = visitor;
52 			this.meta_data_provider = metaDataProvider;
53 		}
54 
55 		#region IILVisitor<APC,Dummy,Dummy,Data,Result> Members
BinaryMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator56 		public Result Binary (APC pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, Data data)
57 		{
58 			return this.visitor.Binary (pc, op, dest, operand1, operand2, data);
59 		}
60 
IsinstMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator61 		public Result Isinst (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
62 		{
63 			return this.visitor.Isinst (pc, type, dest, obj, data);
64 		}
65 
LoadNullMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator66 		public Result LoadNull (APC pc, Dummy dest, Data polarity)
67 		{
68 			return this.visitor.LoadNull (pc, dest, polarity);
69 		}
70 
LoadConstMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator71 		public Result LoadConst (APC pc, TypeNode type, object constant, Dummy dest, Data data)
72 		{
73 			return this.visitor.LoadConst (pc, type, constant, dest, data);
74 		}
75 
SizeofMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator76 		public Result Sizeof (APC pc, TypeNode type, Dummy dest, Data data)
77 		{
78 			return this.visitor.Sizeof (pc, type, dest, data);
79 		}
80 
UnaryMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator81 		public Result Unary (APC pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, Data data)
82 		{
83 			return this.visitor.Unary (pc, op, unsigned, dest, source, data);
84 		}
85 
EntryMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator86 		public Result Entry (APC pc, Method method, Data data)
87 		{
88 			return this.visitor.Entry (pc, method, data);
89 		}
90 
AssumeMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator91 		public Result Assume (APC pc, EdgeTag tag, Dummy condition, Data data)
92 		{
93 			if (tag == EdgeTag.Requires && pc.InsideRequiresAtCall || tag == EdgeTag.Invariant && pc.InsideInvariantOnExit)
94 				return this.visitor.Assert (pc, tag, condition, data);
95 
96 			return this.visitor.Assume (pc, tag, condition, data);
97 		}
98 
AssertMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator99 		public Result Assert (APC pc, EdgeTag tag, Dummy condition, Data data)
100 		{
101 			if (pc.InsideEnsuresAtCall)
102 				return this.visitor.Assume (pc, tag, condition, data);
103 
104 			return this.visitor.Assert (pc, tag, condition, data);
105 		}
106 
BeginOldMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator107 		public Result BeginOld (APC pc, APC matchingEnd, Data data)
108 		{
109 			return this.visitor.BeginOld (pc, matchingEnd, data);
110 		}
111 
EndOldMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator112 		public Result EndOld (APC pc, APC matchingBegin, TypeNode type, Dummy dest, Dummy source, Data data)
113 		{
114 			return this.visitor.EndOld (pc, matchingBegin, type, dest, source, data);
115 		}
116 
LoadStackMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator117 		public Result LoadStack (APC pc, int offset, Dummy dest, Dummy source, bool isOld, Data data)
118 		{
119 			return this.visitor.LoadStack (pc, offset, dest, source, isOld, data);
120 		}
121 
LoadStackAddressMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator122 		public Result LoadStackAddress (APC pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, Data data)
123 		{
124 			return this.visitor.LoadStackAddress (pc, offset, dest, source, type, isOld, data);
125 		}
126 
LoadResultMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator127 		public Result LoadResult (APC pc, TypeNode type, Dummy dest, Dummy source, Data data)
128 		{
129 			return this.visitor.LoadResult (pc, type, dest, source, data);
130 		}
131 
ArglistMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator132 		public Result Arglist (APC pc, Dummy dest, Data data)
133 		{
134 			return this.visitor.Arglist (pc, dest, data);
135 		}
136 
BranchMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator137 		public Result Branch (APC pc, APC target, bool leavesExceptionBlock, Data data)
138 		{
139 			return this.visitor.Nop (pc, data);
140 		}
141 
BranchCondMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator142 		public Result BranchCond (APC pc, APC target, BranchOperator bop, Dummy value1, Dummy value2, Data data)
143 		{
144 			Dummy dest = Dummy.Value;
145 			switch (bop) {
146 			case BranchOperator.Beq:
147 				return this.visitor.Binary (pc, BinaryOperator.Ceq, dest, value1, value2, data);
148 			case BranchOperator.Bge:
149 				return this.visitor.Binary (pc, BinaryOperator.Cge, dest, value1, value2, data);
150 			case BranchOperator.Bge_Un:
151 				return this.visitor.Binary (pc, BinaryOperator.Cge_Un, dest, value1, value2, data);
152 			case BranchOperator.Bgt:
153 				return this.visitor.Binary (pc, BinaryOperator.Cgt, dest, value1, value2, data);
154 			case BranchOperator.Bgt_Un:
155 				return this.visitor.Binary (pc, BinaryOperator.Cgt_Un, dest, value1, value2, data);
156 			case BranchOperator.Ble:
157 				return this.visitor.Binary (pc, BinaryOperator.Cle, dest, value1, value2, data);
158 			case BranchOperator.Ble_Un:
159 				return this.visitor.Binary (pc, BinaryOperator.Cle_Un, dest, value1, value2, data);
160 			case BranchOperator.Blt:
161 				return this.visitor.Binary (pc, BinaryOperator.Clt, dest, value1, value2, data);
162 			case BranchOperator.Blt_Un:
163 				return this.visitor.Binary (pc, BinaryOperator.Clt_Un, dest, value1, value2, data);
164 			case BranchOperator.Bne_un:
165 				return this.visitor.Binary (pc, BinaryOperator.Cne_Un, dest, value1, value2, data);
166 			default:
167 				return this.visitor.Nop (pc, data);
168 			}
169 		}
170 
BranchTrueMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator171 		public Result BranchTrue (APC pc, APC target, Dummy cond, Data data)
172 		{
173 			return this.visitor.Nop (pc, data);
174 		}
175 
BranchFalseMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator176 		public Result BranchFalse (APC pc, APC target, Dummy cond, Data data)
177 		{
178 			return this.visitor.Nop (pc, data);
179 		}
180 
BreakMono.CodeContracts.Static.ControlFlow.RemoveBranchDelegator181 		public Result Break (APC pc, Data data)
182 		{
183 			return this.visitor.Break (pc, data);
184 		}
185 
186 		public Result Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, Data data)
187 			where TypeList : IIndexable<TypeNode>
188 			where ArgList : IIndexable<Dummy>
189 		{
190 			TypeNode declaringType = this.meta_data_provider.DeclaringType (method);
191 			if (MethodIsReferenceEquals (method, args, declaringType))
192 				return this.visitor.Binary (pc, BinaryOperator.Ceq, dest, args [0], args [1], data);
193 
194 			return this.visitor.Call (pc, method, virt, extraVarargs, dest, args, data);
195 		}
196 
197 		public Result Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, Data data)
198 			where TypeList : IIndexable<TypeNode>
199 			where ArgList : IIndexable<Dummy>
200 		{
201 			return this.visitor.Calli (pc, returnType, argTypes, instance, dest, functionPointer, args, data);
202 		}
203 
CheckFinite(APC pc, Dummy dest, Dummy source, Data data)204 		public Result CheckFinite (APC pc, Dummy dest, Dummy source, Data data)
205 		{
206 			return this.visitor.CheckFinite (pc, dest, source, data);
207 		}
208 
CopyBlock(APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, Data data)209 		public Result CopyBlock (APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, Data data)
210 		{
211 			return this.visitor.CopyBlock (pc, destAddress, srcAddress, len, data);
212 		}
213 
EndFilter(APC pc, Dummy decision, Data data)214 		public Result EndFilter (APC pc, Dummy decision, Data data)
215 		{
216 			return this.visitor.EndFilter (pc, decision, data);
217 		}
218 
EndFinally(APC pc, Data data)219 		public Result EndFinally (APC pc, Data data)
220 		{
221 			return this.visitor.EndFinally (pc, data);
222 		}
223 
Jmp(APC pc, Method method, Data data)224 		public Result Jmp (APC pc, Method method, Data data)
225 		{
226 			return this.visitor.Jmp (pc, method, data);
227 		}
228 
LoadArg(APC pc, Parameter argument, bool isOld, Dummy dest, Data data)229 		public Result LoadArg (APC pc, Parameter argument, bool isOld, Dummy dest, Data data)
230 		{
231 			return this.visitor.LoadArg (pc, argument, isOld, dest, data);
232 		}
233 
LoadArgAddress(APC pc, Parameter argument, bool isOld, Dummy dest, Data data)234 		public Result LoadArgAddress (APC pc, Parameter argument, bool isOld, Dummy dest, Data data)
235 		{
236 			return this.visitor.LoadArgAddress (pc, argument, isOld, dest, data);
237 		}
238 
LoadLocal(APC pc, Local local, Dummy dest, Data data)239 		public Result LoadLocal (APC pc, Local local, Dummy dest, Data data)
240 		{
241 			return this.visitor.LoadLocal (pc, local, dest, data);
242 		}
243 
LoadLocalAddress(APC pc, Local local, Dummy dest, Data data)244 		public Result LoadLocalAddress (APC pc, Local local, Dummy dest, Data data)
245 		{
246 			return this.visitor.LoadLocalAddress (pc, local, dest, data);
247 		}
248 
LoadElement(APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, Data data)249 		public Result LoadElement (APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, Data data)
250 		{
251 			return this.visitor.LoadElement (pc, type, dest, array, index, data);
252 		}
253 
LoadField(APC pc, Field field, Dummy dest, Dummy obj, Data data)254 		public Result LoadField (APC pc, Field field, Dummy dest, Dummy obj, Data data)
255 		{
256 			return this.visitor.LoadField (pc, field, dest, obj, data);
257 		}
258 
LoadFieldAddress(APC pc, Field field, Dummy dest, Dummy obj, Data data)259 		public Result LoadFieldAddress (APC pc, Field field, Dummy dest, Dummy obj, Data data)
260 		{
261 			return this.visitor.LoadFieldAddress (pc, field, dest, obj, data);
262 		}
263 
LoadLength(APC pc, Dummy dest, Dummy array, Data data)264 		public Result LoadLength (APC pc, Dummy dest, Dummy array, Data data)
265 		{
266 			return this.visitor.LoadLength (pc, dest, array, data);
267 		}
268 
LoadStaticField(APC pc, Field field, Dummy dest, Data data)269 		public Result LoadStaticField (APC pc, Field field, Dummy dest, Data data)
270 		{
271 			return this.visitor.LoadStaticField (pc, field, dest, data);
272 		}
273 
LoadStaticFieldAddress(APC pc, Field field, Dummy dest, Data data)274 		public Result LoadStaticFieldAddress (APC pc, Field field, Dummy dest, Data data)
275 		{
276 			return this.visitor.LoadStaticFieldAddress (pc, field, dest, data);
277 		}
278 
LoadTypeToken(APC pc, TypeNode type, Dummy dest, Data data)279 		public Result LoadTypeToken (APC pc, TypeNode type, Dummy dest, Data data)
280 		{
281 			return this.visitor.LoadTypeToken (pc, type, dest, data);
282 		}
283 
LoadFieldToken(APC pc, Field type, Dummy dest, Data data)284 		public Result LoadFieldToken (APC pc, Field type, Dummy dest, Data data)
285 		{
286 			return this.visitor.LoadFieldToken (pc, type, dest, data);
287 		}
288 
LoadMethodToken(APC pc, Method type, Dummy dest, Data data)289 		public Result LoadMethodToken (APC pc, Method type, Dummy dest, Data data)
290 		{
291 			return this.visitor.LoadMethodToken (pc, type, dest, data);
292 		}
293 
Nop(APC pc, Data data)294 		public Result Nop (APC pc, Data data)
295 		{
296 			return this.visitor.Nop (pc, data);
297 		}
298 
Pop(APC pc, Dummy source, Data data)299 		public Result Pop (APC pc, Dummy source, Data data)
300 		{
301 			return this.visitor.Pop (pc, source, data);
302 		}
303 
Return(APC pc, Dummy source, Data data)304 		public Result Return (APC pc, Dummy source, Data data)
305 		{
306 			return this.visitor.Return (pc, source, data);
307 		}
308 
StoreArg(APC pc, Parameter argument, Dummy source, Data data)309 		public Result StoreArg (APC pc, Parameter argument, Dummy source, Data data)
310 		{
311 			return this.visitor.StoreArg (pc, argument, source, data);
312 		}
313 
StoreLocal(APC pc, Local local, Dummy source, Data data)314 		public Result StoreLocal (APC pc, Local local, Dummy source, Data data)
315 		{
316 			return this.visitor.StoreLocal (pc, local, source, data);
317 		}
318 
StoreElement(APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, Data data)319 		public Result StoreElement (APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, Data data)
320 		{
321 			return this.visitor.StoreElement (pc, type, array, index, value, data);
322 		}
323 
StoreField(APC pc, Field field, Dummy obj, Dummy value, Data data)324 		public Result StoreField (APC pc, Field field, Dummy obj, Dummy value, Data data)
325 		{
326 			return this.visitor.StoreField (pc, field, obj, value, data);
327 		}
328 
StoreStaticField(APC pc, Field field, Dummy value, Data data)329 		public Result StoreStaticField (APC pc, Field field, Dummy value, Data data)
330 		{
331 			return this.visitor.StoreStaticField (pc, field, value, data);
332 		}
333 
Switch(APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, Data data)334 		public Result Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, Data data)
335 		{
336 			return this.visitor.Nop (pc, data);
337 		}
338 
Box(APC pc, TypeNode type, Dummy dest, Dummy source, Data data)339 		public Result Box (APC pc, TypeNode type, Dummy dest, Dummy source, Data data)
340 		{
341 			return this.visitor.Box (pc, type, dest, source, data);
342 		}
343 
344 		public Result ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, Data data)
345 			where TypeList : IIndexable<TypeNode>
346 			where ArgList : IIndexable<Dummy>
347 		{
348 			return this.visitor.ConstrainedCallvirt (pc, method, constraint, extraVarargs, dest, args, data);
349 		}
350 
CastClass(APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)351 		public Result CastClass (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
352 		{
353 			return this.visitor.CastClass (pc, type, dest, obj, data);
354 		}
355 
CopyObj(APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, Data data)356 		public Result CopyObj (APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, Data data)
357 		{
358 			return this.visitor.CopyObj (pc, type, destPtr, sourcePtr, data);
359 		}
360 
Initobj(APC pc, TypeNode type, Dummy ptr, Data data)361 		public Result Initobj (APC pc, TypeNode type, Dummy ptr, Data data)
362 		{
363 			return this.visitor.Initobj (pc, type, ptr, data);
364 		}
365 
366 		public Result NewArray<ArgList> (APC pc, TypeNode type, Dummy dest, ArgList lengths, Data data) where ArgList : IIndexable<Dummy>
367 		{
368 			return this.visitor.NewArray (pc, type, dest, lengths, data);
369 		}
370 
371 		public Result NewObj<ArgList> (APC pc, Method ctor, Dummy dest, ArgList args, Data data) where ArgList : IIndexable<Dummy>
372 		{
373 			return this.visitor.NewObj (pc, ctor, dest, args, data);
374 		}
375 
MkRefAny(APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)376 		public Result MkRefAny (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
377 		{
378 			return this.visitor.MkRefAny (pc, type, dest, obj, data);
379 		}
380 
RefAnyType(APC pc, Dummy dest, Dummy source, Data data)381 		public Result RefAnyType (APC pc, Dummy dest, Dummy source, Data data)
382 		{
383 			return this.visitor.RefAnyType (pc, dest, source, data);
384 		}
385 
RefAnyVal(APC pc, TypeNode type, Dummy dest, Dummy source, Data data)386 		public Result RefAnyVal (APC pc, TypeNode type, Dummy dest, Dummy source, Data data)
387 		{
388 			return this.visitor.RefAnyVal (pc, type, dest, source, data);
389 		}
390 
Rethrow(APC pc, Data data)391 		public Result Rethrow (APC pc, Data data)
392 		{
393 			return this.visitor.Rethrow (pc, data);
394 		}
395 
Throw(APC pc, Dummy exception, Data data)396 		public Result Throw (APC pc, Dummy exception, Data data)
397 		{
398 			return this.visitor.Throw (pc, exception, data);
399 		}
400 
Unbox(APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)401 		public Result Unbox (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
402 		{
403 			return this.visitor.Unbox (pc, type, dest, obj, data);
404 		}
405 
UnboxAny(APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)406 		public Result UnboxAny (APC pc, TypeNode type, Dummy dest, Dummy obj, Data data)
407 		{
408 			return this.visitor.UnboxAny (pc, type, dest, obj, data);
409 		}
410 		#endregion
411 
412 		private bool MethodIsReferenceEquals<ArgList> (Method method, ArgList args, TypeNode declaringType)
413 			where ArgList : IIndexable<Dummy>
414 		{
415 			return args.Count == 2 && this.meta_data_provider.IsStatic (method)
416 			       && this.meta_data_provider.Equal (declaringType, this.meta_data_provider.System_Object)
417 			       && this.meta_data_provider.Name (method) == "ReferenceEquals";
418 		}
419 		}
420 }
421